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
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
sp = speak.Speak()
graph = agent.Agent()
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 "exit" in text.lower():
break
response = loop.run_until_complete(graph.invoke_agent(text))
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
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.agents import create_openai_tools_agent
from langchain.prompts import PromptTemplate, SystemMessagePromptTemplate
@ -8,7 +8,7 @@ from langchain import hub
from langchain_core.tools import tool
from langgraph.graph import StateGraph, END
import asyncio
import json
@ -19,6 +19,7 @@ class Agent:
self.ap = app_launcher.AppLauncher()
self.wf = windows_focus.WindowFocusManager()
self.llm = self.ad.llm_chat
self.spk = speak.Speak()
@ -29,9 +30,9 @@ class Agent:
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!"
@ -46,16 +47,13 @@ class Agent:
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(
llm=self.llm,
tools=[
# self.rag_final_answer_tool,
self.spotify,
self.app_launcher,
self.windows_focus
self.windows_focus,
self.journal_mode
],
prompt=self.prompt,
)
@ -70,34 +68,43 @@ class Agent:
agent_out: Union[AgentAction, AgentFinish, None]
intermediate_steps: Annotated[List[tuple[AgentAction, str]], operator.add]
#! Tools
@tool("respond")
async def respond(self, answer: str):
"""Returns a natural language response to the user in `answer`"""
return ""
#! Tools
@tool("spotify")
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"""
return ""
@tool("app_launcher")
async def app_launcher(self, app_name: str):
"""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
"""
@tool("windows_focus")
async def windows_focus(self, app_name: str):
"""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
pass the name of the app to this tool as app_name
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.
"""
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):
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("windows_focus", self.windows_focus_tool)
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.add_conditional_edges(
@ -114,13 +122,15 @@ class Agent:
"spotify": "spotify",
"respond": "respond",
"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("app_launcher", END)
self.graph.add_edge("windows_focus", END)
self.graph.add_edge("respond", END)
self.graph.add_edge("journal_mode", END)
self.runnable = self.graph.compile()
@ -132,6 +142,18 @@ class Agent:
print(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):
try:
print("> spotify_tool")
@ -167,7 +189,8 @@ class Agent:
print("> app_launcher_tool")
print(f"state: {state}")
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}")
self.ap.find_and_open_app(app_name)
@ -175,7 +198,8 @@ class Agent:
print("> windows_focus_tool")
print(f"state: {state}")
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}")
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
#! listen with vosk
def listen2(self, noise_threshold=500):
def listen2(self, time_listen=15):
noise_threshold=500
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=8000)
stream.start_stream()
print("Listening...")
count = 0
try:
while count < 10:
while count < time_listen:
data = stream.read(8000, exception_on_overflow=False)
filtered_data = nr.reduce_noise(y=frombuffer(data, dtype=int16), sr=16000).astype(int16).tobytes()
@ -154,7 +155,7 @@ class Speak:
stream = None
# 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''
for chunk in response.iter_content(chunk_size=chunk_size):
@ -171,7 +172,7 @@ class Speak:
)
# Randomly adjust pitch
octaves = random.uniform(-0.5, 1.5)
octaves = random.uniform(-0.1, 1.5)
modified_chunk = change_pitch(audio_segment, octaves)
if random.random() < 0.001: # 1% chance to trigger stutter

View File

@ -1,55 +1,101 @@
import spotipy
import environ
from spotipy.oauth2 import SpotifyOAuth
from requests.exceptions import ConnectionError, HTTPError
import time
import functools
env = environ.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:
def __init__(self):
self.sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=env("spotify_client_id"),
client_secret=env("spotify_client_secret"),
redirect_uri=env("spotify_redirect_uri"),
scope="user-modify-playback-state user-read-playback-state user-library-modify"))
self.auth_manager = SpotifyOAuth(
client_id=env("spotify_client_id"),
client_secret=env("spotify_client_secret"),
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):
devices = self.sp.devices()
if devices['devices']:
# Select the first active device
active_device_id = devices['devices'][0]['id']
return active_device_id
else:
try:
devices = self.sp.devices()
if devices['devices']:
active_device_id = devices['devices'][0]['id']
return active_device_id
else:
return None
except spotipy.exceptions.SpotifyException as e:
print(f"Error fetching devices: {e}")
return None
def play(self):
def refresh_token(self):
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)
except Exception as e:
print(f"Failed to play: {e}")
def pause(self):
try:
device_id = self.get_active_device()
print("Playback started successfully.")
else:
print("No active device found.")
@handle_spotify_errors_and_device
def pause(self, device_id=None):
if device_id:
self.sp.pause_playback(device_id=device_id)
except Exception as e:
print(f"Failed to pause playback: {e}")
def next_track(self):
try:
device_id = self.get_active_device()
print("Playback paused successfully.")
else:
print("No active device found.")
@handle_spotify_errors_and_device
def next_track(self, device_id=None):
if device_id:
self.sp.next_track(device_id=device_id)
except Exception as e:
print(f"Failed to skip to the next track: {e}")
def previous_track(self):
try:
device_id = self.get_active_device()
else:
print("Failed to skip to the next track")
@handle_spotify_errors_and_device
def previous_track(self, device_id=None):
if device_id:
self.sp.previous_track(device_id=device_id)
except Exception as e:
print(f"Failed to go to the previous track: {e}")
def favorite_current_song(self):
try:
else:
print("Failed to go to the previous track")
@handle_spotify_errors_and_device
def favorite_current_song(self, device_id=None):
if device_id:
current_track = self.sp.current_playback()
if current_track and current_track['item']:
track_id = current_track['item']['id']
@ -57,15 +103,15 @@ class Spotify:
print(f"Added '{current_track['item']['name']}' to favorites")
else:
print("No song is currently playing")
except Exception as e:
print(f"Failed to add current song to favorites: {e}")
def search_song_and_play(self, song_name):
else:
print("Failed to add current song to favorites")
@handle_spotify_errors_and_device
def search_song_and_play(self, song_name, device_id=None):
try:
results = self.sp.search(q='track:' + song_name, type='track')
if results['tracks']['items']:
track_uri = results['tracks']['items'][0]['uri']
device_id = self.get_active_device()
if device_id:
self.sp.start_playback(device_id=device_id, uris=[track_uri])
else:
@ -74,13 +120,13 @@ class Spotify:
print(f"No results found for song: {song_name}")
except Exception as 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:
results = self.sp.search(q='artist:' + artist_name, type='artist')
if results['artists']['items']:
artist_uri = results['artists']['items'][0]['uri']
device_id = self.get_active_device()
if device_id:
self.sp.start_playback(device_id=device_id, context_uri=artist_uri)
else:
@ -89,13 +135,13 @@ class Spotify:
print(f"No results found for artist: {artist_name}")
except Exception as 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:
results = self.sp.search(q='album:' + album_name, type='album')
if results['albums']['items']:
album_uri = results['albums']['items'][0]['uri']
device_id = self.get_active_device()
if device_id:
self.sp.start_playback(device_id=device_id, context_uri=album_uri)
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