From 13349c43c9379b56404b69b9bd6d013dc62d80d5 Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Fri, 28 Feb 2025 21:41:00 +0100 Subject: [PATCH 1/9] Changed functionality. Simplified download processes of model. --- src/ai.py | 27 +++++++++++++++------------ test.py | 8 ++++++++ 2 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 test.py diff --git a/src/ai.py b/src/ai.py index 5b3e0e5..b9d6a18 100644 --- a/src/ai.py +++ b/src/ai.py @@ -55,7 +55,6 @@ def __init__( self.SummaryCompleted = False self.SetTemplates(PromptTemplate, SummaryPromptTemplate) - self.ManageOllama() def SetTemplates(self, PromptTemplate, SummaryPromptTemplate): """ @@ -101,7 +100,7 @@ def SetRepoPath(self, Path): """ self.RepoPath = Path - @unittest.skip("Not needed for test.") + #@unittest.skip("Not needed for test.") def ManageOllama(self): """ Manage Ollama server and model availability. @@ -110,10 +109,6 @@ def ManageOllama(self): is available. If the server is not running, it attempts to start it. If the model is not available, it downloads the specified model. """ - OllamaPath = shutil.which("ollama") - if not OllamaPath: - print("Ollama executable not found. Please install Ollama.") - exit(1) # Check if Ollama server is running try: @@ -126,9 +121,13 @@ def ManageOllama(self): print("Ollama server not running. Attempting to start...") try: subprocess.Popen( - [OllamaPath, "serve"], + ["ollama", "serve"], stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL + stderr=subprocess.DEVNULL, + shell=True, + capture_output=True, + text=True, + encoding="utf-8" ) # nosec print("Ollama server started successfully.") except Exception as E: @@ -138,17 +137,21 @@ def ManageOllama(self): # Check if the specified model exists and pull if necessary try: Result = subprocess.run( - [OllamaPath, "list"], + ["ollama", "list"], + shell=True, capture_output=True, - text=True + text=True, + encoding="utf-8" ) # nosec if self.ModelName not in Result.stdout: print(f"Model '{self.ModelName}' not found. Downloading...") subprocess.run( - [OllamaPath, "pull", self.ModelName], + ["ollama", "pull", self.ModelName], + shell=True, capture_output=True, - text=True + text=True, + encoding="utf-8" ) # nosec print(f"Model '{self.ModelName}' downloaded successfully.") else: diff --git a/test.py b/test.py new file mode 100644 index 0000000..d0b499f --- /dev/null +++ b/test.py @@ -0,0 +1,8 @@ +import os +import subprocess +#os.system("ollama ps") +model= "llama3.1:8b" +result = subprocess.run(["ollama", "pull", model], capture_output=True, text=True, encoding="utf-8") # nosec + +print(result.stdout) +print(result.stderr) \ No newline at end of file From 71f9a301e6946f867388219c30f9eeb756cc2864 Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Sun, 2 Mar 2025 14:32:35 +0100 Subject: [PATCH 2/9] Updated storage and interaction with the UI and the AI --- src/ai.py | 112 +++++++++++++++++++++++++++++++--------------------- src/main.py | 31 +++++++++------ src/ui.py | 29 +++++++------- 3 files changed, 103 insertions(+), 69 deletions(-) diff --git a/src/ai.py b/src/ai.py index b9d6a18..5270276 100644 --- a/src/ai.py +++ b/src/ai.py @@ -100,17 +100,35 @@ def SetRepoPath(self, Path): """ self.RepoPath = Path - #@unittest.skip("Not needed for test.") - def ManageOllama(self): - """ - Manage Ollama server and model availability. + def CheckIfModelAvailability(self): + """Check if the specified model exists and pull if necessary.""" + try: + Result = subprocess.run( + ["ollama", "list"], + shell=True, + capture_output=True, + text=True, + encoding="utf-8" + ) # nosec - Ensures the Ollama server is running and the required model - is available. If the server is not running, it attempts to start it. - If the model is not available, it downloads the specified model. - """ + if self.ModelName not in Result.stdout: + print(f"Model '{self.ModelName}' not found. Downloading...") + subprocess.run( + ["ollama", "pull", self.ModelName], + shell=True, + capture_output=True, + text=True, + encoding="utf-8" + ) # nosec + print(f"Model '{self.ModelName}' downloaded successfully.") + else: + print(f"Model '{self.ModelName}' already exists.") + except Exception as E: + print(f"Failed to check/download model '{self.ModelName}': {E}") + exit(1) - # Check if Ollama server is running + def CheckModelStatus(self): + """Check if Ollama server is running.""" try: Response = requests.get("http://localhost:11434/health", timeout=5) if Response.status_code == 200: @@ -120,12 +138,19 @@ def ManageOllama(self): except requests.exceptions.ConnectionError: print("Ollama server not running. Attempting to start...") try: + subprocess.Popen( + ["ollama", "stop"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + shell=True, + text=True, + encoding="utf-8" + ) # nosec subprocess.Popen( ["ollama", "serve"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True, - capture_output=True, text=True, encoding="utf-8" ) # nosec @@ -134,31 +159,17 @@ def ManageOllama(self): print(f"Failed to start Ollama server: {E}") exit(1) - # Check if the specified model exists and pull if necessary - try: - Result = subprocess.run( - ["ollama", "list"], - shell=True, - capture_output=True, - text=True, - encoding="utf-8" - ) # nosec + #@unittest.skip("Not needed for test.") + def ManageOllama(self): + """ + Manage Ollama server and model availability. - if self.ModelName not in Result.stdout: - print(f"Model '{self.ModelName}' not found. Downloading...") - subprocess.run( - ["ollama", "pull", self.ModelName], - shell=True, - capture_output=True, - text=True, - encoding="utf-8" - ) # nosec - print(f"Model '{self.ModelName}' downloaded successfully.") - else: - print(f"Model '{self.ModelName}' already exists.") - except Exception as E: - print(f"Failed to check/download model '{self.ModelName}': {E}") - exit(1) + Ensures the Ollama server is running and the required model + is available. If the server is not running, it attempts to start it. + If the model is not available, it downloads the specified model. + """ + self.CheckIfModelAvailability() + self.CheckModelStatus() def LoadDocuments(self): """ @@ -203,9 +214,16 @@ def CreateVectorStore(self, Docs): Splits = TextSplitter.create_documents( [Doc["Content"] for Doc in Docs] ) + + # Falls Chroma beschädigt ist, löschen und neu erstellen + ChromaPath = "chromadb_store" + if os.path.exists(ChromaPath): + shutil.rmtree(ChromaPath) # Löscht die bestehende Datenbank + self.VectorStore = Chroma.from_documents( Splits, embedding=self.Embeddings, + persist_directory=ChromaPath # Persistenz aktivieren ) print("Vector store created successfully.") @@ -262,23 +280,29 @@ def AskQuestion(self, Query): "Please analyze the repository first." ) - if not self.VectorStore: + if self.VectorStore is None: return ( "No vector store available. " "Please analyze a repository first." ) - # Retrieve relevant documents using similarity search - RelevantDocs = self.VectorStore.similarity_search(Query, k=5) - Context = "\n\n".join(Doc.page_content for Doc in RelevantDocs) + try: + # Retrieve relevant documents using similarity search + RelevantDocs = self.VectorStore.similarity_search(Query, k=5) + if not RelevantDocs: + return "No relevant documents found for the query." - # Create prompt based on retrieved context - Prompt = self.PromptTemplate.format(Context=Context, Question=Query) - Response = self.Assistant.invoke(Prompt) + # Create prompt based on retrieved context + Context = "\n\n".join(Doc.page_content for Doc in RelevantDocs) + Prompt = self.PromptTemplate.format(Context=Context, Question=Query) + Response = self.Assistant.invoke(Prompt) - if isinstance(Response, AIMessage): - return Response.content - return str(Response) + if isinstance(Response, AIMessage): + return Response.content + return str(Response) + + except Exception as E: + return f"Error during query processing: {E}" def WriteSummary(self, Content): """ diff --git a/src/main.py b/src/main.py index 86b7d19..27a06f8 100644 --- a/src/main.py +++ b/src/main.py @@ -1,5 +1,6 @@ """This file runs the AI model and lets you interact with it.""" +import streamlit as st from ai import AIAssistant from ui import StreamlitUI @@ -15,19 +16,27 @@ def __init__( summary_prompt_template ): """Initialize the application.""" - self.ai_assistant = AIAssistant( - model_name, - creativity, - prompt_template, - summary_prompt_template - ) - self.ui = StreamlitUI(self.ai_assistant) - - def run(self): + if "AI_Assistant" not in st.session_state: + st.session_state.AI_Assistant = AIAssistant( + model_name, + creativity, + prompt_template, + summary_prompt_template + ) + st.session_state.AI_Assistant.ManageOllama() + print("Starting AI...") + + self.ai_assistant = st.session_state.AI_Assistant + self.ui = StreamlitUI() + + def Run(self): """Run the application.""" self.ui.Run() + print("Starting UI...") if __name__ == "__main__": - app = MainApp("llama3.1:8b", 1.0, "", "") - app.run() + if "MainApp" not in st.session_state: + st.session_state.MainApp = MainApp("llama3.1:8b", 1.0, "", "") + + st.session_state.MainApp.Run() diff --git a/src/ui.py b/src/ui.py index 90bc8c9..9b9a729 100644 --- a/src/ui.py +++ b/src/ui.py @@ -1,20 +1,22 @@ """This file provides the UI for the AI model.""" -from ai import AIAssistant import streamlit as st +from ai import AIAssistant class StreamlitUI: """Class for managing the Streamlit user interface.""" - def __init__(self, AIAssistant: AIAssistant): + def __init__(self): """Initialize Process.""" - self.AIAssistant = AIAssistant - self.ChatHistory = "" - self.RepoPath = "" + if "ChatHistory" not in st.session_state: + st.session_state.ChatHistory = "" + if "RepoPath" not in st.session_state: + st.session_state.RepoPath = "" def Run(self): """Run the Streamlit UI.""" + st.set_page_config("AI Assistant") st.title("AI Assistant") st.write( """Welcome to the AI Repo Summarizer!\n @@ -22,22 +24,21 @@ def Run(self): ) # Path Input - self.RepoPath = st.text_input("Set Repository Path:", self.RepoPath) + st.session_state.RepoPath = st.text_input("Set Repository Path:", st.session_state.RepoPath) if st.button("Set Path"): - if self.RepoPath: - st.write(f"Repository path set to: {self.RepoPath}") - self.AIAssistant.SetRepoPath(self.ChatHistory) + if st.session_state.RepoPath: + st.write(f"Repository path set to: {st.session_state.RepoPath}") + st.session_state.AI_Assistant.SetRepoPath(st.session_state.RepoPath) st.write("Analyzing repository...") - result = self.AIAssistant.AnalyzeRepository() + result = st.session_state.AI_Assistant.AnalyzeRepository() st.write(result) # User Input UserInput = st.text_input("Your question:") if st.button("Send Question"): if UserInput: - Response = self.AIAssistant.AskQuestion(UserInput) - self.ChatHistory += f"User: {UserInput}\nAI: {Response}\n\n" - st.write(Response) + Response = st.session_state.AI_Assistant.AskQuestion(UserInput) + st.session_state.ChatHistory += f"User: {UserInput}\nAI: {Response}\n\n" # Show Conversation History - st.text_area("Chat History", self.ChatHistory, height=300) + st.text_area("Chat History", st.session_state.ChatHistory, height=300) From 351074f6e06055d877c06baefc3fd901d105a680 Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Sun, 2 Mar 2025 14:52:57 +0100 Subject: [PATCH 3/9] Solved general syntax check --- src/ai.py | 2 +- src/main.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ai.py b/src/ai.py index 5270276..1a5910b 100644 --- a/src/ai.py +++ b/src/ai.py @@ -159,7 +159,7 @@ def CheckModelStatus(self): print(f"Failed to start Ollama server: {E}") exit(1) - #@unittest.skip("Not needed for test.") + @unittest.skip("Not needed for test.") def ManageOllama(self): """ Manage Ollama server and model availability. diff --git a/src/main.py b/src/main.py index 27a06f8..98821cf 100644 --- a/src/main.py +++ b/src/main.py @@ -26,7 +26,6 @@ def __init__( st.session_state.AI_Assistant.ManageOllama() print("Starting AI...") - self.ai_assistant = st.session_state.AI_Assistant self.ui = StreamlitUI() def Run(self): From eb1701b79244e9da28888024758154400bbab75c Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Sun, 2 Mar 2025 15:03:09 +0100 Subject: [PATCH 4/9] Solved general syntax check --- src/ai.py | 3 ++- src/ui.py | 4 ++-- test.py | 8 -------- 3 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 test.py diff --git a/src/ai.py b/src/ai.py index 1a5910b..75bd7f6 100644 --- a/src/ai.py +++ b/src/ai.py @@ -294,7 +294,8 @@ def AskQuestion(self, Query): # Create prompt based on retrieved context Context = "\n\n".join(Doc.page_content for Doc in RelevantDocs) - Prompt = self.PromptTemplate.format(Context=Context, Question=Query) + Prompt = self.PromptTemplate.format(Context=Context, + Question=Query) Response = self.Assistant.invoke(Prompt) if isinstance(Response, AIMessage): diff --git a/src/ui.py b/src/ui.py index 9b9a729..cc980cd 100644 --- a/src/ui.py +++ b/src/ui.py @@ -1,7 +1,6 @@ """This file provides the UI for the AI model.""" import streamlit as st -from ai import AIAssistant class StreamlitUI: @@ -24,7 +23,8 @@ def Run(self): ) # Path Input - st.session_state.RepoPath = st.text_input("Set Repository Path:", st.session_state.RepoPath) + st.session_state.RepoPath = st.text_input("Set Repository Path:", + st.session_state.RepoPath) if st.button("Set Path"): if st.session_state.RepoPath: st.write(f"Repository path set to: {st.session_state.RepoPath}") diff --git a/test.py b/test.py deleted file mode 100644 index d0b499f..0000000 --- a/test.py +++ /dev/null @@ -1,8 +0,0 @@ -import os -import subprocess -#os.system("ollama ps") -model= "llama3.1:8b" -result = subprocess.run(["ollama", "pull", model], capture_output=True, text=True, encoding="utf-8") # nosec - -print(result.stdout) -print(result.stderr) \ No newline at end of file From 25a5a16186f0cca8ae22e97a6715406933bfd932 Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Sun, 2 Mar 2025 15:07:59 +0100 Subject: [PATCH 5/9] Solved general syntax check --- src/ai.py | 2 +- src/ui.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ai.py b/src/ai.py index 75bd7f6..f98bf59 100644 --- a/src/ai.py +++ b/src/ai.py @@ -294,7 +294,7 @@ def AskQuestion(self, Query): # Create prompt based on retrieved context Context = "\n\n".join(Doc.page_content for Doc in RelevantDocs) - Prompt = self.PromptTemplate.format(Context=Context, + Prompt = self.PromptTemplate.format(Context=Context, Question=Query) Response = self.Assistant.invoke(Prompt) diff --git a/src/ui.py b/src/ui.py index cc980cd..d140916 100644 --- a/src/ui.py +++ b/src/ui.py @@ -23,12 +23,14 @@ def Run(self): ) # Path Input - st.session_state.RepoPath = st.text_input("Set Repository Path:", + st.session_state.RepoPath = st.text_input("Set Repository Path:", st.session_state.RepoPath) if st.button("Set Path"): if st.session_state.RepoPath: - st.write(f"Repository path set to: {st.session_state.RepoPath}") - st.session_state.AI_Assistant.SetRepoPath(st.session_state.RepoPath) + st.write(f"""Repository path set to: + {st.session_state.RepoPath}""") + st.session_state.AI_Assistant.SetRepoPath( + st.session_state.RepoPath) st.write("Analyzing repository...") result = st.session_state.AI_Assistant.AnalyzeRepository() st.write(result) From 765ae7ec9f4451d65c000a4ac2e4336f93e918f5 Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Sun, 2 Mar 2025 15:11:45 +0100 Subject: [PATCH 6/9] Solved general syntax check --- src/ui.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ui.py b/src/ui.py index d140916..0a309d1 100644 --- a/src/ui.py +++ b/src/ui.py @@ -27,7 +27,7 @@ def Run(self): st.session_state.RepoPath) if st.button("Set Path"): if st.session_state.RepoPath: - st.write(f"""Repository path set to: + st.write(f"""Repository path set to: {st.session_state.RepoPath}""") st.session_state.AI_Assistant.SetRepoPath( st.session_state.RepoPath) @@ -40,7 +40,8 @@ def Run(self): if st.button("Send Question"): if UserInput: Response = st.session_state.AI_Assistant.AskQuestion(UserInput) - st.session_state.ChatHistory += f"User: {UserInput}\nAI: {Response}\n\n" + st.session_state.ChatHistory += f"""User: + {UserInput}\nAI: {Response}\n\n""" # Show Conversation History st.text_area("Chat History", st.session_state.ChatHistory, height=300) From 16fa9ff84e959eb243bc4f8bedf973ab39920c4a Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Sun, 2 Mar 2025 15:12:35 +0100 Subject: [PATCH 7/9] Solved general syntax check --- src/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui.py b/src/ui.py index 0a309d1..dbe4624 100644 --- a/src/ui.py +++ b/src/ui.py @@ -40,7 +40,7 @@ def Run(self): if st.button("Send Question"): if UserInput: Response = st.session_state.AI_Assistant.AskQuestion(UserInput) - st.session_state.ChatHistory += f"""User: + st.session_state.ChatHistory += f"""User: {UserInput}\nAI: {Response}\n\n""" # Show Conversation History From 82fb368f208907316ad2806ddedf0a4e3e63b167 Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Sun, 2 Mar 2025 17:23:18 +0100 Subject: [PATCH 8/9] Adapted test for UI --- tests/test_ui.py | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/tests/test_ui.py b/tests/test_ui.py index 54b747c..668ee68 100644 --- a/tests/test_ui.py +++ b/tests/test_ui.py @@ -11,34 +11,17 @@ class TestUI: """Value Section.""" @pytest.mark.parametrize( - """ModelName, Creativity, Prompt, SummaryPrompt, FileTypes, - expected_AIAssistant, expected_UI""", + """ expected_UI""", [ ( - "llama3.1:8b", - 1, - "This is a test prompt.", - "This is a summary test prompt.", - [".py", ".js", ".java", ".md", ".txt"], - True, True, ), ], ) def test_UI( self, - ModelName, - Creativity, - Prompt, - SummaryPrompt, - FileTypes, - expected_AIAssistant, expected_UI, ): """Initialize the UI.""" - self.AIAssistant = AIAssistant( - ModelName, Creativity, Prompt, SummaryPrompt, FileTypes - ) - self.UI = StreamlitUI(self.AIAssistant) - assert (self.AIAssistant is not None) == expected_AIAssistant + self.UI = StreamlitUI() assert (self.UI is not None) == expected_UI From 72a7a014ef907833b9acdbb8beafe9d7cc68b931 Mon Sep 17 00:00:00 2001 From: "Tom.DevTech" Date: Sun, 2 Mar 2025 17:25:06 +0100 Subject: [PATCH 9/9] Adapted test for UI --- tests/test_ui.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_ui.py b/tests/test_ui.py index 668ee68..33770a5 100644 --- a/tests/test_ui.py +++ b/tests/test_ui.py @@ -1,7 +1,6 @@ """This file runs the tests for the UI.""" import pytest -from src.ai import AIAssistant from src.ui import StreamlitUI @@ -14,7 +13,7 @@ class TestUI: """ expected_UI""", [ ( - True, + True ), ], )