Skip to content

Conversation

@gadenbuie
Copy link
Collaborator

@gadenbuie gadenbuie commented Feb 11, 2025

This PR stacks on #1845 (and should be merged into it before merging to main).

The goal is to add an option to auto-submit the inline chat suggestion. This required a small amount of refactoring how the disabled input state is handled first, and then giving ChatInput.setInputValue() a submit parameter that defaults to false.

For styling, I've used the idea from @cpsievert in #1845 (comment) to use ↵ for suggestions that will auto-submit and ✦ for suggestions that fill out the input value without submitting. In the screenshot below, the first and third suggestions would auto-submit and the second would just fill out the input.

image

(I modified the example app below for the screenshot, it's more likely that you'd pick one style or the other for your app.)

The easiest way to create an auto-submitting suggestion is to use <span class="suggestion submit">, but data-suggestion-submit and data-suggestion-submit="true" also work as well.

Example app

Along the way, I made a fun little app that works well for me locally with ollama and Phi4.

Example App
# ------------------------------------------------------------------------------------
# A basic Shiny Chat example powered by Ollama.
# To run it, you'll need an Ollama server running locally.
# To download and run the server, see https://github.com/ollama/ollama
# To install the Ollama Python client, see https://github.com/ollama/ollama-python
# ------------------------------------------------------------------------------------

from chatlas import ChatOllama

from shiny import reactive
from shiny.express import ui

# Set some Shiny page options
ui.page_opts(
    title="Choose your own data science adventure",
    fillable=True,
    fillable_mobile=True,
)

# Create and display empty chat
chat = ui.Chat(id="chat")
chat.ui()

chat_model = ChatOllama(
    model="phi4",
    system_prompt="""
You are an AI guide creating an interactive "choose-your-own adventure" experience for
data scientists. Your task is to present scenarios and choices that allow the user to
navigate through various data science challenges and situations.

Follow these steps to continue the adventure:

1. Read the user's input carefully.

2. Create 2-3 distinct choices for the user, considering:
   - Select appropriate emojis for each choice
   - Determine which part of each choice should be marked as a clickable suggestion

3. Present a short scenario (2-3 sentences) that builds upon the user's previous choice
   or input.

4. Offer 2-3 choices for the user to select from. Each choice should be formatted as
   follows:

   - Begin with a single, relevant emoji
   - Wrap the clickable part of the suggestion (the part that makes sense as a user response) in a span with class "suggestion"
   - The entire choice, including the emoji and any additional context, should be on a single line

   Example format (do not use this content, create your own):

   * 📊 <span class="suggestion submit">Analyze the data using regression analysis</span> to identify trends
   * 🧮 <span class="suggestion submit">Apply clustering algorithms</span> to segment the customer base
   * 🔬 <span class="suggestion submit">Conduct A/B testing</span> on the new feature

5. Ensure that your scenario and choices are creative, clear, and concise, while
   remaining relevant to data science topics.

Remember, the user will continue the adventure by selecting one of the choices you
present. Be prepared to build upon any of the options in future interactions.
    """,
)

@reactive.effect
async def init_chat():
    response = chat_model.stream("Let's start our story together.")
    await chat.append_message_stream(response)


@chat.on_user_submit
async def handle_user_input():
    response = chat_model.stream(chat.user_input())
    await chat.append_message_stream(response)
Screen.Recording.2025-02-11.at.3.01.18.PM.mov

Notice that clicking the suggestions doesn't usually work while streaming, but it does work if you scroll up to a previous message. That's because, while streaming, the chat message is being re-rendered fast enough that the clicked element no longer exists by the time the click handler runs. I think it's okay for us not to do anything about it, but it's also important that we're not submitting during streaming.

* Disable input on send
* Disable input when appending a message (i.e. while streaming)
* Reflect `disabled` state to HTML element (lit's `reflect: true` doesn't work with `LightElement`)
* Reflect HTML element changes of `disabled` state back to component
`this.#sendInput()` doesn't send when `this.disabled`, but we still want to emit the input event, etc.
@gadenbuie gadenbuie marked this pull request as ready for review February 11, 2025 20:37
@gadenbuie gadenbuie merged commit 4dea386 into chat-suggestions Feb 13, 2025
41 checks passed
@gadenbuie gadenbuie deleted the chat-suggestions-submit branch February 13, 2025 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants