-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat: Add Stop button to interrupt message generation #336
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
base: main
Are you sure you want to change the base?
feat: Add Stop button to interrupt message generation #336
Conversation
Implementada funcionalidade completa de stop para permitir que usuários interrompam a geração de mensagens do chat em tempo real. Mudanças: - Criado novo componente StopButton para UI - Adicionado AbortController para gerenciar interrupção de mensagens - Integrado AbortController em fetchResponseFromEventStream() - Botão Stop substituiu botão Send durante carregamento - Função stopMessage() para abortar requisições de forma segura O botão Stop aparece automaticamente quando uma mensagem está sendo gerada e volta para o botão Send quando a geração é concluída.
Atualizar yarn.lock e adicionar package-lock.json após instalação de dependências necessárias para build do projeto.
Summary of ChangesHello @marcosmarf27, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! Este pull request introduz uma funcionalidade crucial que permite aos usuários interromper a geração de mensagens em tempo real em um chat, através da adição de um botão 'Stop'. Essa melhoria visa proporcionar maior controle e uma experiência de usuário mais fluida, especialmente em cenários onde as respostas do chat podem ser longas ou indesejadas. A implementação utiliza o Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
Este pull request adiciona uma funcionalidade útil para interromper a geração de mensagens. A implementação geral usando AbortController está correta, mas identifiquei alguns pontos para melhoria. O mais crítico é uma rejeição de promessa não tratada que ocorre ao abortar a requisição, o que pode levar a instabilidade. Também há algumas simplificações possíveis nos componentes e no gerenciamento de estado, como a remoção de props e estados não utilizados. Por fim, fiz sugestões para melhorar a clareza e a acessibilidade do novo componente StopButton.
| const controller = messageAbortController(); | ||
| if (controller) { | ||
| setIsMessageStopping(true); | ||
| controller.abort(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A chamada controller.abort() fará com que a promessa retornada por fetchEventSource seja rejeitada com um AbortError. Como a chamada para fetchResponseFromEventStream em handleSubmit não possui um bloco .catch(), isso resultará em uma rejeição de promessa não tratada (unhandled promise rejection) no console.
Embora a limpeza síncrona em stopMessage funcione visualmente, é crucial tratar a rejeição para evitar erros e garantir um código mais robusto. A abordagem ideal seria adicionar um .catch() à chamada de fetchResponseFromEventStream e mover a lógica de limpeza para lá, tratando especificamente o AbortError.
| type StopButtonProps = { | ||
| buttonColor?: string; | ||
| isDisabled?: boolean; | ||
| isLoading?: boolean; | ||
| disableIcon?: boolean; | ||
| } & JSX.ButtonHTMLAttributes<HTMLButtonElement>; | ||
|
|
||
| export const StopButton = (props: StopButtonProps) => { | ||
| return ( | ||
| <button | ||
| type="button" | ||
| disabled={props.isDisabled || props.isLoading} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As propriedades isLoading e disableIcon em StopButtonProps não são utilizadas ou podem causar confusão. A propriedade isLoading na lógica disabled é contra-intuitiva para um botão de parada, que deve ser clicável durante o carregamento. A propriedade disableIcon não é utilizada.
Sugiro simplificar as props e a lógica disabled. Além disso, como o botão não renderiza texto, um aria-label seria bom para acessibilidade.
| type StopButtonProps = { | |
| buttonColor?: string; | |
| isDisabled?: boolean; | |
| isLoading?: boolean; | |
| disableIcon?: boolean; | |
| } & JSX.ButtonHTMLAttributes<HTMLButtonElement>; | |
| export const StopButton = (props: StopButtonProps) => { | |
| return ( | |
| <button | |
| type="button" | |
| disabled={props.isDisabled || props.isLoading} | |
| type StopButtonProps = { | |
| buttonColor?: string; | |
| isDisabled?: boolean; | |
| } & JSX.ButtonHTMLAttributes<HTMLButtonElement>; | |
| export const StopButton = (props: StopButtonProps) => { | |
| return ( | |
| <button | |
| type="button" | |
| aria-label="Interromper geração da mensagem" | |
| disabled={props.isDisabled} |
src/components/Bot.tsx
Outdated
|
|
||
| const [isChatFlowAvailableToStream, setIsChatFlowAvailableToStream] = createSignal(false); | ||
| const [chatId, setChatId] = createSignal(''); | ||
| const [isMessageStopping, setIsMessageStopping] = createSignal(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/components/Bot.tsx
Outdated
| const stopMessage = () => { | ||
| const controller = messageAbortController(); | ||
| if (controller) { | ||
| setIsMessageStopping(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| on:click={props.onStopMessage} | ||
| > | ||
| <span style={{ 'font-family': 'Poppins, sans-serif' }}>Stop</span> | ||
| </StopButton> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
O componente StopButton não renderiza seus filhos, então o <span>Stop</span> não será exibido. Para manter a consistência com o SendButton (que é apenas um ícone), sugiro remover o span e tornar o componente auto-fechado. A acessibilidade deve ser tratada no próprio componente StopButton com um aria-label.
on:click={props.onStopMessage} />
Improvements based on Gemini Code Assist review: - Simplified StopButton props by removing unused isLoading and disableIcon - Added aria-label for accessibility - Removed unused isMessageStopping state - Added proper error handling for AbortController rejection - Removed non-rendered children span from StopButton usage - Handle AbortError silently as it's an expected user action These changes improve code maintainability, accessibility, and prevent unhandled promise rejections in the console.
🎯 Objective
Implement functionality that allows users to interrupt chat message generation in real-time through a Stop button.
✨ Changes Implemented
New Component
src/components/buttons/StopButton.tsx): New button component with stop iconInterruption Logic
messageAbortControllersignal to manage AbortControllerfetchResponseFromEventStream()to support interruption via AbortControllerstopMessage()function that safely aborts SSE requestscloseResponse()User Interface
isLoadingstateisLoadingandonStopMessageprops to TextInput component🔧 How It Works
AbortController.abort()interrupts the SSE request🧪 Testing
📦 Modified Files
src/components/buttons/StopButton.tsx(new)src/components/Bot.tsxsrc/components/inputs/textInput/components/TextInput.tsxdist/(build files)🎨 Preview
The Stop button appears automatically when a message is being generated:
🔍 Technical Notes
@microsoft/fetch-event-sourcelibrary📸 User Experience
Users now have full control over message generation, improving the chat experience by allowing them to: