From de341e7d727b1fdc98f43556080ec879da899d9f Mon Sep 17 00:00:00 2001 From: Ye Min Naing Date: Mon, 19 May 2025 14:39:05 +0700 Subject: [PATCH 1/2] refactor: replace call_llm import and remove deprecated file, add new call_llm_openai implementation --- nodes.py | 2 +- utils/{call_llm.py => call_llm_gemini.py} | 1 + utils/call_llm_openai.py | 92 +++++++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) rename utils/{call_llm.py => call_llm_gemini.py} (99%) create mode 100644 utils/call_llm_openai.py diff --git a/nodes.py b/nodes.py index 0e3fa58..b8667d5 100644 --- a/nodes.py +++ b/nodes.py @@ -3,7 +3,7 @@ import yaml from pocketflow import Node, BatchNode from utils.crawl_github_files import crawl_github_files -from utils.call_llm import call_llm +from utils.call_llm_openai import call_llm from utils.crawl_local_files import crawl_local_files diff --git a/utils/call_llm.py b/utils/call_llm_gemini.py similarity index 99% rename from utils/call_llm.py rename to utils/call_llm_gemini.py index 81ef2a2..bd72bd1 100644 --- a/utils/call_llm.py +++ b/utils/call_llm_gemini.py @@ -233,3 +233,4 @@ def call_llm(prompt: str, use_cache: bool = True) -> str: print("Making call...") response1 = call_llm(test_prompt, use_cache=False) print(f"Response: {response1}") + \ No newline at end of file diff --git a/utils/call_llm_openai.py b/utils/call_llm_openai.py new file mode 100644 index 0000000..5d70942 --- /dev/null +++ b/utils/call_llm_openai.py @@ -0,0 +1,92 @@ +import os +import logging +import json +from datetime import datetime +from openai import OpenAI + +# Configure logging +log_directory = os.getenv("LOG_DIR", "logs") +os.makedirs(log_directory, exist_ok=True) +log_file = os.path.join( + log_directory, f"llm_calls_{datetime.now().strftime('%Y%m%d')}.log" +) + +# Set up logger +logger = logging.getLogger("llm_logger") +logger.setLevel(logging.INFO) +logger.propagate = False # Prevent propagation to root logger +file_handler = logging.FileHandler(log_file, encoding='utf-8') +file_handler.setFormatter( + logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") +) +logger.addHandler(file_handler) + +# Simple cache configuration +cache_file = "llm_cache.json" + +def call_llm(prompt: str, use_cache: bool = True) -> str: + # Log the prompt + logger.info(f"PROMPT: {prompt}") + + # Check cache if enabled + if use_cache: + # Load cache from disk + cache = {} + if os.path.exists(cache_file): + try: + with open(cache_file, "r", encoding="utf-8") as f: + cache = json.load(f) + except Exception as e: + logger.warning(f"Failed to load cache: {e}") + + # Return from cache if exists + if prompt in cache: + logger.info(f"CACHED RESPONSE: {cache[prompt]}") + return cache[prompt] + + # Initialize OpenAI client + client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) + + try: + response = client.chat.completions.create( + model="o1", # Update to latest model + messages=[{ + "role": "user", + "content": prompt + }], + max_tokens=1000, # Adjust as needed + temperature=0.7 # Add common parameters + ) + + response_text = response.choices[0].message.content + + # Log the response + logger.info(f"RESPONSE: {response_text}") + + # Update cache if enabled + if use_cache: + cache[prompt] = response_text + try: + with open(cache_file, "w", encoding="utf-8") as f: + json.dump(cache, f) + except Exception as e: + logger.error(f"Failed to save cache: {e}") + + return response_text + + except Exception as e: + logger.error(f"API call failed: {e}") + raise + +if __name__ == "__main__": + test_prompt = "Hello, how are you?" + + # First call - should hit the API + print("Making call...") + response1 = call_llm(test_prompt, use_cache=False) + print(f"Response: {response1}") + + # Second call - should use cache if enabled + print("Making cached call...") + response2 = call_llm(test_prompt) + print(f"Cached Response: {response2}") \ No newline at end of file From 68bd10871e227d63811d0c94b932936fffc82171 Mon Sep 17 00:00:00 2001 From: Ye Min Naing Date: Mon, 19 May 2025 15:20:09 +0700 Subject: [PATCH 2/2] refactor: encapsulate logger setup in a function and improve cache handling --- utils/call_llm_openai.py | 140 ++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 68 deletions(-) diff --git a/utils/call_llm_openai.py b/utils/call_llm_openai.py index 5d70942..356d809 100644 --- a/utils/call_llm_openai.py +++ b/utils/call_llm_openai.py @@ -5,88 +5,92 @@ from openai import OpenAI # Configure logging -log_directory = os.getenv("LOG_DIR", "logs") -os.makedirs(log_directory, exist_ok=True) -log_file = os.path.join( - log_directory, f"llm_calls_{datetime.now().strftime('%Y%m%d')}.log" -) +def setup_logger(): + log_directory = os.getenv("LOG_DIR", "logs") + os.makedirs(log_directory, exist_ok=True) + log_file = os.path.join( + log_directory, + f"llm_calls_{datetime.now().strftime('%Y%m%d')}.log" + ) -# Set up logger -logger = logging.getLogger("llm_logger") -logger.setLevel(logging.INFO) -logger.propagate = False # Prevent propagation to root logger -file_handler = logging.FileHandler(log_file, encoding='utf-8') -file_handler.setFormatter( - logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") -) -logger.addHandler(file_handler) + logger = logging.getLogger("llm_logger") + logger.setLevel(logging.INFO) + logger.propagate = False # Don't propagate to root logger -# Simple cache configuration -cache_file = "llm_cache.json" + file_handler = logging.FileHandler(log_file, encoding="utf-8") + file_handler.setFormatter( + logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") + ) + logger.addHandler(file_handler) + return logger +logger = setup_logger() +cache_file = os.getenv("LLM_CACHE_FILE", "llm_cache.json") + +# Wrapper for calling OpenAI o-series models with optional caching def call_llm(prompt: str, use_cache: bool = True) -> str: - # Log the prompt - logger.info(f"PROMPT: {prompt}") + """ + Send a prompt to the OpenAI thinking model (default: o4-mini) with chain-of-thought enabled. + Caches responses in llm_cache.json by default. - # Check cache if enabled - if use_cache: - # Load cache from disk - cache = {} - if os.path.exists(cache_file): - try: - with open(cache_file, "r", encoding="utf-8") as f: - cache = json.load(f) - except Exception as e: - logger.warning(f"Failed to load cache: {e}") + Args: + prompt (str): The input prompt for the LLM. + use_cache (bool): Whether to read/write from cache. - # Return from cache if exists - if prompt in cache: - logger.info(f"CACHED RESPONSE: {cache[prompt]}") - return cache[prompt] + Returns: + str: The model's response text. + """ + logger.info(f"PROMPT: {prompt}") + + # Load or check cache + if use_cache and os.path.exists(cache_file): + try: + with open(cache_file, "r", encoding="utf-8") as f: + cache = json.load(f) + if prompt in cache: + logger.info("CACHE HIT") + logger.info(f"RESPONSE: {cache[prompt]}") + return cache[prompt] + except Exception: + logger.warning("Failed to load cache; continuing without cache") # Initialize OpenAI client - client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) + client = OpenAI(api_key=os.getenv("OPENAI_API_KEY", "")) + model_name = os.getenv("OPENAI_MODEL", "o4-mini") - try: - response = client.chat.completions.create( - model="o1", # Update to latest model - messages=[{ - "role": "user", - "content": prompt - }], - max_tokens=1000, # Adjust as needed - temperature=0.7 # Add common parameters - ) - - response_text = response.choices[0].message.content + # Send chat completion request + response = client.chat.completions.create( + model=model_name, + messages=[{"role": "user", "content": prompt}], + max_completion_tokens=4000, + reasoning_effort="medium", + store=False + ) + response_text = response.choices[0].message.content - # Log the response - logger.info(f"RESPONSE: {response_text}") + logger.info(f"RESPONSE: {response_text}") - # Update cache if enabled - if use_cache: - cache[prompt] = response_text - try: - with open(cache_file, "w", encoding="utf-8") as f: - json.dump(cache, f) - except Exception as e: - logger.error(f"Failed to save cache: {e}") + # Write to cache + if use_cache: + try: + cache = {} + if os.path.exists(cache_file): + with open(cache_file, "r", encoding="utf-8") as f: + cache = json.load(f) + except Exception: + cache = {} - return response_text + cache[prompt] = response_text + try: + with open(cache_file, "w", encoding="utf-8") as f: + json.dump(cache, f, ensure_ascii=False, indent=2) + except Exception as e: + logger.error(f"Failed to save cache: {e}") - except Exception as e: - logger.error(f"API call failed: {e}") - raise + return response_text if __name__ == "__main__": test_prompt = "Hello, how are you?" - - # First call - should hit the API print("Making call...") - response1 = call_llm(test_prompt, use_cache=False) - print(f"Response: {response1}") - - # Second call - should use cache if enabled - print("Making cached call...") - response2 = call_llm(test_prompt) - print(f"Cached Response: {response2}") \ No newline at end of file + response = call_llm(test_prompt, use_cache=False) + print(f"Response: {response}")