pythonjupyter-notebookchatboteoferrorjupyter-widget

Jupyter Notebook - Unable to get user input the second time - EOFError: EOF when reading a line


I am trying to create a chatbot like UI where I wish to recursively ask user to input question through the input() function and pass it to an external function and fetch a relevant answer.

---> 36   ques[0] = input("How can i help you? ")
     37   chat(ques[0])
     38 
EOFError: EOF when reading a line

The below code works for the first time - gets input and even returns relevant output. But, I get the above error when I click on the "Try again" button (for the second time).

from ipywidgets import interact, widgets
from IPython.display import display, clear_output

ques = [""] 
def chat(q):
  a = faq(q) #FAQ is a function that returns answers to questions
  question = widgets.Text(
      value= ques[0],
      disabled=True
  )
  display(question)

  answer = widgets.Textarea(
      value= a[0][0],
      disabled=True
  )
  display(answer)

  def callback(wdgt):
      display(wdgt.value)

  question.on_submit(callback)

def btn_eventhandler(obj):
  ques[0] = input("How can i help you? ")
  chat(ques[0])    

ques[0] = input("How can i help you? ")
chat(ques[0])

btn = widgets.Button(description='Try again ?')
display(btn)
btn.on_click(btn_eventhandler)

I also wish to use the clear_output() function so that I get a clear screen for the next user input.

I am really lost here. Kindly help me out!!


Solution

  • input() was created for terminal/console/cmd.exe and maybe this is why it has problem to work correctly in jupyter.

    I would rather use widgets.Text to create input_widget.


    Minimal working code

    from ipywidgets import interact, widgets
    from IPython.display import display, clear_output
    
    #ques = [""] 
    
    def faq(q):
        return [["I don't know !!!"]]
    
    def chat(q):
        a = faq(q) #FAQ is a function that returns answers to questions
        
        question = widgets.Text(
            value = q,
            disabled=True
        )
        display(question)
    
        answer = widgets.Textarea(
            value= a[0][0],
            disabled=True
        )
        display(answer)
    
    def input_widget(text, callback):
        label = widgets.Label(text)
        
        text = widgets.Text()
        text.on_submit(callback)
    
        box = widgets.HBox([label, text])
        display(box)
    
    def result(event):
        chat(event.value)    
        
        btn = widgets.Button(description='Try again ?')
        btn.on_click(ask)
        display(btn)
    
    def ask(event=None):
        input_widget("How can i help you? ", result)
        
    ask()   
    

    enter image description here


    EDIT:

    Version which use clear_output() to remove widgets before new question.

    Eventually you can use widget.close() to remove only some widgets - but they have to be global to access them in other function.

    from ipywidgets import interact, widgets
    from IPython.display import display, clear_output
    
    def faq(q):
        return [["I don't know !!!"]]
    
    def chat(q):
        #global question, answer
    
        a = faq(q) #FAQ is a function that returns answers to questions
        
        question = widgets.Text(
            value = q,
            disabled=True
        )
        display(question)
    
        answer = widgets.Textarea(
            value= a[0][0],
            disabled=True
        )
        display(answer)
    
    def input_widget(text, callback):
        #global input_label, input_text, input_box
        
        input_label = widgets.Label(text)
        
        input_text = widgets.Text()
        input_text.on_submit(callback)
    
        input_box = widgets.HBox([input_label, input_text])
        display(input_box)
    
    def result(event):
        #global btn
    
        chat(event.value)    
        
        btn = widgets.Button(description='Try again ?')
        btn.on_click(try_again)
        display(btn)
    
    def try_again(event):
        #input_box.close()
        #question.close()
        #answer.close()
        #btn.close()
        clear_output()
        
        ask()
        
    def ask():
        input_widget("How can i help you? ", result)
        
    ask()
    

    EDIT:

    Version reduced to two functions ask_question and get_answer

    from ipywidgets import interact, widgets
    from IPython.display import display, clear_output
    
    def faq(question):
        return [["I don't know !!!"]]
    
    def get_answer(event):
        question = event.value
        answer = faq(question) 
        answer = answer[0][0]
    
        chat_question = widgets.Text(
            value = question,
            disabled=True
        )
        display(chat_question)
    
        chat_answer = widgets.Textarea(
            value= answer,
            disabled=True
        )
        display(chat_answer)
    
        chat_button = widgets.Button(description='Try again ?')
        chat_button.on_click(ask_question)
        display(chat_button)
        
    def ask_question(event=None):
        clear_output()
    
        input_label = widgets.Label("How can i help you? ")
        
        input_text = widgets.Text()
        input_text.on_submit(get_answer)
    
        input_box = widgets.HBox([input_label, input_text])
        display(input_box)
    
    ask_question()