Improve gr.ChatInterface UI, add autofocus to textbox (#4978)

* changes

* changes

* lint

* fix tests

* fix

---------

Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
This commit is contained in:
aliabid94 2023-07-20 14:44:52 +03:00 committed by GitHub
parent 3dc9a65815
commit b68aeea412
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 45 deletions

View File

@ -5,6 +5,7 @@ No changes to highlight.
## New Features:
- Add `show_download_button` param to allow the download button in static Image components to be hidden by [@hannahblair](https://github.com/hannahblair) in [PR 4959](https://github.com/gradio-app/gradio/pull/4959)
- Added autofocus argument to Textbox by [@aliabid94](https://github.com/aliabid94) in [PR 4978](https://github.com/gradio-app/gradio/pull/4978)
- Use `gr.State` in `gr.ChatInterface` to reduce latency by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 4976](https://github.com/gradio-app/gradio/pull/4976)
## Bug Fixes:
@ -18,6 +19,7 @@ No changes to highlight.
## Other Changes:
- Apply pyright to the `components` directory by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 4948](https://github.com/gradio-app/gradio/pull/4948)
- Improved look of ChatInterface by [@aliabid94](https://github.com/aliabid94) in [PR 4978](https://github.com/gradio-app/gradio/pull/4978)
# Version 3.37

View File

@ -20,7 +20,7 @@ from gradio.components import (
Textbox,
)
from gradio.helpers import create_examples as Examples # noqa: N812
from gradio.layouts import Group, Row
from gradio.layouts import Column, Group, Row
from gradio.themes import ThemeClass as Theme
set_documentation_group("chatinterface")
@ -110,11 +110,13 @@ class ChatInterface(Blocks):
if description:
Markdown(description)
with Group():
with Column(variant="panel"):
if chatbot:
self.chatbot = chatbot.render()
else:
self.chatbot = Chatbot(label="Chatbot")
with Group():
with Row():
if textbox:
self.textbox = textbox.render()
@ -124,6 +126,7 @@ class ChatInterface(Blocks):
show_label=False,
placeholder="Type a message...",
scale=10,
autofocus=True,
)
if submit_btn:
if isinstance(submit_btn, Button):
@ -146,7 +149,7 @@ class ChatInterface(Blocks):
if isinstance(btn, Button):
btn.render()
elif isinstance(btn, str):
btn = Button(btn, variant="secondary")
btn = Button(btn, variant="secondary", size="sm")
else:
raise ValueError(
f"All the _btn parameters must be a gr.Button, string, or None, not {type(btn)}"
@ -154,7 +157,9 @@ class ChatInterface(Blocks):
self.buttons.append(btn)
self.fake_api_btn = Button("Fake API", visible=False)
self.fake_response_textbox = Textbox(label="Response", visible=False)
self.fake_response_textbox = Textbox(
label="Response", visible=False
)
(
self.submit_btn,
self.retry_btn,

View File

@ -66,6 +66,7 @@ class Textbox(
interactive: bool | None = None,
visible: bool = True,
elem_id: str | None = None,
autofocus: bool = False,
elem_classes: list[str] | str | None = None,
type: Literal["text", "password", "email"] = "text",
text_align: Literal["left", "right"] | None = None,
@ -88,6 +89,7 @@ class Textbox(
min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.
interactive: if True, will be rendered as an editable textbox; if False, editing will be disabled. If not provided, this is inferred based on whether the component is used as an input or output.
visible: If False, component will be hidden.
autofocus: If True, will focus on the textbox when the page loads.
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
type: The type of textbox. One of: 'text', 'password', 'email', Default is 'text'.
@ -105,6 +107,7 @@ class Textbox(
self.max_lines = 1
self.placeholder = placeholder
self.show_copy_button = show_copy_button
self.autofocus = autofocus
self.select: EventListenerMethod
"""
Event listener for when the user selects text in the Textbox.
@ -139,6 +142,7 @@ class Textbox(
"placeholder": self.placeholder,
"value": self.value,
"type": self.type,
"autofocus": self.autofocus,
"show_copy_button": self.show_copy_button,
"container": self.container,
"text_align": self.text_align,
@ -164,6 +168,7 @@ class Textbox(
text_align: Literal["left", "right"] | None = None,
rtl: bool | None = None,
show_copy_button: bool | None = None,
autofocus: bool | None = None,
):
return {
"lines": lines,
@ -180,6 +185,7 @@ class Textbox(
"type": type,
"interactive": interactive,
"show_copy_button": show_copy_button,
"autofocus": autofocus,
"text_align": text_align,
"rtl": rtl,
"__type__": "update",

View File

@ -188,6 +188,7 @@ XRAY_CONFIG = {
"id": 14,
"type": "textbox",
"props": {
"autofocus": False,
"lines": 1,
"max_lines": 20,
"value": "",
@ -508,6 +509,7 @@ XRAY_CONFIG_DIFF_IDS = {
"id": 19,
"type": "textbox",
"props": {
"autofocus": False,
"lines": 1,
"max_lines": 20,
"value": "",
@ -784,6 +786,7 @@ XRAY_CONFIG_WITH_MISTAKE = {
"show_copy_button": False,
"type": "text",
"rtl": False,
"autofocus": False,
},
},
],

View File

@ -26,6 +26,7 @@
export let value_is_output: boolean = false;
export let rtl = false;
export let text_align: "left" | "right" | undefined = undefined;
export let autofocus: boolean = false;
</script>
<Block {visible} {elem_id} {elem_classes} {scale} {min_width} allow_overflow={false} padding={container}>
@ -46,6 +47,7 @@
max_lines={!max_lines && mode === "static" ? lines + 1 : max_lines}
{placeholder}
{show_copy_button}
{autofocus}
{container}
on:change
on:input

View File

@ -18,6 +18,7 @@
export let type: "text" | "password" | "email" = "text";
export let show_copy_button: boolean = false;
export let rtl = false;
export let autofocus: boolean = false;
export let text_align: "left" | "right" | undefined = undefined;
let el: HTMLTextAreaElement | HTMLInputElement;
@ -150,6 +151,7 @@
bind:this={el}
{placeholder}
{disabled}
{autofocus}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:select={handle_select}
@ -164,6 +166,7 @@
bind:this={el}
{placeholder}
{disabled}
{autofocus}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:select={handle_select}
@ -178,6 +181,7 @@
bind:this={el}
{placeholder}
{disabled}
{autofocus}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:select={handle_select}
@ -202,6 +206,7 @@
{placeholder}
rows={lines}
{disabled}
{autofocus}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:select={handle_select}

View File

@ -1065,6 +1065,7 @@ class TestSpecificUpdate:
"lines": 4,
"info": None,
"max_lines": None,
"autofocus": None,
"placeholder": None,
"label": None,
"show_label": None,
@ -1093,6 +1094,7 @@ class TestSpecificUpdate:
"show_label": None,
"container": None,
"scale": None,
"autofocus": None,
"min_width": None,
"visible": None,
"value": gr.components._Keywords.NO_VALUE,

View File

@ -105,6 +105,7 @@ class TestTextbox:
"root_url": None,
"rtl": False,
"text_align": None,
"autofocus": False,
}
@pytest.mark.asyncio