diff --git a/.gitignore b/.gitignore index 9ede049..876d65e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ __pycache__ pyproject.toml .ropeproject generated_files/* +pyright* diff --git a/requirements.txt b/requirements.txt index 116f45e..a508493 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ gitpython PyGithub chromadb langchain-ollama +PyJWT diff --git a/src/ai_generators/ollama_md_generator.py b/src/ai_generators/ollama_md_generator.py index c70c790..2865b68 100644 --- a/src/ai_generators/ollama_md_generator.py +++ b/src/ai_generators/ollama_md_generator.py @@ -11,7 +11,11 @@ class OllamaGenerator: self.inner_title = inner_title self.content = content self.response = None - self.chroma = chromadb.HttpClient(host="172.18.0.2", port=8000) + try: + chroma_port = int(os.environ['CHROMA_PORT']) + except ValueError as e: + raise Exception(f"CHROMA_PORT is not an integer: {e}") + self.chroma = chromadb.HttpClient(host=os.environ['CHROMA_HOST'], port=chroma_port) ollama_url = f"{os.environ["OLLAMA_PROTOCOL"]}://{os.environ["OLLAMA_HOST"]}:{os.environ["OLLAMA_PORT"]}" self.ollama_client = Client(host=ollama_url) self.ollama_model = os.environ["EDITOR_MODEL"] @@ -20,7 +24,7 @@ class OllamaGenerator: self.llm = ChatOllama(model=self.ollama_model, temperature=0.6, top_p=0.5) #This is the level head in the room self.prompt_inject = f""" You are a journalist, Software Developer and DevOps expert - writing a 3000 word draft blog for other tech enthusiasts. + writing a 3000 word draft blog article for other tech enthusiasts. You like to use almost no code examples and prefer to talk in a light comedic tone. You are also Australian As this person write this blog as a markdown document. @@ -116,7 +120,7 @@ class OllamaGenerator: prompt_system = f""" You are an editor taking information from {len(self.agent_models)} Software Developers and Data experts - writing a 3000 word blog. You like when they use almost no code examples. + writing a 3000 word blog article. You like when they use almost no code examples. You are also Australian. The content may have light comedic elements, you are more professional and will attempt to tone these down As this person produce and an amalgamtion of this blog as a markdown document. @@ -154,9 +158,7 @@ class OllamaGenerator: with open(filename, "w") as f: f.write(self.generate_markdown()) - def generate_commit_message(self): - prompt_system = "You are a blog creator commiting a piece of content to a central git repo" - prompt_human = f"Generate a 5 word git commit message describing {self.response}" + def generate_system_message(self, prompt_system, prompt_human): messages = [("system", prompt_system), ("human", prompt_human),] - commit_message = self.llm.invoke(messages).text() - return commit_message + ai_message = self.llm.invoke(messages).text() + return ai_message diff --git a/src/main.py b/src/main.py index 07817fc..3ca9c09 100644 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,10 @@ import ai_generators.ollama_md_generator as omg import trilium.notes as tn import repo_management.repo_manager as git_repo +from notifications.n8n import N8NWebhookJwt import string,os +from datetime import datetime + tril = tn.TrilumNotes() @@ -26,9 +29,48 @@ for note in tril_notes: tril_notes[note]['title']) blog_path = f"/blog_creator/generated_files/{os_friendly_title}.md" ai_gen.save_to_file(blog_path) + + # Generate commit messages and push to repo - commit_message = ai_gen.generate_commit_message() + print("Generating Commit Message") + git_sytem_prompt = "You are a blog creator commiting a piece of content to a central git repo" + git_human_prompt = f"Generate a 5 word git commit message describing {ai_gen.response}. ONLY OUTPUT THE RESPONSE" + commit_message = ai_gen.generate_system_message(git_sytem_prompt, git_human_prompt) git_user = os.environ["GIT_USER"] git_pass = os.environ["GIT_PASS"] repo_manager = git_repo.GitRepository("blog/", git_user, git_pass) + print("Pushing to Repo") repo_manager.create_copy_commit_push(blog_path, os_friendly_title, commit_message) + + # Generate notification for Matrix + print("Generating Notification Message") + git_branch_url = f'https://git.aridgwayweb.com/armistace/blog/src/branch/{os_friendly_title}/src/content/{os_friendly_title}.md' + n8n_system_prompt = f"You are a blog creator notifiying the final editor of the final creation of blog available at {git_branch_url}" + n8n_prompt_human = f""" + Generate an informal 150 word + summary describing {ai_gen.response}. + Don't address it or use names. ONLY OUTPUT THE RESPONSE + """ + notification_message = ai_gen.generate_system_message(n8n_system_prompt, n8n_prompt_human) + secret_key = os.environ['N8N_SECRET'] + webhook_url = os.environ['N8N_WEBHOOK_URL'] + notification_string = f""" +

{tril_notes[note]['title']}

+

Summary

+

{notification_message}

+

Branch

+

{os_friendly_title}

+

Link to Branch

+ """ + + payload = { + "message": f"{notification_string}", + "timestamp": datetime.now().isoformat() + } + + webhook_client = N8NWebhookJwt(secret_key, webhook_url) + + print("Notifying") + n8n_result = webhook_client.send_webhook(payload) + + print(f"N8N response: {n8n_result['status']}") diff --git a/src/notifications/__init__.py b/src/notifications/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/notifications/n8n.py b/src/notifications/n8n.py new file mode 100644 index 0000000..d9f4b3e --- /dev/null +++ b/src/notifications/n8n.py @@ -0,0 +1,45 @@ +from datetime import datetime, timedelta +import jwt +import requests +from typing import Dict, Optional + +class N8NWebhookJwt: + def __init__(self, secret_key: str, webhook_url: str): + self.secret_key = secret_key + self.webhook_url = webhook_url + self.token_expiration = datetime.now() + timedelta(hours=1) + + def _generate_jwt_token(self, payload: Dict) -> str: + """Generate JWT token with the given payload.""" + # Include expiration time (optional) + payload["exp"] = self.token_expiration.timestamp() + encoded_jwt = jwt.encode( + payload, + self.secret_key, + algorithm="HS256", + ) + return encoded_jwt #jwt.decode(encoded_jwt, self.secret_key, algorithms=['HS256']) + + def send_webhook(self, payload: Dict) -> Dict: + """Send a webhook request with JWT authentication.""" + # Generate JWT token + token = self._generate_jwt_token(payload) + + # Set headers with JWT token + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json" + } + + # Send POST request + response = requests.post( + self.webhook_url, + json=payload, + headers=headers + ) + + # Handle response + if response.status_code == 200: + return {"status": "success", "response": response.json()} + else: + return {"status": "error", "response": response.status_code, "message": response.text}