Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI extension for new Corpus feature #499

Merged
merged 60 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
c793f2c
draft of the UI for metadata filters
pierrotsmnrd Aug 6, 2024
84bf47b
metadata filters UI : handle types
pierrotsmnrd Aug 6, 2024
921a748
styling + impacts
pierrotsmnrd Aug 6, 2024
0dbad51
validate the filters before starting new chat
pierrotsmnrd Aug 7, 2024
164a0ed
validate the filters before starting new chat
pierrotsmnrd Aug 7, 2024
a84fa44
Fix validation of value for in/not in operators
pierrotsmnrd Aug 8, 2024
66170d9
actual conversion of the value
pierrotsmnrd Aug 8, 2024
361ea28
Merge branch 'corpus-dev' into corpus-dev-ui
pmeier Aug 8, 2024
eeee6f1
allow use of all corpus
pierrotsmnrd Aug 8, 2024
f497abc
Merge branch 'corpus-dev-ui' of https://github.com/Quansight/ragna in…
pierrotsmnrd Aug 8, 2024
6e5bef1
update metadata filters in UI
pierrotsmnrd Aug 8, 2024
be3b57f
Fix for empty filters / use whole corpus
pierrotsmnrd Aug 8, 2024
69a7314
cleanup in CSS files
pierrotsmnrd Aug 8, 2024
cdd466e
fix
pmeier Aug 8, 2024
549a8d8
cleanup
pmeier Aug 8, 2024
dee5e0e
Merge branch 'corpus-dev' into corpus-dev-ui
pmeier Aug 8, 2024
1720e85
update hardcoded metadata
pmeier Aug 8, 2024
44e2ea5
cleanup
pmeier Aug 13, 2024
88005a7
Update ragna/deploy/_ui/central_view.py
pierrotsmnrd Aug 14, 2024
9917109
simplify switch yard
pierrotsmnrd Aug 14, 2024
da398d1
Merge branch 'corpus-dev-ui' of https://github.com/Quansight/ragna in…
pierrotsmnrd Aug 14, 2024
97e0b70
missing comma
pierrotsmnrd Aug 14, 2024
3b582b3
use operator
pierrotsmnrd Aug 14, 2024
68d2581
cleanup
pierrotsmnrd Aug 14, 2024
6ea9aa2
remove comment
pierrotsmnrd Aug 14, 2024
47a1991
Replace custom UI repr with ragna MetadataFilter repr
nenb Aug 19, 2024
36e790c
Merge branch 'corpus-dev' into corpus-dev-ui
nenb Aug 20, 2024
83e0120
Update type inference logic for input
nenb Aug 20, 2024
f5b8c7f
Merge branch 'corpus-dev' into corpus-dev-ui
nenb Aug 21, 2024
ef44fb6
temp stash of working poc
nenb Aug 23, 2024
b2f5700
MVP
nenb Aug 23, 2024
3889498
Tidy API wrapper and file uploader
nenb Aug 23, 2024
0b8b522
Tidy CSS for upload row
nenb Aug 23, 2024
fc74e06
Tidy radio button group
nenb Aug 23, 2024
f3b0cb6
Simplify config
nenb Aug 23, 2024
717dd3e
Simplify config
nenb Aug 23, 2024
4d445dd
Simplify config
nenb Aug 23, 2024
2220104
Move text input button
nenb Aug 23, 2024
e813c2a
Activate upload button
nenb Aug 23, 2024
dfc0ecc
Final tweaks
nenb Aug 23, 2024
d6ff444
tidy
nenb Aug 23, 2024
f4124c8
Fix typo in CSS
nenb Aug 23, 2024
d40bc72
Merge branch 'corpus-dev' into corpus-dev-ui-rework
nenb Aug 26, 2024
02cd14a
Merge branch 'corpus-dev' into corpus-dev-ui-rework
nenb Aug 26, 2024
258160b
Add API support to list metadata
nenb Aug 26, 2024
60419fe
Replace type object with type name
nenb Aug 26, 2024
b4b26df
Merge branch 'corpus-dev-list-metadata-api' into corpus-dev-ui-rework
nenb Aug 26, 2024
df373f4
Remove corpus name from upload
nenb Aug 26, 2024
719082c
Fix error message update
nenb Aug 26, 2024
b8207f5
Fix edge cases
nenb Aug 27, 2024
574d041
Merge branch 'corpus-dev' into corpus-dev-ui-rework
nenb Aug 27, 2024
3d77da4
Improve validation and UX
nenb Aug 27, 2024
b7f39c0
restore dev branch API code
nenb Aug 27, 2024
99739b2
Merge branch 'corpus-dev' into corpus-dev-ui-rework
pmeier Sep 2, 2024
625a648
Retain line breaks
nenb Sep 3, 2024
d85478d
Add HTMLTemplate style to _stylesheets
nenb Sep 3, 2024
95eeeee
Simplify logic for selecting valid operators
nenb Sep 3, 2024
f245f91
Add multichoice option
nenb Sep 4, 2024
4e716a8
use css helper
pmeier Sep 5, 2024
a095a1f
temporarily disable most of the UI tests
pmeier Sep 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions ragna/deploy/_ui/api_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,40 @@ async def auth(self, username, password):
def update_auth_header(self):
self.client.headers["Authorization"] = f"Bearer {self.auth_token}"

async def get_corpus_names(self):
pmeier marked this conversation as resolved.
Show resolved Hide resolved
# TODO: replace with actual endpoint
# return (await self.client.get("/corpuses")).raise_for_status().json()
return {
"Chroma": ["corpus1", "corpus2"],
"LanceDB": ["corpus1"],
}

async def get_corpus_metadata(self, corpus_name=None):
# TODO: replace with actual endpoint, and add corpus_name as query parameter
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once #495 is merged.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be #500, right?

# return (
# (await self.client.get(f"/corpuses/metadata"))
# .raise_for_status()
# .json()
# )
metadata1 = {
"document_name": ["doc1", "doc2", "doc3"],
"size": [100, 200, 300],
"is_pdf": ["True", "False", "True"],
}
metadata2 = {
"document_name": ["doc1", "doc2"],
"size": [100, 200],
"is_pdf": ["True", "False"],
}
source_storage1 = {
"corpus1": metadata1,
"corpus2": metadata2,
}
source_storage2 = {
"corpus1": metadata1,
}
return {"Chroma": source_storage1, "LanceDB": source_storage2}

async def get_chats(self):
json_data = (await self.client.get("/chats")).raise_for_status().json()
for chat in json_data:
Expand Down
58 changes: 46 additions & 12 deletions ragna/deploy/_ui/central_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from panel.reactive import ReactiveHTML

from ragna._compat import anext
from ragna.core._metadata_filter import MetadataFilter

from . import styles as ui

Expand Down Expand Up @@ -186,20 +187,49 @@ def on_click_chat_info_wrapper(self, event):
if self.on_click_chat_info is None:
return

pills = "".join(
[
f"""<div class='chat_document_pill'>{d['name']}</div>"""
for d in self.current_chat["metadata"]["documents"]
]
)
# see _api/schemas.py for `input` type definitions
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Display in right sidebar depending on what has been used as input for the chat.

if isinstance(self.current_chat["metadata"]["input"], list):
# `Document`s provided as list
title = "Uploaded Files"

pills = "".join(
[
f"""<div class='chat_document_pill'>{d['name']}</div>"""
for d in self.current_chat["metadata"]["input"]
]
)

details = f"<div class='details'>{pills}</div><br />\n\n"
grid_height = len(self.current_chat["metadata"]["input"]) // 3

grid_height = len(self.current_chat["metadata"]["documents"]) // 3
elif isinstance(self.current_chat["metadata"]["input"], dict):
# `MetadataFilter`s provided as dict
title = "Metadata Filters"

metadata_filters_readable = str(
MetadataFilter.from_primitive(self.current_chat["metadata"]["input"])
)
nenb marked this conversation as resolved.
Show resolved Hide resolved

details = f"<div class='details details_block' style='display:block;'>{metadata_filters_readable}</div><br />\n\n"
grid_height = 1

elif self.current_chat["metadata"]["input"] is None:
title = ""

details = "<div class='details'>No metadata filters applied.<br /> Using the whole corpus.</div><br />\n\n"
grid_height = 1

else:
title = ""

details = "<div class='details'>Unable to infer the `input` type.<br /> Defaulting to using the whole corpus.</div><br />\n\n"
grid_height = 1

markdown = "\n".join(
[
"To change configurations, start a new chat.\n",
"**Uploaded Files**",
f"<div class='pills_list'>{pills}</div><br />\n\n",
f"**{title}**",
details,
"----",
"**Source Storage**",
f"""<span>{self.current_chat['metadata']['source_storage']}</span>\n""",
Expand All @@ -225,11 +255,15 @@ def on_click_chat_info_wrapper(self, event):
# The CSS rule below relies on a variable value, so we can't move it into modifers
stylesheets=[
ui.css(
":host(.chat_info_markdown) .pills_list",
":host(.chat_info_markdown) .details",
{
"grid-template": f"repeat({grid_height}, 1fr) / repeat(3, 1fr)",
},
)
),
ui.css(
":host(.chat_info_markdown) .details_block",
{"display": "block"},
),
],
),
],
Expand All @@ -246,7 +280,7 @@ def on_click_source_info_wrapper(self, event, sources):
location = f": page(s) {location}"
source_infos.append(
(
f"<b>{rank}. {source['document']['name']}</b> {location}",
f"<b>{rank}. {source['document_name']}</b> {location}",
pn.pane.Markdown(source["content"], css_classes=["source-content"]),
)
)
Expand Down
27 changes: 16 additions & 11 deletions ragna/deploy/_ui/components/file_uploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
from panel.reactive import ReactiveHTML
from panel.widgets import Widget

from .. import styles as ui


class FileUploader(ReactiveHTML, Widget): # type: ignore[misc]
allowed_documents = param.List(default=[])
allowed_documents_str = param.String(default="")

file_list = param.List(default=[])

height_upload_container = param.String(default=ui.FILE_CONTAINER_HEIGHT)
nenb marked this conversation as resolved.
Show resolved Hide resolved

custom_js = param.String(default="")
uploaded_documents_json = param.String(default="")

Expand All @@ -37,7 +41,7 @@ async def did_finish_upload(self):
if self.after_upload_callback is not None:
await self.after_upload_callback(json.loads(self.uploaded_documents_json))

def perform_upload(self, event=None, after_upload_callback=None):
def perform_upload(self, event=None, after_upload_callback=None, corpus_name=""):
self.after_upload_callback = after_upload_callback

self.loading = True
Expand All @@ -56,7 +60,7 @@ def perform_upload(self, event=None, after_upload_callback=None):
self.custom_js = (
final_callback_js
+ random_id
+ f"""upload( self.get_upload_files(), '{self.token}', '{self.informations_endpoint}', final_callback) """
+ f"""upload( self.get_upload_files(), '{corpus_name}', '{self.token}', '{self.informations_endpoint}', final_callback) """
)

_child_config = {
Expand All @@ -74,7 +78,7 @@ def perform_upload(self, event=None, after_upload_callback=None):
}

.fileUploadContainer {
height: 130px;
height: ${height_upload_container};
}

.fileUploadDropArea {
Expand All @@ -101,10 +105,6 @@ def perform_upload(self, event=None, after_upload_callback=None):
.fileUploadDropArea.draggedOver {
border-width: 3px;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed to reduce the number of resize operations on the height of the upload container (see previous comment on how I have introduced a new parameter for this). This has negligible UX impact IMO. The basic functionality was to make the upload container smaller when a 'pill' (icon for a newly upload file) was present below. I have now introduced some more spacing and a scroll (see below).

.fileUploadDropArea.uploaded {
height: calc(100% - 40px);
}

.fileUpload {
height: 100% !important;
Expand All @@ -115,15 +115,20 @@ def perform_upload(self, event=None, after_upload_callback=None):
.fileListContainer {
display:flex;
flex-direction: row;
height: 44px;
overflow:scroll;
padding-top:14px;
flex-wrap: wrap;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduces wrapping so that if the pills are wider than the modal, they 'wrap' around to the next line, and scroll along the Y-axis. I have removed the scroll on the X-axis as I found having too scrolls to be hard to follow. I have also added more spacing to compensate for the fact that the file upload container no longer shrinks when a pill is added (see previous comment).

height: 40px;
overflow-y:scroll;
overflow-x:hidden;
margin-top: 10px;
margin-bottom: 10px;
padding-top:5px;
nenb marked this conversation as resolved.
Show resolved Hide resolved
padding-left:6px;
padding-bottom:5px;
}

.chat_document_pill {
background-color: rgb(241,241,241);
margin-top:0px;
margin-top:5px;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make things a bit more readable when many pills, introduce a small amount of white space between them.

margin-left: 5px;
margin-right: 5px;
padding: 5px 15px;
Expand Down
Loading
Loading