sylvie-2024

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

chatterbot_ollama.py (8877B)


      1 from chatterbot import ChatBot
      2 from chatterbot.conversation import Statement
      3 from chatterbot.trainers import ChatterBotCorpusTrainer
      4 import en_core_web_sm
      5 
      6 import random
      7 import serial
      8 import time
      9 import json
     10 import simpleaudio as sa
     11 import pyaudio
     12 from vosk import Model as srModel
     13 from vosk import KaldiRecognizer
     14 from dimits import Dimits
     15 import ollama
     16 
     17 # Uncomment the following line to enable verbose logging
     18 # import logging
     19 # logging.basicConfig(level=logging.INFO)
     20 
     21 # Open serial port
     22 ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
     23 dt_model = Dimits("en_US-amy-medium")
     24 
     25 srmodel = srModel("/home/khan/srmodels/vosk-model-small-en-us-0.15")
     26 recognizer = KaldiRecognizer(srmodel, 16000)
     27 
     28 # Create a new instance of a ChatBot
     29 cbot = ChatBot(
     30     'Sylvie',
     31     storage_adapter='chatterbot.storage.SQLStorageAdapter',
     32     logic_adapters=[
     33         'chatterbot.logic.MathematicalEvaluation',
     34         # 'chatterbot.logic.TimeLogicAdapter',
     35         'chatterbot.logic.BestMatch'
     36     ],
     37     database_uri='sqlite:///sylvie_db.sqlite3'
     38 )
     39 
     40 learning_mode = False
     41 ollama_mode = False
     42 
     43 admin_name = "Princess Khan"
     44 admin_pronoun = "She"
     45 
     46 user_prefix = "You are Sylvie Deane who is a cute librarian from French Polynesia. You are 33 years old. You were born on April 12th, in 1991. Your job is to chat with me, " + admin_name + ". We have only just met on Tinder, and we are not sure about each other yet. I asked you: \n" + admin_name + ": '"
     47 user_suffix = "?' Now write a short and concise response in English. \n Sylvie Deane:"
     48 
     49 global_prefix = ""
     50 global_suffix = ""
     51 
     52 def get_feedback():
     53     text = input()
     54     if 'yes' in text.lower():
     55         return True
     56     elif 'no' in text.lower():
     57         return False
     58     else:
     59         print('Please type either "Yes" or "No"')
     60         return get_feedback()
     61 
     62 def send_command(user_text):
     63     # Determine the command type based on the length of the input
     64     if len(user_text.split()) > 10:
     65         command_type = "1sm"  # Use long command for speech
     66     elif len(user_text.split()) > 5:
     67         command_type = "1so"  # Use medium command for speech
     68     else:
     69         command_type = "1sn"
     70 
     71     # Send the mouth movement command to the robot
     72     ser.write(command_type.encode())  # Use variable command_type
     73     ser.write(b'\n')  # Assuming commands are terminated with a newline character
     74     print("[SYSTEM] Sent motor command")
     75 
     76 def generate_and_save_tts(dt_model, text):
     77     # Initialize Dimits with the desired voice model
     78     dt = dt_model
     79     # Convert text to audio and save it as a WAV file
     80     audio_path = dt.text_2_audio_file(text, "tts_output", "/home/khan/sylvie-2024/python/conversation/llama", format="wav")
     81     # Return None as the audio path (since it's saved to a file directly)
     82     return audio_path
     83 
     84 def play_audio_file(audio_path):
     85     # Play the saved WAV file using simpleaudio
     86     wave_obj = sa.WaveObject.from_wave_file(audio_path)
     87     play_obj = wave_obj.play()
     88     play_obj.wait_done()  # Wait for the audio playback to finish
     89 
     90 def ollama_get_text(ollama_prompt, max_attempts=3):
     91     attempt = 1
     92 
     93     final_prompt = global_prefix + ollama_prompt + global_suffix
     94     print("Final prompt:", final_prompt)
     95     
     96     while attempt <= max_attempts:
     97         # Generate a response using the Ollama API
     98         ollama_stream = ollama.chat(
     99             model='phi3',
    100             messages=[{'role': 'user', 'content': final_prompt}],
    101             stream=True,
    102         )
    103         
    104         generated_text = ""
    105         for chunk in ollama_stream:
    106             generated_text += chunk['message']['content']
    107             if len(generated_text) >= 75:
    108                 break
    109         
    110         # Remove newline characters and trim whitespace
    111         generated_text = generated_text.replace('\n', ' ').strip()
    112         
    113         # Find the last occurrence of punctuation in the generated text
    114         last_punctuation_index = max(generated_text.rfind('.'), generated_text.rfind('!'), generated_text.rfind('?'))
    115         
    116         # Check if the response ends with punctuation
    117         if last_punctuation_index != -1:
    118             generated_text = generated_text[:last_punctuation_index+1]  # Include the punctuation mark
    119         else:
    120             # If no punctuation found, use entire generated text
    121             last_punctuation_index = len(generated_text)
    122         
    123         # Check if the response is empty or incomplete
    124         if generated_text:
    125             if last_punctuation_index == len(generated_text) - 1:  # Response ends with punctuation
    126                 print("Ollama Response:", generated_text)
    127                 return generated_text
    128             else:
    129                 filler_words = ['um', 'well', 'you know', 'let me think', "I'm not sure", 'hmm', 'hold on', 'actually', 'that reminds me', 'by the way', 'oh, right', 'interesting', 'to be honest', 'give me a moment', 'pardon me', 'I suppose', 'it seems', 'so', 'in other words', 'in any case', 'anyway', 'as a matter of fact', 'on the other hand', 'as far as I know', 'it appears', 'nevermind']
    130                 filler = random.choice(filler_words)
    131                 generated_text += f'... {filler}'
    132                 print("Ollama Response:", generated_text)
    133                 return generated_text
    134         else:
    135             print("Ollama Response: No response received. Attempt", attempt)
    136             attempt += 1
    137     
    138     print("Ollama Response: No response received after", max_attempts, "attempts.")
    139     return None
    140 
    141 
    142 def store_ollama_response_in_chatterbot(cbot, user_input, ollama_response):
    143     input_statement = Statement(user_input)
    144     response_statement = Statement(ollama_response)
    145     cbot.learn_response(response_statement, input_statement)
    146 
    147 # If training the chatbot for first time use, uncomment some of these lines depending on your need
    148 #trainer = ChatterBotCorpusTrainer(cbot)
    149 #trainer.train("chatterbot.corpus.english")
    150 #trainer.train("./custom_corpus.yml")  # Train with custom data
    151 
    152 # The following loop will execute each time the user enters input
    153 while True:
    154     try:
    155         user_input = input("Say something to Sylvie: ")
    156 
    157         if user_input.lower() == "engage in learning mode":
    158             print('Learning mode engaged.')
    159             learning_mode = True
    160             continue
    161         elif user_input.lower() == "exit learning mode":
    162             print('Exiting learning mode.')
    163             learning_mode = False    
    164             continue
    165         elif user_input.lower() == "engage in ollama mode":
    166             print('Ollama mode engaged.')
    167             ollama_mode = True
    168             continue
    169         elif user_input.lower() == "exit ollama mode":
    170             print('Exiting Ollama mode.')
    171             ollama_mode = False
    172             continue
    173         elif user_input.lower() == "enable prompt context":
    174             print('Enabling the prompt context.')
    175             global_prefix = user_prefix
    176             global_suffix = user_suffix
    177             continue
    178         elif user_input.lower() == "disable prompt context":
    179             print('Disabling the prompt context.')
    180             global_prefix = ""
    181             global_suffix = ""
    182             continue
    183         elif user_input.lower() == "enable microphone":
    184             print('Microphone enabled.')
    185             # To do
    186             continue
    187         elif user_input.lower() == "disable microphone":
    188             print('Microphone disabled.')
    189             # To do
    190             continue
    191 
    192         if learning_mode:
    193             input_statement = Statement(user_input)
    194             response = cbot.generate_response(input_statement)
    195             print('\nIs "{}" a coherent response to "{}"? \n'.format(response.text, input_statement.text))
    196             if get_feedback() is False:
    197                 print('Please input the correct one.')
    198                 correct_response = Statement(text=input())
    199                 cbot.learn_response(correct_response, input_statement)
    200                 print('Responses added to bot!')
    201         
    202         elif ollama_mode:
    203             ollama_response = ollama_get_text(user_input)
    204             print("Ollama Response:", ollama_response)
    205             store_ollama_response_in_chatterbot(cbot, user_input, ollama_response)
    206             
    207             audio_path = generate_and_save_tts(dt_model, ollama_response)
    208             
    209             send_command(ollama_response)
    210             play_audio_file(audio_path)
    211             #play_audio_file(generate_and_save_tts(dt_model, ollama_response))
    212         
    213         else:
    214             bot_response = cbot.get_response(user_input)
    215             print(bot_response)
    216             
    217             audio_path = generate_and_save_tts(dt_model, bot_response.text)
    218             
    219             send_command(bot_response.text)
    220             play_audio_file(audio_path)            
    221             #play_audio_file(generate_and_save_tts(dt_model, bot_response.text))
    222 
    223     # Press ctrl-c or ctrl-d on the keyboard to exit
    224     except (KeyboardInterrupt, EOFError, SystemExit):
    225         break