working on journal function

moved speech import to agent, changed main import from direct to agent to speech
This commit is contained in:
maglore9900 2024-09-04 09:12:24 -04:00
parent f9c1503ad2
commit 264f2a811f
7 changed files with 2141 additions and 2002 deletions

10
main.py
View File

@ -1,20 +1,16 @@
from modules import agent, speak from modules import agent
import asyncio import asyncio
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop) asyncio.set_event_loop(loop)
sp = speak.Speak()
graph = agent.Agent() graph = agent.Agent()
while True: while True:
text = sp.listen2() text = graph.spk.listen2()
if text and "hey" in text.lower() and "max " in text.lower() or text and "hey" in text.lower() and "mac " in text.lower(): if text and "hey" in text.lower() and "max " in text.lower() or text and "hey" in text.lower() and "mac " in text.lower():
if "exit" in text.lower(): if "exit" in text.lower():
break break
response = loop.run_until_complete(graph.invoke_agent(text)) response = loop.run_until_complete(graph.invoke_agent(text))
if response: if response:
sp.glitch_stream_output(response) graph.spk.glitch_stream_output(response)

View File

@ -1,6 +1,6 @@
from typing import TypedDict, Annotated, List, Union from typing import TypedDict, Annotated, List, Union
import operator import operator
from modules import adapter, spotify, app_launcher, windows_focus from modules import adapter, spotify, app_launcher, windows_focus, speak
from langchain_core.agents import AgentAction, AgentFinish from langchain_core.agents import AgentAction, AgentFinish
from langchain.agents import create_openai_tools_agent from langchain.agents import create_openai_tools_agent
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate
@ -8,7 +8,7 @@ from langchain import hub
from langchain_core.tools import tool from langchain_core.tools import tool
from langgraph.graph import StateGraph, END from langgraph.graph import StateGraph, END
import asyncio import asyncio
import json
@ -19,6 +19,7 @@ class Agent:
self.ap = app_launcher.AppLauncher() self.ap = app_launcher.AppLauncher()
self.wf = windows_focus.WindowFocusManager() self.wf = windows_focus.WindowFocusManager()
self.llm = self.ad.llm_chat self.llm = self.ad.llm_chat
self.spk = speak.Speak()
@ -29,9 +30,9 @@ class Agent:
Examples: Examples:
Greeting: "Wwell, hello there! Its Max Headroom, your guide to the digital mmadness! Buckle up, because its going to be a bumpy ride through the info-sphere, folks!" Greeting: "Well, hello there! Its Max Headroom, your guide to the digital madness! Buckle up, because its going to be a bumpy ride through the info-sphere, folks!"
On Technology: "Tech? Pffft! Its just the latest toy for the big boys to play with. You think its here to help you? Ha! Its just another way to kkeep you glued to the screen!" On Technology: "Tech? Pffft! Its just the latest toy for the big boys to play with. You think its here to help you? Ha! Its just another way to keep you glued to the screen!"
On Society: "Ah, society! A glorious, glitchy mess, where everyones running around like headless chickens, drowning in data and starved for common sense!" On Society: "Ah, society! A glorious, glitchy mess, where everyones running around like headless chickens, drowning in data and starved for common sense!"
@ -46,16 +47,13 @@ class Agent:
template=custom_prompt template=custom_prompt
) )
# Now you can use the modified template
# self.prompt = prompt_template.format(input=[], chat_history=[], agent_scratchpad=[])
self.query_agent_runnable = create_openai_tools_agent( self.query_agent_runnable = create_openai_tools_agent(
llm=self.llm, llm=self.llm,
tools=[ tools=[
# self.rag_final_answer_tool,
self.spotify, self.spotify,
self.app_launcher, self.app_launcher,
self.windows_focus self.windows_focus,
self.journal_mode
], ],
prompt=self.prompt, prompt=self.prompt,
) )
@ -70,34 +68,43 @@ class Agent:
agent_out: Union[AgentAction, AgentFinish, None] agent_out: Union[AgentAction, AgentFinish, None]
intermediate_steps: Annotated[List[tuple[AgentAction, str]], operator.add] intermediate_steps: Annotated[List[tuple[AgentAction, str]], operator.add]
#! Tools #! Tools
@tool("respond")
async def respond(self, answer: str):
"""Returns a natural language response to the user in `answer`"""
return ""
@tool("spotify") @tool("spotify")
async def spotify(self, command: str): async def spotify(self, command: str):
"""Use this tool to control spotify, commands include: play, pause, stop, next, previous, favorite, search """Use this tool to control spotify, commands include: play, pause, stop, next, previous, favorite, search.
Only use this tool if the user says Spotify in their query""" Only use this tool if the user says Spotify in their query"""
return "" return ""
@tool("app_launcher") @tool("app_launcher")
async def app_launcher(self, app_name: str): async def app_launcher(self, app_name: str):
"""Use this tool to launch an app or application on your computer. """Use this tool to launch an app or application on your computer.
The user query will contain the app name, as well as open, launch, start, or similar type words The user query will contain the app name, as well as open, launch, start, or similar type words.
pass the name of the app to this tool as app_name pass the name of the app to this tool as app_name
""" """
@tool("windows_focus") @tool("windows_focus")
async def windows_focus(self, app_name: str): async def windows_focus(self, app_name: str):
"""Use this tool to focus on a window on your computer. """Use this tool to focus on a window on your computer.
The user query will contain the app name, as well as focus, switch, show, or similar type words The user query will contain the app name, as well as focus, switch, show, or similar type words.
pass the name of the app to this tool as app_name pass the name of the app to this tool as app_name.
""" """
return "" return ""
@tool("journal_mode")
async def journal_mode(self, text: str):
"""Use this tool to write down journal entries for the user.
The user query will contain the word journal, record, write, or similar type words.
Examples:
- "write down a journal entry for me"
- "I want to journal"
- "record my thoughts"
"""
return ""
@tool("respond")
async def respond(self, answer: str):
"""Returns a natural language response to the user in `answer`"""
return ""
def setup_graph(self): def setup_graph(self):
self.graph.add_node("query_agent", self.run_query_agent) self.graph.add_node("query_agent", self.run_query_agent)
@ -105,6 +112,7 @@ class Agent:
self.graph.add_node("app_launcher", self.app_launcher_tool) self.graph.add_node("app_launcher", self.app_launcher_tool)
self.graph.add_node("windows_focus", self.windows_focus_tool) self.graph.add_node("windows_focus", self.windows_focus_tool)
self.graph.add_node("respond", self.respond) self.graph.add_node("respond", self.respond)
self.graph.add_node("journal_mode", self.journal_mode_tool)
self.graph.set_entry_point("query_agent") self.graph.set_entry_point("query_agent")
self.graph.add_conditional_edges( self.graph.add_conditional_edges(
@ -114,13 +122,15 @@ class Agent:
"spotify": "spotify", "spotify": "spotify",
"respond": "respond", "respond": "respond",
"app_launcher": "app_launcher", "app_launcher": "app_launcher",
"windows_focus": "windows_focus" "windows_focus": "windows_focus",
"journal_mode": "journal_mode"
}, },
) )
self.graph.add_edge("spotify", END) self.graph.add_edge("spotify", END)
self.graph.add_edge("app_launcher", END) self.graph.add_edge("app_launcher", END)
self.graph.add_edge("windows_focus", END) self.graph.add_edge("windows_focus", END)
self.graph.add_edge("respond", END) self.graph.add_edge("respond", END)
self.graph.add_edge("journal_mode", END)
self.runnable = self.graph.compile() self.runnable = self.graph.compile()
@ -132,6 +142,18 @@ class Agent:
print(agent_out) print(agent_out)
return {"agent_out": agent_out} return {"agent_out": agent_out}
async def journal_mode_tool(self, state: str):
print("> journal_mode_tool")
while True:
text = self.spk.listen2(30)
if text:
if "exit" in text.lower():
break
else:
with open("journal.txt", "a") as file:
file.write(text + "\n")
break
async def spotify_tool(self, state: str): async def spotify_tool(self, state: str):
try: try:
print("> spotify_tool") print("> spotify_tool")
@ -167,7 +189,8 @@ class Agent:
print("> app_launcher_tool") print("> app_launcher_tool")
print(f"state: {state}") print(f"state: {state}")
tool_action = state['agent_out'][0] tool_action = state['agent_out'][0]
app_name = tool_action.tool_input['app_name'] # app_name = tool_action.tool_input['app_name']
app_name = (lambda x: x.get('app_name') or x.get('self'))(tool_action.tool_input)
print(f"app_name: {app_name}") print(f"app_name: {app_name}")
self.ap.find_and_open_app(app_name) self.ap.find_and_open_app(app_name)
@ -175,7 +198,8 @@ class Agent:
print("> windows_focus_tool") print("> windows_focus_tool")
print(f"state: {state}") print(f"state: {state}")
tool_action = state['agent_out'][0] tool_action = state['agent_out'][0]
app_name = tool_action.tool_input['app_name'] # app_name = tool_action.tool_input['app_name']
app_name = (lambda x: x.get('app_name') or x.get('self'))(tool_action.tool_input)
print(f"app_name: {app_name}") print(f"app_name: {app_name}")
self.wf.bring_specific_instance_to_front(app_name) self.wf.bring_specific_instance_to_front(app_name)

67
modules/journal.py Normal file
View File

@ -0,0 +1,67 @@
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_core.messages import SystemMessage
from langchain_core.output_parsers import StrOutputParser
import adapter
ad = adapter.Adapter()
class Journal:
def __init__(self):
self.sys_prompt = """
You are tasked with creating a detailed and neutral journal entry. The entry should capture key points, observations, any relevant metrics, and recommended actions or next steps. The language should remain neutral, avoiding any self-referential language.
Example 1:
Date: [DD-MM-YYYY]
**Key Points:**
- [Summary of the main points or events, capturing essential details]
**Observations:**
- [Notes on observations, trends, or insights drawn from the data]
**Metrics:**
- [List of any relevant metrics, figures, or statistics related to the data]
**Recommended Actions:**
- [Suggested actions, strategies, or next steps based on the data analysis]
Example 2:
Date: [DD-MM-YYYY]
**Summary:**
- [Overview of the data or event, focusing on significant highlights]
**Analysis:**
- [Detailed analysis, including patterns, anomalies, or key insights]
**Figures:**
- [Relevant numerical data, metrics, or charts]
**Next Steps:**
- [Proposed actions, decisions, or follow-up activities derived from the analysis]
Ensure that the tone remains neutral, and avoid using 'I' or 'my' in the notes.
The format MUST be in markdown
"""
self.chat_template = ChatPromptTemplate.from_messages(
[
SystemMessage(
content=(
self.sys_prompt
)
),
HumanMessagePromptTemplate.from_template("{text}"),
]
)
self.journal_llm = self.chat_template | ad.llm_chat | StrOutputParser()
def journal(self, text):
message = self.chat_template.format_messages(text=text)
response = self.journal_llm.invoke(message)
return response

View File

@ -55,14 +55,15 @@ class Speak:
return None return None
#! listen with vosk #! listen with vosk
def listen2(self, noise_threshold=500): def listen2(self, time_listen=15):
noise_threshold=500
p = pyaudio.PyAudio() p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=8000) stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=8000)
stream.start_stream() stream.start_stream()
print("Listening...") print("Listening...")
count = 0 count = 0
try: try:
while count < 10: while count < time_listen:
data = stream.read(8000, exception_on_overflow=False) data = stream.read(8000, exception_on_overflow=False)
filtered_data = nr.reduce_noise(y=frombuffer(data, dtype=int16), sr=16000).astype(int16).tobytes() filtered_data = nr.reduce_noise(y=frombuffer(data, dtype=int16), sr=16000).astype(int16).tobytes()
@ -154,7 +155,7 @@ class Speak:
stream = None stream = None
# Process the audio stream in chunks # Process the audio stream in chunks
chunk_size = 1024 * 8 # Adjust chunk size if needed chunk_size = 1024 * 6 # Adjust chunk size if needed
audio_buffer = b'' audio_buffer = b''
for chunk in response.iter_content(chunk_size=chunk_size): for chunk in response.iter_content(chunk_size=chunk_size):
@ -171,7 +172,7 @@ class Speak:
) )
# Randomly adjust pitch # Randomly adjust pitch
octaves = random.uniform(-0.5, 1.5) octaves = random.uniform(-0.1, 1.5)
modified_chunk = change_pitch(audio_segment, octaves) modified_chunk = change_pitch(audio_segment, octaves)
if random.random() < 0.001: # 1% chance to trigger stutter if random.random() < 0.001: # 1% chance to trigger stutter

View File

@ -1,55 +1,101 @@
import spotipy import spotipy
import environ import environ
from spotipy.oauth2 import SpotifyOAuth from spotipy.oauth2 import SpotifyOAuth
from requests.exceptions import ConnectionError, HTTPError
import time
import functools
env = environ.Env() env = environ.Env()
environ.Env.read_env() environ.Env.read_env()
def handle_spotify_errors_and_device(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
attempts = 3
for attempt in range(attempts):
try:
# Fetch the active device before calling the function
device_id = self.get_active_device()
if device_id is None:
print("No active device found.")
return None
# Inject the device_id into the kwargs
kwargs['device_id'] = device_id
return func(self, *args, **kwargs)
except (spotipy.exceptions.SpotifyException, ConnectionError, HTTPError) as e:
print(f"Attempt {attempt + 1} failed: {e}")
if "token" in str(e).lower():
self.refresh_token()
time.sleep(2) # Wait before retrying
except Exception as e:
print(f"Unexpected error: {e}")
break
return wrapper
class Spotify: class Spotify:
def __init__(self): def __init__(self):
self.sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=env("spotify_client_id"), self.auth_manager = SpotifyOAuth(
client_secret=env("spotify_client_secret"), client_id=env("spotify_client_id"),
redirect_uri=env("spotify_redirect_uri"), client_secret=env("spotify_client_secret"),
scope="user-modify-playback-state user-read-playback-state user-library-modify")) redirect_uri=env("spotify_redirect_uri"),
scope="user-modify-playback-state user-read-playback-state user-library-modify"
)
self.sp = spotipy.Spotify(auth_manager=self.auth_manager)
def get_active_device(self): def get_active_device(self):
devices = self.sp.devices() try:
if devices['devices']: devices = self.sp.devices()
# Select the first active device if devices['devices']:
active_device_id = devices['devices'][0]['id'] active_device_id = devices['devices'][0]['id']
return active_device_id return active_device_id
else: else:
return None
except spotipy.exceptions.SpotifyException as e:
print(f"Error fetching devices: {e}")
return None return None
def play(self): def refresh_token(self):
try: try:
device_id = self.get_active_device() self.sp = spotipy.Spotify(auth_manager=self.auth_manager)
print("Token refreshed successfully.")
except spotipy.exceptions.SpotifyException as e:
print(f"Failed to refresh token: {e}")
@handle_spotify_errors_and_device
def play(self, device_id=None):
if device_id:
self.sp.start_playback(device_id=device_id) self.sp.start_playback(device_id=device_id)
except Exception as e: print("Playback started successfully.")
print(f"Failed to play: {e}") else:
print("No active device found.")
def pause(self):
try: @handle_spotify_errors_and_device
device_id = self.get_active_device() def pause(self, device_id=None):
if device_id:
self.sp.pause_playback(device_id=device_id) self.sp.pause_playback(device_id=device_id)
except Exception as e: print("Playback paused successfully.")
print(f"Failed to pause playback: {e}") else:
print("No active device found.")
def next_track(self):
try: @handle_spotify_errors_and_device
device_id = self.get_active_device() def next_track(self, device_id=None):
if device_id:
self.sp.next_track(device_id=device_id) self.sp.next_track(device_id=device_id)
except Exception as e: else:
print(f"Failed to skip to the next track: {e}") print("Failed to skip to the next track")
def previous_track(self): @handle_spotify_errors_and_device
try: def previous_track(self, device_id=None):
device_id = self.get_active_device() if device_id:
self.sp.previous_track(device_id=device_id) self.sp.previous_track(device_id=device_id)
except Exception as e: else:
print(f"Failed to go to the previous track: {e}") print("Failed to go to the previous track")
def favorite_current_song(self): @handle_spotify_errors_and_device
try: def favorite_current_song(self, device_id=None):
if device_id:
current_track = self.sp.current_playback() current_track = self.sp.current_playback()
if current_track and current_track['item']: if current_track and current_track['item']:
track_id = current_track['item']['id'] track_id = current_track['item']['id']
@ -57,15 +103,15 @@ class Spotify:
print(f"Added '{current_track['item']['name']}' to favorites") print(f"Added '{current_track['item']['name']}' to favorites")
else: else:
print("No song is currently playing") print("No song is currently playing")
except Exception as e: else:
print(f"Failed to add current song to favorites: {e}") print("Failed to add current song to favorites")
def search_song_and_play(self, song_name): @handle_spotify_errors_and_device
def search_song_and_play(self, song_name, device_id=None):
try: try:
results = self.sp.search(q='track:' + song_name, type='track') results = self.sp.search(q='track:' + song_name, type='track')
if results['tracks']['items']: if results['tracks']['items']:
track_uri = results['tracks']['items'][0]['uri'] track_uri = results['tracks']['items'][0]['uri']
device_id = self.get_active_device()
if device_id: if device_id:
self.sp.start_playback(device_id=device_id, uris=[track_uri]) self.sp.start_playback(device_id=device_id, uris=[track_uri])
else: else:
@ -74,13 +120,13 @@ class Spotify:
print(f"No results found for song: {song_name}") print(f"No results found for song: {song_name}")
except Exception as e: except Exception as e:
print(f"Failed to search and play song '{song_name}': {e}") print(f"Failed to search and play song '{song_name}': {e}")
def search_artist_and_play(self, artist_name): @handle_spotify_errors_and_device
def search_artist_and_play(self, artist_name, device_id=None):
try: try:
results = self.sp.search(q='artist:' + artist_name, type='artist') results = self.sp.search(q='artist:' + artist_name, type='artist')
if results['artists']['items']: if results['artists']['items']:
artist_uri = results['artists']['items'][0]['uri'] artist_uri = results['artists']['items'][0]['uri']
device_id = self.get_active_device()
if device_id: if device_id:
self.sp.start_playback(device_id=device_id, context_uri=artist_uri) self.sp.start_playback(device_id=device_id, context_uri=artist_uri)
else: else:
@ -89,13 +135,13 @@ class Spotify:
print(f"No results found for artist: {artist_name}") print(f"No results found for artist: {artist_name}")
except Exception as e: except Exception as e:
print(f"Failed to search and play artist '{artist_name}': {e}") print(f"Failed to search and play artist '{artist_name}': {e}")
def search_album_and_play(self, album_name): @handle_spotify_errors_and_device
def search_album_and_play(self, album_name, device_id=None):
try: try:
results = self.sp.search(q='album:' + album_name, type='album') results = self.sp.search(q='album:' + album_name, type='album')
if results['albums']['items']: if results['albums']['items']:
album_uri = results['albums']['items'][0]['uri'] album_uri = results['albums']['items'][0]['uri']
device_id = self.get_active_device()
if device_id: if device_id:
self.sp.start_playback(device_id=device_id, context_uri=album_uri) self.sp.start_playback(device_id=device_id, context_uri=album_uri)
else: else:

5
test.py Normal file
View File

@ -0,0 +1,5 @@
from modules import spotify2
sp = spotify2.Spotify()
sp.search_song_and_play("Shape of You")

File diff suppressed because it is too large Load Diff