parthshr370
parth
6aee514
#main.py
import os
import logging
import time
from typing import Dict, Any, Callable, Optional
from pathlib import Path
import sys
# Add parent directory to path for OWL imports
sys.path.append('../')
from dotenv import load_dotenv
import numpy as np # Explicitly import numpy to avoid 'numpy' errors
from camel.models import ModelFactory
from camel.types import ModelPlatformType, ModelType
from camel.toolkits import (
SearchToolkit,
BrowserToolkit,
CodeExecutionToolkit
)
from camel.societies import RolePlaying
from camel.configs import ChatGPTConfig
from owl.utils import run_society # Official run_society with round_limit support
# Import prompt templates
from config.prompts import (
get_system_prompt,
get_company_research_prompt,
get_question_generator_prompt,
get_preparation_plan_prompt
)
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Load environment variables
load_dotenv()
# Create the output directory for interview preparation materials
INTERVIEW_PREP_DIR = "./interview_prep"
os.makedirs(INTERVIEW_PREP_DIR, exist_ok=True)
def run_society_with_strict_limit(society, round_limit=5, progress_callback=None):
"""Wrapper around run_society to ensure round limit is strictly enforced
This implementation hijacks the step method to force termination after a specific number of rounds.
"""
# Track rounds manually
round_count = 0
# Save original step function
original_step = society.step
# Override the step method
def limited_step(*args, **kwargs):
nonlocal round_count
round_count += 1
# Report progress if callback is provided
if progress_callback and callable(progress_callback):
progress_callback(round_count, round_limit)
# Force termination after reaching the round limit
if round_count >= round_limit:
logger.info(f"Reached round limit of {round_limit}, forcibly terminating.")
# Force a TASK_DONE in the user response to trigger termination
result = original_step(*args, **kwargs)
if len(result) >= 2 and hasattr(result[1], 'msgs') and result[1].msgs and len(result[1].msgs) > 0:
result[1].msgs[0].content += "\n\nTASK_DONE"
result[1].terminated = True
return result
return original_step(*args, **kwargs)
# Replace the step method
society.step = limited_step
try:
# Run the conversation with the standard run_society function
answer, chat_history, token_count = run_society(society, round_limit=round_limit)
# Add a note about the conversation being truncated
if len(chat_history) > 0 and "truncated_note" not in chat_history[-1]:
chat_history[-1]["truncated_note"] = True
if "assistant" in chat_history[-1]:
chat_history[-1]["assistant"] += "\n\n[Note: This conversation was limited to maintain response quality.]"
return answer, chat_history, token_count
finally:
# Restore the original step method
society.step = original_step
def construct_interview_assistant(
job_description: str,
company_name: str,
detailed: bool = True,
limited_searches: bool = True
) -> RolePlaying:
"""
Construct a specialized interview preparation assistant using OWL.
"""
# Select model based on environment variables
if os.environ.get("OPENROUTER_API_KEY"):
logger.info("Using OpenRouter with Gemini model")
model = ModelFactory.create(
model_platform=ModelPlatformType.OPENAI_COMPATIBLE_MODEL,
api_key=os.environ.get("OPENROUTER_API_KEY"),
model_type="google/gemini-2.0-flash-001",
url="https://openrouter.ai/api/v1",
model_config_dict={
"temperature": 0.6,
"max_tokens": 4000, # Reduced from 10000 to avoid exceeding limits
# Do NOT use context_length - it's not a valid API parameter
}
)
elif os.environ.get("OPENAI_API_KEY"):
logger.info("Using OpenAI model (GPT-4)")
config = ChatGPTConfig(
temperature=0.3,
max_tokens=4000
)
model = ModelFactory.create(
model_platform=ModelPlatformType.OPENAI,
model_type=ModelType.GPT_4O,
model_config_dict=config.as_dict()
)
else:
raise ValueError("Either OPENAI_API_KEY or OPENROUTER_API_KEY must be set")
# Configure toolkits - Remove FileWriteToolkit as requested
essential_tools = [
SearchToolkit().search_duckduckgo,
SearchToolkit().search_wiki,
# Removed the FileWriteToolkit as requested
]
if os.environ.get("GOOGLE_API_KEY") and os.environ.get("SEARCH_ENGINE_ID"):
essential_tools.append(SearchToolkit().search_google)
if detailed:
tools = [
*essential_tools,
*BrowserToolkit(
headless=True,
web_agent_model=model,
planning_agent_model=model,
).get_tools(),
*CodeExecutionToolkit(sandbox="subprocess", verbose=True).get_tools(),
]
logger.info("Using full toolset for comprehensive results (detailed=True)")
else:
tools = essential_tools
logger.info("Using essential toolset for faster results (detailed=False)")
user_agent_kwargs = {"model": model}
assistant_agent_kwargs = {"model": model, "tools": tools}
# Build enhanced prompt asking for full, detailed output
base_prompt = get_system_prompt()
enhanced_prompt = f"""{base_prompt}
Task: Help me prepare for an interview at {company_name} for the position of {job_description}.
Requirements:
1. Provide a highly detailed, extremely comprehensive response (aim for at least 2000+ words).
2. Structure the output with clear sections, actionable insights, examples, and code where relevant.
3. Tailor the content specifically to {company_name} and the {job_description} role.
4. Do NOT truncate or summarize—provide the full explanation directly.
"""
task_kwargs = {
"task_prompt": enhanced_prompt,
"with_task_specify": False,
}
society = RolePlaying(
**task_kwargs,
user_role_name="job_seeker",
user_agent_kwargs=user_agent_kwargs,
assistant_role_name="interview_coach",
assistant_agent_kwargs=assistant_agent_kwargs,
)
# Try to set memory parameters to reduce context size
try:
# Try to access the context creator if it exists
if hasattr(society, '_context_creator') and hasattr(society._context_creator, 'max_tokens'):
society._context_creator.max_tokens = 4000
# Alternative approach through kwargs if available
elif hasattr(society, '_context_creator_kwargs'):
society._context_creator_kwargs = {"max_tokens": 4000}
except AttributeError:
logger.warning("Could not directly set memory parameters. Using default values.")
return society
def research_company(
company_name: str,
detailed: bool = True,
limited_searches: bool = True,
progress_callback: Optional[Callable] = None
) -> Dict[str, Any]:
start_time = time.time()
logging.info(f"Beginning company research for {company_name}")
base_prompt = get_company_research_prompt(company_name)
enhanced_prompt = f"""{base_prompt}
Please provide the most detailed, in-depth report possible, with no summarization or truncation.
Your response must include extensive coverage, code samples (if relevant), and be at least 2000 words long.
"""
society = construct_interview_assistant("", company_name, detailed=detailed, limited_searches=limited_searches)
society.task_prompt = enhanced_prompt
# Use our strict wrapper function to enforce limit at exactly 5 rounds
answer, chat_history, token_count = run_society_with_strict_limit(
society,
round_limit=5,
progress_callback=progress_callback
)
duration = time.time() - start_time
logging.info(f"Completed company research for {company_name} in {duration:.2f} seconds")
# Find any files that may have been generated
generated_files = [str(file) for file in Path(INTERVIEW_PREP_DIR).glob("*") if file.is_file()]
return {
"answer": answer,
"chat_history": chat_history,
"token_count": token_count,
"generated_files": generated_files,
"duration_seconds": duration
}
def generate_interview_questions(
job_role: str,
company_name: str,
detailed: bool = True,
limited_searches: bool = True,
progress_callback: Optional[Callable] = None
) -> Dict[str, Any]:
start_time = time.time()
logging.info(f"Starting question generation for {job_role} at {company_name} (detailed={detailed})")
try:
# Ensure numpy is available to prevent 'numpy' errors
import numpy as np
base_prompt = get_question_generator_prompt(job_role, company_name)
enhanced_prompt = f"""{base_prompt}
Please provide at least 50 highly specific questions with code examples, multiple solution approaches,
and extremely thorough explanations. Aim for 3000+ words, with no truncation or summarization.
"""
society = construct_interview_assistant(job_role, company_name, detailed=detailed, limited_searches=limited_searches)
society.task_prompt = enhanced_prompt
# Use our wrapper function to strictly enforce a limit of 5 rounds
answer, chat_history, token_count = run_society_with_strict_limit(
society,
round_limit=5,
progress_callback=progress_callback
)
duration = time.time() - start_time
logging.info(f"Completed question generation for {job_role} at {company_name} in {duration:.2f} seconds")
# Find any files that were generated
generated_files = [str(file) for file in Path(INTERVIEW_PREP_DIR).glob("*") if file.is_file()]
return {
"answer": answer,
"chat_history": chat_history,
"token_count": token_count,
"generated_files": generated_files,
"duration_seconds": duration
}
except Exception as e:
logging.error(f"Error in question generation: {str(e)}", exc_info=True)
raise
def create_interview_prep_plan(
job_role: str,
company_name: str,
detailed: bool = True,
limited_searches: bool = True,
progress_callback: Optional[Callable] = None
) -> Dict[str, Any]:
start_time = time.time()
logging.info(f"Starting preparation plan creation for {job_role} at {company_name} (detailed={detailed})")
try:
base_prompt = get_preparation_plan_prompt(job_role, company_name)
enhanced_prompt = f"""{base_prompt}
Please provide a highly thorough, step-by-step preparation plan with multiple days of tasks,
detailed technical reviews, code examples where applicable, and at least 2000 words total.
No truncation or summaries—include the full content.
"""
society = construct_interview_assistant(job_role, company_name, detailed=detailed, limited_searches=limited_searches)
society.task_prompt = enhanced_prompt
# Use our wrapper function with strict limit of 5 rounds
answer, chat_history, token_count = run_society_with_strict_limit(
society,
round_limit=5,
progress_callback=progress_callback
)
duration = time.time() - start_time
logging.info(f"Completed preparation plan creation in {duration:.2f} seconds")
# Find any files that were generated
generated_files = [str(file) for file in Path(INTERVIEW_PREP_DIR).glob("*") if file.is_file()]
return {
"answer": answer,
"chat_history": chat_history,
"token_count": token_count,
"generated_files": generated_files,
"duration_seconds": duration
}
except Exception as e:
logging.error(f"Error in preparation plan creation: {str(e)}", exc_info=True)
raise
if __name__ == "__main__":
job_role = "Machine Learning Engineer"
company_name = "Google"
result = create_interview_prep_plan(job_role, company_name, detailed=True)
print(f"Answer: {result['answer']}")
print(f"Generated files: {result['generated_files']}")
print(f"Execution time: {result['duration_seconds']:.2f} seconds")
print(f"Conversation rounds: {len(result['chat_history'])}")