Files

243 lines
7.0 KiB
Python
Raw Permalink Normal View History

2025-04-01 22:29:59 -04:00
from codeExecution import UserEnvironment, orchestrate_code
from queries import (
2025-04-02 21:56:41 -04:00
rag_query,
2025-04-01 22:29:59 -04:00
classify_task,
2025-04-02 21:56:41 -04:00
MODEL_NAMES,
show_thinking
2025-04-01 22:29:59 -04:00
)
import debug as debugMod
from search import perform_web_search
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
import os
import argparse
import re
import ollama
2025-04-02 21:56:41 -04:00
import subprocess
2025-04-01 22:29:59 -04:00
from config import Config
import conversation_store
conversation_store.initialize_db()
ollama.Client(host='http://ollama:11434')
# Just in case
for complexity, model_name in MODEL_NAMES.items():
print(f"Pulling {complexity} model ({model_name})...")
# Stream the pull process and print progress
for progress in ollama.pull(model=model_name, stream=True):
if "status" in progress:
print(f" {progress['status']}", end="\r") # Overwrite the same line
if "completed" in progress and "total" in progress:
# Calculate and print download percentage
percent = (progress["completed"] / progress["total"]) * 100
print(f" Downloading: {percent:.1f}% complete", end="\r")
print("\nDone!") # Newline after each model is pulled
def load_and_chunk_file(file_path):
debugMod.log(f"Loading and chunking file: {file_path}")
if not os.path.exists(file_path):
raise FileNotFoundError(f"File {file_path} not found")
with open(file_path, "r") as f:
text = f.read()
splitter = RecursiveCharacterTextSplitter(
chunk_size=Config.CHUNK_SIZE, chunk_overlap=Config.CHUNK_OVERLAP)
chunks = splitter.split_text(text)
debugMod.log(f"File chunked into {len(chunks)} chunks")
return chunks
def create_vector_store(chunks):
debugMod.log("Creating vector store")
if not chunks:
debugMod.log("No chunks provided, returning None")
return None
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
vector_store = Chroma.from_texts(
2025-04-03 17:07:37 -04:00
chunks,
embeddings,
persist_directory=Config.chroma_path()
)
2025-04-01 22:29:59 -04:00
debugMod.log("Vector store created")
return vector_store
def orchestrate(query, vector_store=None, comm_outp=print, comm_inp=input):
2025-04-02 21:56:41 -04:00
debugMod.log(f"Orchestrating query: {query}")
aggregated_web_context = ""
local_context = ""
user_context = ""
response_context = ""
links = []
# Classify task once at start
show_thinking("[Analyzing query type...]")
task_type = classify_task(query)
show_thinking(f"[Task classified as: {task_type}]")
# Early exit for simple tasks
if task_type == "simple":
debugMod.log("Direct response for simple task")
return [rag_query(query, task_type=task_type), []]
# Initialize context for medium/complex tasks
if vector_store:
docs = vector_store.similarity_search(query, k=3)
local_context = "\n".join(
[d.page_content for d in docs]) if docs else ""
debugMod.log(f"Local context: {local_context}")
iteration = 0
status = "continue"
while iteration < Config.MAX_ORCHESTRATION_ITERATIONS and status != "final":
debugMod.log(f"--- Iteration {iteration} [Status: {status}] ---")
response = ""
if status == "continue":
# Include previous responses in reflection
reflection_prompt = f"""Determine the next action needed to answer: {query}
Available actions:
1. web_search - Needs web information
2. user_input - Requires clarification
3. final_response - Ready to answer
Context:
- Web: {aggregated_web_context}
- Local: {local_context}
- User: {user_context}
- Previous Responses: {response_context}
Return ONLY: web_search/user_input/final_response"""
show_thinking('[choosing the appropriate action]')
status = rag_query(
reflection_prompt, task_type=task_type, silent=True).strip().lower()
debugMod.log(f"Action determined: {status}")
if status == "web_search":
show_thinking("[Searching web for information...]")
search_prompt = f"""Generate search query considering: {query}
Previous responses: {response_context}
Return ONLY search terms"""
search_terms = rag_query(
search_prompt, task_type=task_type, silent=True).strip('"')
debugMod.log(f"Searching web for: {search_terms}")
web_results, new_links = perform_web_search(search_terms)
links.extend(new_links)
if web_results:
aggregated_web_context += f"\nWeb: {web_results}"
debugMod.log(f"Updated web context")
elif status == "user_input":
comm_outp("\n[System] Additional info needed:")
user_input = comm_inp("Please clarify: ")
user_context += f"\nUser input: {user_input}"
debugMod.log(f"Received user input")
status = "continue"
elif status == "final_response":
break
else:
debugMod.log(f"Unknown status: {status}")
status = "final_response"
# Generate and store response
if status != "final_response":
response = rag_query(
query,
task_type=task_type,
web_context=aggregated_web_context,
local_context=local_context,
user_context=user_context,
response_context=response_context # Pass previous responses
)
response_context += f"\nIteration {iteration} response: {response}"
debugMod.log(f"Iteration {iteration} response stored")
iteration += 1
# Generate final response with full context
final_response = rag_query(
f"Final answer considering: {query}",
task_type=task_type,
web_context=aggregated_web_context,
local_context=local_context,
user_context=user_context,
response_context=response_context
)
debugMod.log("Orchestration completed")
return [final_response, links]
2025-04-01 22:29:59 -04:00
2025-04-03 17:07:37 -04:00
if __name__ == "__main__":
2025-04-01 22:29:59 -04:00
debugMod.moveDebugLog()
parser = argparse.ArgumentParser()
parser.add_argument('--file', type=str, default="",
2025-04-03 17:07:37 -04:00
help='Path to data file for analysis')
2025-04-01 22:29:59 -04:00
parser.add_argument('--cli', type=str, default="false",
2025-04-03 17:07:37 -04:00
help="whether to use the CLI for input or run the API")
2025-04-01 22:29:59 -04:00
args = parser.parse_args()
vector_store = None
chunks = []
if args.file:
try:
debugMod.log(f"Loading file: {args.file}")
chunks = load_and_chunk_file(args.file)
vector_store = create_vector_store(chunks)
except Exception as e:
debugMod.log(f"Error loading file: {str(e)}")
chunks = []
user_env = UserEnvironment("ION606")
# if args.cli:
while True:
query = input("\nEnter your query (type 'exit' to quit): ")
if query.lower() == 'exit':
break
[response, links] = orchestrate(query, vector_store)
if len(links) > 0:
print(f"links: {", ".join(links)}")
# Save conversation to SQLite
conversation_store.save_conversation(query, response, links)
# code
code_blocks = re.findall(Config.code_block_regex(), response, re.DOTALL)
if code_blocks:
2025-04-02 21:56:41 -04:00
show_thinking('[running code...]')
2025-04-01 22:29:59 -04:00
orchestrate_code(orchestrate, vector_store, chunks,
2025-04-03 17:07:37 -04:00
user_env, code_blocks, query, response, links)
2025-04-02 21:56:41 -04:00
# clean up
try:
# For Linux/macOS
subprocess.run(["pkill", "-f", "ollama run"], check=False)
# For Windows
subprocess.run(["taskkill", "/IM", "ollama.exe", "/F"], check=False)
debugMod.log("Terminated Ollama background processes")
except Exception as e:
debugMod.log(f"Cleanup error: {str(e)}")