Skip to content

Instantly share code, notes, and snippets.

@graylan0
Created November 21, 2023 19:59
Show Gist options
  • Save graylan0/24add30f54d38acbf7f9206dc354848b to your computer and use it in GitHub Desktop.
Save graylan0/24add30f54d38acbf7f9206dc354848b to your computer and use it in GitHub Desktop.
import asyncio
import threading
import uuid
import logging
from concurrent.futures import ThreadPoolExecutor
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
from kivy.uix.label import Label
import weaviate
from llama_cpp import Llama
import platform
if platform.system() == 'Windows':
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
KV = '''
ScreenManager:
ChatScreen:
SettingsScreen:
<ChatScreen>:
name: 'chat'
BoxLayout:
orientation: 'vertical'
ActionBar:
background_color: 0.3, 0.3, 0.3, 1
pos_hint: {'top':1}
ActionView:
use_separator: True
ActionPrevious:
title: 'Chat with Bot'
with_previous: False
app_icon: ''
color: 1, 1, 1, 1
ActionButton:
icon: 'brain'
on_release: app.analyze_emotion(message_input.text)
color: 0.9, 0.9, 0.9, 1
ActionButton:
text: 'Settings'
on_release: app.root.current = 'settings'
color: 0.9, 0.9, 0.9, 1
BoxLayout:
canvas.before:
Color:
rgba: 0.2, 0.2, 0.2, 1
Rectangle:
pos: self.pos
size: self.size
RecycleView:
id: chat_list
viewclass: 'ChatLabel'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
BoxLayout:
size_hint_y: None
height: dp(50)
padding: dp(4)
spacing: dp(4)
canvas.before:
Color:
rgba: 0.1, 0.1, 0.1, 1
Rectangle:
pos: self.pos
size: self.size
TextInput:
id: message_input
hint_text: 'Type a message...'
background_color: 1, 1, 1, 0.3
foreground_color: 1, 1, 1, 1
size_hint_x: 0.8
multiline: False
on_text_validate: app.llama_generate_wrapper(message_input.text)
Button:
text: 'Send'
background_normal: ''
background_color: 0.8, 0.8, 0.8, 1
color: 0, 0, 0, 1
on_release: app.llama_generate_wrapper(message_input.text)
<SettingsScreen>:
name: 'settings'
BoxLayout:
orientation: 'vertical'
ActionBar:
background_color: 0.3, 0.3, 0.3, 1
pos_hint: {'top':1}
ActionView:
use_separator: True
ActionPrevious:
title: 'Settings'
with_previous: False
app_icon: ''
color: 1, 1, 1, 1
ActionButton:
text: 'Back'
on_release: app.root.current = 'chat'
color: 0.9, 0.9, 0.9, 1
GridLayout:
cols: 1
padding: dp(24)
spacing: dp(15)
TextInput:
id: api_key
hint_text: 'OpenAI API Key'
multiline: False
padding_y: dp(10)
padding_x: dp(10)
size_hint_x: 0.8
pos_hint: {'center_x': 0.5}
Button:
text: 'Save Settings'
size_hint_x: 0.8
pos_hint: {'center_x': 0.5}
on_release: app.save_settings(api_key.text)
<ChatLabel>:
size_hint_y: None
height: self.texture_size[1]
padding: 10, 10
halign: 'left'
valign: 'middle'
text_size: self.width, None
'''
class ChatScreen(Screen):
pass
class SettingsScreen(Screen):
pass
class ChatLabel(Label):
text = StringProperty()
class ChatApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.loop = asyncio.new_event_loop()
self.executor = ThreadPoolExecutor(max_workers=4)
def start_async_loop(self):
asyncio.set_event_loop(self.loop)
self.loop.run_forever()
def build(self):
threading.Thread(target=self.start_async_loop, daemon=True).start()
self.screen_manager = ScreenManager()
self.screen_manager.add_widget(ChatScreen(name='chat'))
self.screen_manager.add_widget(SettingsScreen(name='settings'))
self.client = weaviate.Client(url="https://tolerant-subtly-foxhound.ngrok-free.app")
self.llm = Llama(
model_path="llama-2-7b-chat.ggmlv3.q8_0.bin",
n_gpu_layers=-1,
n_ctx=3900,
)
return Builder.load_string(KV)
def llama_generate_wrapper(self, prompt):
print("Llama generate wrapper called")
coroutine = self.llama_generate(prompt)
asyncio.run_coroutine_threadsafe(coroutine, self.loop)
async def llama_generate(self, prompt, max_tokens=2500, chunk_size=500):
try:
print("Llama generate called with prompt:", prompt)
prompt_chunks = [prompt[i:i + chunk_size] for i in range(0, len(prompt), chunk_size)]
responses = []
last_output = ""
for i, chunk in enumerate(prompt_chunks):
# Adjust this line to correctly pass arguments to the Llama model
output_dict = await asyncio.get_event_loop().run_in_executor(self.executor, lambda: self.llm(chunk, max_tokens=min(max_tokens, chunk_size)))
output = output_dict.get('text', '')
if i > 0 and last_output:
overlap = len(set(last_output[-300:]).intersection(set(output[:300])))
output = output[overlap:]
responses.append(output)
last_output = output
final_response = ''.join(responses)
print("Llama generate response:", final_response)
return final_response
except Exception as e:
logging.error(f"Llama generate error: {e}")
return "Error in generating response."
async def retrieve_past_interactions(self):
query = {
"class": "InteractionHistory",
"properties": ["user_message", "ai_response"],
}
response = await asyncio.get_event_loop().run_in_executor(self.executor, self.client.query.raw, query)
interactions = response['data']['Get']['InteractionHistory']
return interactions
def format_prompt(self, past_interactions, current_message):
formatted_interactions = "\n".join([f"User: {interaction['user_message']}\nAI: {interaction['ai_response']}" for interaction in past_interactions])
return f"{formatted_interactions}\nUser: {current_message}"
async def store_interaction_in_weaviate(self, user_message, ai_response):
interaction_object = {
"user_message": user_message,
"ai_response": ai_response,
}
interaction_uuid = uuid.uuid4()
await asyncio.get_event_loop().run_in_executor(self.executor, self.client.data_object.create, interaction_object, "InteractionHistory", interaction_uuid)
def save_settings(self, api_key):
pass
if __name__ == '__main__':
ChatApp().run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment