diff --git a/.gitignore b/.gitignore index 5152f84..1248f07 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env __pycache__ .venv +.aider* diff --git a/docker-compose.yml b/docker-compose.yml index fb9f900..0e61a87 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,8 @@ services: context: . dockerfile: Dockerfile container_name: blog_creator - env_file: + env_file: - .env + volumes: + - ./generated_files/:/blog_creator/generated_files diff --git a/generated_files/creating_an_ollama_blog_writer.md b/generated_files/creating_an_ollama_blog_writer.md new file mode 100644 index 0000000..f85cb95 --- /dev/null +++ b/generated_files/creating_an_ollama_blog_writer.md @@ -0,0 +1,109 @@ +Creating an Ollama Blog Writer: Your Ultimate DevOps Guide + +As software developers and DevOps enthusiasts, we all know the struggles of creating blog content. Whether it's finding inspiration or dealing with writer's block, the process can be daunting. But fear not, dear engineers! In this blog, we're going to share our secret weapon: Ollama, the AI writing assistant that will help you create high-quality content effortlessly. + +Step 1: Communicate with your local Ollama instance +First, make sure you have a local Ollama instance running on your machine. If you don't already have one, we recommend checking out their official documentation to get started. Once it's up and running, create a Python script that can communicate with it. Here's an example: + +```python +import requests +from ollama_client import OllamaClient + +# Set your API key here +api_key = "your_api_key" + +# Connect to the local Ollamma instance +ollama_url = "http://localhost:5000" +ollama_client = OllamaClient(ollama_url, api_key) + +# Prompt Ollama to generate some content for us +prompt = "Write a 1000-word blog post about DevOps best practices." +response = ollama_client.create(text=prompt) +content = response["generated"] +print(content) +``` + +Step 2: Connect to Trilum for structured notes as prompts +Trilum is a powerful personal knowledge base and note-taking app that allows you to structure your notes in a hierarchical and interconnected way. It also has a Python API, which we can use to connect to it and fetch our notes as prompts for Ollama. Here's an example: + +```python +import trilium_py +from trilium import nodes +from trilium.api import Client +from trilium.exceptions import InvalidApiKeyException, UnknownNodeTypeException + +# Set your API key and Trilium URL here +api_key = "your_api_key" +trilium_url = "https://example.com" + +# Connect to the local Trilium instance +client = Client(trilium_url, api_key) + +# Fetch a specific node as our prompt +node_id = "some_node_id" +try: + node = client.get_node(node_id).data + # Convert the Trilium Node to plain text for Ollama + prompt = nodes.TextNode(node) +except (InvalidApiKeyException, UnknownNodeTypeException): + # Handle API key or node type errors gracefully + pass + +# Call Ollama with our prompt +prompt_text = prompt.content +ollama_url = "http://localhost:5000" +ollama_client = OllamaClient(ollama_url, api_key) +response = ollama_client.create(text=prompt_text) +content = response["generated"] +print(content) +``` + +Step 3: Create a blog entry in your Git repo and send a notification to Matrix +Once you have some content generated by Ollama, it's time to create the actual blog post. For this, we recommend using Git for version control and a CI/CD pipeline that automatically deploys your blog to your website. Here's an example of how you might do this: + +```python +import os +from git import Git +from git.repo import BaseRepository +from git.exc import InvalidGitRepositoryError +from git.remote import RemoteAction + +# Set the path to your blog repo here +blog_repo = "/path/to/your/blog/repo" + +# Checkout a new branch and create a new file for our blog post +branch_name = "new-post" +try: + repo = Git(blog_repo) + repo.checkout("-b", branch_name, "origin/main") + with open("my-blog-post.md", "w") as f: + f.write(content) +except InvalidGitRepositoryError: + # Handle repository errors gracefully + pass + +# Add and commit the changes to Git +repo.add("my-blog-post.md") +repo.commit("-m", "Added new blog post about DevOps best practices.") + +# Push the changes to Git and create a PR +repo.remote().push("refs/heads/{0}:refs/for/main".format(branch_name), "--set-upstream") +base_branch = "origin/main" +target_branch = "main" +pr_title = "DevOps best practices" +try: + repo.create_head("{0}-{1}", base=base_branch, message="{}".format(pr_title)) +except RemoteAction.GitExitStatus as e: + # Handle Git exit status errors gracefully + pass + +# Send a notification to Matrix about the new PR +matrix_server = "https://example.com" +room_id = "#blog-updates" +content = "[Blog] {} - Review please!".format(pr_title) +requests.get("{0}/api/v3/client?token={1}&sid={2}".format(matrix_server, your_matrix_token, room_id)) +requests.post("{0}/api/v3/rooms/{1}/send?text={2}&formatted=false".format(matrix_server, room_id, content)) +``` + +And that's it! With these steps, you can create high-quality blog posts effortlessly using Ollama and Trilum. Happy blogging! + diff --git a/ollama_generator.py b/ollama_generator.py deleted file mode 100644 index 8bccd5c..0000000 --- a/ollama_generator.py +++ /dev/null @@ -1,28 +0,0 @@ -import os -import requests - -class OllamaGenerator: - def __init__(self, title: str, content: str): - self.title = title - self.content = content - self.ollama_url = f"{os.getenv('OLLAMA_PROTOCOL')}://{os.getenv('OLLAMA_HOST')}:{os.getenv('OLLAMA_PORT')}/api/generate" - - def generate_markdown(self) -> str: - data = { - "prompt": f"Title: {self.title}\n\nContent:\n{self.content}", - "max_tokens": 1000, - "temperature": 0.7, - "top_p": 0.9, - "presence_penalty": 0, - "frequency_penalty": 0 - } - - response = requests.post(self.ollama_url, json=data) - if response.status_code == 200: - return response.json()["choices"][0]["text"] - else: - raise Exception(f"Failed to generate markdown: {response.text}") - - def save_to_file(self, filename: str) -> None: - with open(filename, "w") as f: - f.write(self.generate_markdown()) diff --git a/requirements.txt b/requirements.txt index 626ee13..7ae22b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ ollama trilium-py +gitpython +PyGithub diff --git a/src/ai_generators/ollama_md_generator.py b/src/ai_generators/ollama_md_generator.py index 1717ca6..1339b2b 100644 --- a/src/ai_generators/ollama_md_generator.py +++ b/src/ai_generators/ollama_md_generator.py @@ -4,21 +4,24 @@ from ollama import Client class OllamaGenerator: - def __init__(self, title: str, content: str): + def __init__(self, title: str, content: str, model: str): self.title = title self.content = content - self.ollama_client = Client(host=f""" - {os.getenv('OLLAMA_PROTOCOL')}://{os.getenv('OLLAMA_HOST')}:{os.getenv('OLLAMA_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 = model def generate_markdown(self) -> str: prompt = f""" - Generate a 1000 word blog as a markdown document. + You are a Software Developer and DevOps expert + writing a 1000 word blog for other engineers. + You like to use very small and minimal code examples and prefer to talk + in a light comedic tone + As this person write this blog as a markdown document. The title for the blog is {self.title}. Do not output the title in the markdown. - The content for the blog is: + The basis for the content of the blog is: {self.content} Only output markdown DO NOT GENERATE AN EXPLANATION """ @@ -30,6 +33,7 @@ class OllamaGenerator: 'content': f'{prompt}', }, ]) + return self.response['message']['content'] except Exception as e: raise Exception(f"Failed to generate markdown: {e}") diff --git a/src/main.py b/src/main.py index bb345a2..96cf115 100644 --- a/src/main.py +++ b/src/main.py @@ -6,6 +6,7 @@ tril = tn.TrilumNotes() tril.get_new_notes() tril_notes = tril.get_notes_content() + def convert_to_lowercase_with_underscores(string): return string.lower().replace(" ", "_") @@ -14,10 +15,8 @@ for note in tril_notes: print(tril_notes[note]['title']) print(tril_notes[note]['content']) print("Generating Document") - ai_gen = omg.OllamaGenerator(tril_notes[note]['title'], - tril_notes[note]['content']) + ai_gen = omg.OllamaGenerator(tril_notes[note]['title'], + tril_notes[note]['content'], + "zephyr") os_friendly_title = convert_to_lowercase_with_underscores(tril_notes[note]['title']) - omg.save_to_file(f"{os_friendly_title}.md") - - - + ai_gen.save_to_file(f"/blog_creator/generated_files/{os_friendly_title}.md") diff --git a/src/repo_management/__init__.py b/src/repo_management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/push_markdown.py b/src/repo_management/push_markdown.py similarity index 100% rename from push_markdown.py rename to src/repo_management/push_markdown.py diff --git a/src/repo_management/repo_manager.py b/src/repo_management/repo_manager.py new file mode 100644 index 0000000..a86920c --- /dev/null +++ b/src/repo_management/repo_manager.py @@ -0,0 +1,35 @@ +import os +from git import Git +from git.repo import BaseRepository +from git.exc import InvalidGitRepositoryError +from git.remote import RemoteAction + +# Set the path to your blog repo here +blog_repo = "/path/to/your/blog/repo" + +# Checkout a new branch and create a new file for our blog post +branch_name = "new-post" +try: + repo = Git(blog_repo) + repo.checkout("-b", branch_name, "origin/main") + with open("my-blog-post.md", "w") as f: + f.write(content) +except InvalidGitRepositoryError: + # Handle repository errors gracefully + pass + +# Add and commit the changes to Git +repo.add("my-blog-post.md") +repo.commit("-m", "Added new blog post about DevOps best practices.") + +# Push the changes to Git and create a PR +repo.remote().push("refs/heads/{0}:refs/for/main".format(branch_name), "--set-upstream") +base_branch = "origin/main" +target_branch = "main" +pr_title = "DevOps best practices" +try: + repo.create_head("{0}-{1}", base=base_branch, message="{}".format(pr_title)) +except RemoteAction.GitExitStatus as e: + # Handle Git exit status errors gracefully + pass +