IdeaLens_App / app.py
NitishBorthakur's picture
Upload 10 files
4705b54 verified
Raw
History Blame Contribute Delete
34.2 kB
import os
import gradio as gr
import sys
from sentence_transformers import SentenceTransformer
import torch
import torch.nn.functional as F
from functools import lru_cache
# Debug print: Check current working directory
import os
import subprocess
import sys
def install_private_repo():
github_agent_token = os.getenv('GITHUB_AGENT_TOKEN')
if not github_agent_token:
print("Error: GITHUB_AGENT_TOKEN environment variable is not set.")
return False
repo_url = f"git+https://{github_agent_token}@github.com/punekichikki/ideaLensAgent.git"
try:
#print(f"Attempting to install from private repo: {repo_url.replace(github_agent_token, '*******')}")
# Install with verbose output
result = subprocess.run(
[sys.executable, "-m", "pip", "install", "-v", repo_url],
capture_output=True,
text=True
)
if result.returncode != 0:
print(f"Installation failed with error code: {result.returncode}")
print(f"stdout: {result.stdout}")
print(f"stderr: {result.stderr}")
return False
#print("Installation output:")
#print(result.stdout)
# Check installed packages
print("\nInstalled packages:")
pip_list = subprocess.run(
[sys.executable, "-m", "pip", "list"],
capture_output=True,
text=True
)
#print(pip_list.stdout)
# Check Python path
#print("\nPython path:")
#print(sys.path)
# Try to find the package location
find_package = subprocess.run(
[sys.executable, "-c", "import idealens_agents; print(idealens_agents.__file__)"],
capture_output=True,
text=True
)
#print("\nPackage location attempt:")
#print("stdout:", find_package.stdout)
#print("stderr:", find_package.stderr)
return True
except Exception as e:
print(f"Error: An unexpected error occurred: {str(e)}")
traceback.print_exc()
return False
# Add debug information before installation
#print("Current environment variables:", {k: v for k, v in os.environ.items() if 'TOKEN' in k})
#print("Python executable:", sys.executable)
#print("Python version:", sys.version)
#print("Current working directory:", os.getcwd())
#print("Directory contents:", os.listdir())
# Install private repo
install_success = install_private_repo()
if not install_success:
print("Failed to install private repository. Exiting.")
sys.exit(1)
agents_dir = os.path.join(os.path.dirname(__file__), 'agents')
sys.path.append(agents_dir)
# Try importing with more detailed error handling
from agents import GitHubAgent
from agents import ArxivSearchAgent
from agents import ProductHuntAgent
from agents import RedditAgent
from vertexai.generative_models import GenerativeModel
import vertexai
import asyncio
import json
import logging.config
from typing import Dict, Any, Optional, Tuple
import traceback
from datetime import datetime
import gc
import jinja2
custom_css = """
.center-label {
display: flex;
flex-direction: column; /* Makes the label stack above the input*/
align-items: center; /* Horizontally center the contents*/
text-align: center;
}
.center-label .form {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.center-label .label {
text-align: center;
width: 100%;
}
.equal-button {
flex: 1; /* Makes the buttons share available space equally */
margin: 5px;
background-color: #f0f0f0;
font-size: 12px;
}
.loading-text textarea {
text-align: center !important;
font-weight: bold !important;
color: #e67e22 !important;
background-color: #f7f7f7 !important;
}
"""
intro_text = """
<div style="padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px; margin-bottom: 20px;">
<h2 style="text-align:center; margin-bottom: 10px;">Meet IdeaLens: the AI Agent for your product ideas</h2>
<div style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 10px;">
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 20px; position: relative;">
<div style="flex: 1; margin-right: 20px; padding-right: 20px; border-right: 1px solid #e0e0e0;">
<h2 style="margin: 0; font-size: 20px; font-weight: bold;">❓ Got an idea that could change the world? 🌍</h2>
<div style="margin-top: 10px; font-size: 13px;">
💡 <span style="font-weight: bold; color: #0073e6;">IdeaLens</span> intelligently analyzes data to chart your idea's potential<br>
🌟 It explores user perspectives and predicts market reactions<br>
📊 It identifies competitors and uncovers technical resources to refine your concept<br>
📚 By integrating cutting-edge academic insights, <span style="font-weight: bold; color: #0073e6;">IdeaLens</span> ensures thorough validation<br>
🚀 With <span style="font-weight: bold; color: #0073e6;">IdeaLens</span> assisting you, success is just an idea away!
</div>
</div>
<div style="flex: 1; margin-left: 20px;">
<h2 style="margin: 0; font-size: 20px;">How IdeaLens Assists:</h2>
<div style="margin-top: 10px; font-size: 13px;">
🧠 IdeaLens reveals hidden insights by connecting patterns across platforms like <span style="font-weight: bold; color: #0073e6;">Reddit</span>,
<span style="font-weight: bold; color: #0073e6;">ProductHunt</span>,
<span style="font-weight: bold; color: #0073e6;">GitHub</span>, and
<span style="font-weight: bold; color: #0073e6;">arXiv</span>.<br>
📋 It synthesizes competitive insights and surface critical technical resources to strengthen your vision<br>
🔍 Want to go deeper? IdeaLens provides comprehensive strategic intelligence from each platform<br>
⏳ In just <span style="font-weight: bold; color: #0073e6;">5 minutes</span>, IdeaLens delivers focused, actionable guidance
</div>
</div>
</div>
<div style="font-weight: bold; margin-top: 20px;">
🔥 Ready to let IdeaLens assist you?<br>
👉 Enter your idea in the search prompt or try one of the curated examples below! 🎯✨
</div>
</div>
</div>
"""
# Debug print: Initial imports complete
print("Debug: Initial imports complete")
# Create logs directory if it doesn't exist
os.makedirs(os.path.join(os.path.dirname(__file__), 'logs'), exist_ok=True)
print(f"Debug: Logs directory created or exists at {os.path.join(os.path.dirname(__file__), 'logs')}")
print("Debug: Agents imported")
# Load configuration
print("Debug: Loading configuration...")
with open('CONFIG.json') as f:
CONFIG = json.load(f)
print("Debug: Configuration loaded successfully")
# Set up logging
print("Debug: Setting up logging...")
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('app')
print("Debug: Logging setup complete")
class QueryPreprocessor:
def __init__(self):
self._model = None
print("Debug: QueryPreprocessor initialized") # Add print statement here
@property
@lru_cache()
def model(self) -> SentenceTransformer:
if self._model is None:
print("Debug: Loading sentence transformer model...")
self._model = SentenceTransformer('all-MiniLM-L6-v2')
logger.info("Sentence transformer model initialized")
print("Debug: Sentence transformer model loaded successfully")
return self._model
async def extract_core_concepts(self, text: str) -> str:
"""Extract core concepts from text, removing structural elements"""
markers = ["Market analysis request:", "Target sector:",
"Primary features:", "Business model category:",
"Technical requirements:"]
cleaned = text
for marker in markers:
cleaned = cleaned.replace(marker, "")
return cleaned.strip()
async def check_semantic_similarity(self, original: str, processed: str,
threshold: float = 0.7) -> bool:
try:
# Extract core concepts from processed text
processed_core = await self.extract_core_concepts(processed)
# Run embedding computation in thread pool
loop = asyncio.get_event_loop()
embeddings = await loop.run_in_executor(
None,
lambda: (
self.model.encode(original, convert_to_tensor=True),
self.model.encode(processed_core, convert_to_tensor=True)
)
)
original_embedding, processed_embedding = embeddings
# Calculate cosine similarity
similarity = F.cosine_similarity(
original_embedding.unsqueeze(0),
processed_embedding.unsqueeze(0)
).item()
logger.info(f"Original query: {original}")
logger.info(f"Processed core concepts: {processed_core}")
logger.info(f"Semantic similarity: {similarity:.3f}")
return similarity > threshold
except Exception as e:
logger.error(f"Error in semantic similarity check: {str(e)}")
return False
def configure_environment():
start_time = datetime.now()
print("Debug: Starting configure_environment")
required_env_vars = [
'GITHUB_TOKEN',
'PRODUCT_HUNT_TOKEN',
'REDDIT_CLIENT_ID',
'REDDIT_CLIENT_SECRET',
'REDDIT_USER_AGENT',
'GOOGLE_APPLICATION_CREDENTIALS_JSON',
'GITHUB_APPLICATION_CREDENTIALS_JSON',
'ARXIV_APPLICATION_CREDENTIALS_JSON',
'PRODUCT_HUNT_APPLICATION_CREDENTIALS_JSON',
'REDDIT_APPLICATION_CREDENTIALS_JSON',
'GITHUB_CLOUD_PROJECT',
'ARXIV_CLOUD_PROJECT',
'PRODUCTHUNT_CLOUD_PROJECT',
'REDDIT_CLOUD_PROJECT'
]
print(f"Debug: Required environment variables: {required_env_vars}")
missing_vars = [var for var in required_env_vars if not os.getenv(var)]
if missing_vars:
error_message = f"Missing required environment variables: {', '.join(missing_vars)}. " \
f"Please check .env.example for required variables."
print(f"Debug: Error - {error_message}")
raise EnvironmentError(error_message)
print("Debug: All required environment variables are present")
# Set up Google credentials from the JSON stored in env variable
if 'GOOGLE_APPLICATION_CREDENTIALS_JSON' in os.environ:
print("Debug: Found GOOGLE_APPLICATION_CREDENTIALS_JSON")
creds_json = os.environ['GOOGLE_APPLICATION_CREDENTIALS_JSON']
with open('/tmp/google_credentials.json', 'w') as f:
f.write(creds_json)
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '/tmp/google_credentials.json'
print("Debug: Google credentials file created and GOOGLE_APPLICATION_CREDENTIALS set")
# Set up Github credentials from the JSON stored in env variable
if 'GITHUB_APPLICATION_CREDENTIALS_JSON' in os.environ:
print("Debug: Found GITHUB_APPLICATION_CREDENTIALS_JSON")
creds_json = os.environ['GITHUB_APPLICATION_CREDENTIALS_JSON']
with open('/tmp/github_credentials.json', 'w') as f:
f.write(creds_json)
os.environ['GITHUB_APPLICATION_CREDENTIALS'] = '/tmp/github_credentials.json'
print("Debug: Github credentials file created and GITHUB_APPLICATION_CREDENTIALS set")
# Set up Arxiv credentials from the JSON stored in env variable
if 'ARXIV_APPLICATION_CREDENTIALS_JSON' in os.environ:
print("Debug: Found ARXIV_APPLICATION_CREDENTIALS_JSON")
creds_json = os.environ['ARXIV_APPLICATION_CREDENTIALS_JSON']
with open('/tmp/arxiv_credentials.json', 'w') as f:
f.write(creds_json)
os.environ['ARXIV_APPLICATION_CREDENTIALS'] = '/tmp/arxiv_credentials.json'
print("Debug: Arxiv credentials file created and ARXIV_APPLICATION_CREDENTIALS set")
# Set up Product Hunt credentials from the JSON stored in env variable
if 'PRODUCTHUNT_APPLICATION_CREDENTIALS_JSON' in os.environ:
print("Debug: Found PRODUCTHUNT_APPLICATION_CREDENTIALS_JSON")
creds_json = os.environ['PRODUCTHUNT_APPLICATION_CREDENTIALS_JSON']
with open('/tmp/producthunt_credentials.json', 'w') as f:
f.write(creds_json)
os.environ['PRODUCTHUNT_APPLICATION_CREDENTIALS'] = '/tmp/producthunt_credentials.json'
print("Debug: Product Hunt credentials file created and PRODUCTHUNT_APPLICATION_CREDENTIALS set")
# Set up Reddit credentials from the JSON stored in env variable
if 'REDDIT_APPLICATION_CREDENTIALS_JSON' in os.environ:
print("Debug: Found REDDIT_APPLICATION_CREDENTIALS_JSON")
creds_json = os.environ['REDDIT_APPLICATION_CREDENTIALS_JSON']
with open('/tmp/reddit_credentials.json', 'w') as f:
f.write(creds_json)
os.environ['REDDIT_APPLICATION_CREDENTIALS'] = '/tmp/reddit_credentials.json'
print("Debug: Reddit credentials file created and REDDIT_APPLICATION_CREDENTIALS set")
end_time = datetime.now()
print(f"Debug: Finished configure_environment, Time taken: {end_time - start_time}")
def initialize_agents() -> Optional[Dict[str, Any]]:
"""Initialize all search agents with proper error handling."""
start_time = datetime.now()
print("Debug: Starting initialize_agents")
try:
print("Debug: Initializing Vertex AI...")
logger.info("Initializing agents...")
vertexai.init(project=None, location="us-central1")
print("Debug: Vertex AI initialized successfully")
summary_model = GenerativeModel("gemini-pro")
print("Debug: Summary model initialized")
# Initialize agents
print("Debug: Initializing agents...")
github_agent = GitHubAgent(
project_id=os.getenv('GITHUB_CLOUD_PROJECT'),
credentials_path='/tmp/github_credentials.json'
)
print("Debug: GitHub agent initialized")
arxiv_agent = ArxivSearchAgent(
project_id=os.getenv('ARXIV_CLOUD_PROJECT'),
credentials_path='/tmp/arxiv_credentials.json'
)
print("Debug: Arxiv agent initialized")
producthunt_agent = ProductHuntAgent(
project_id=os.getenv('PRODUCTHUNT_CLOUD_PROJECT'),
credentials_path='/tmp/producthunt_credentials.json'
)
print("Debug: Product Hunt agent initialized")
reddit_agent = RedditAgent(
project_id=os.getenv('REDDIT_CLOUD_PROJECT'),
credentials_path='/tmp/reddit_credentials.json'
)
print("Debug: Reddit agent initialized")
agents_dict = {
'summary_model': summary_model,
'github_agent': {'agent': github_agent, 'model': summary_model,'config': CONFIG.get('github_settings', {})},
'arxiv_agent': {'agent': arxiv_agent, 'model': summary_model},
'producthunt_agent': {
'agent': producthunt_agent,
'model': summary_model,
'config': CONFIG.get('producthunt_settings', {}) # Pass ProductHunt specific config
},
'reddit_agent': {'agent': reddit_agent, 'model': summary_model}
}
print("Debug: Agents initialized successfully.")
end_time = datetime.now()
print(f"Debug: Finished initialize_agents, Time taken: {end_time - start_time}")
return agents_dict
except Exception as e:
logger.error(f"Error initializing agents: {str(e)}")
print(f"Debug: Error initializing agents: {str(e)}")
logger.error(traceback.format_exc())
print(f"Debug: Traceback: {traceback.format_exc()}")
return None
async def fetch_with_timeout(coro: Any, timeout: int = 600) -> Any:
"""Wrapper for async operations with timeout."""
start_time = datetime.now()
print(f"Debug: Starting fetch_with_timeout with timeout: {timeout}")
try:
result = await asyncio.wait_for(coro, timeout=timeout)
print("Debug: fetch_with_timeout completed successfully")
end_time = datetime.now()
print(f"Debug: Finished fetch_with_timeout, Time taken: {end_time - start_time}")
return result
except asyncio.TimeoutError:
logger.error(f"Task timed out: {coro}")
print(f"Debug: Task timed out: {coro}")
return "Task timed out"
async def process_prompt(prompt: str, agents: Dict[str, Any],
progress: Optional[gr.Progress] = None) -> Tuple[str, str, str, str, str]:
try:
print(f"\n=== APP.PY PROCESSING START ===")
print(f"Original prompt received: {prompt}")
if progress is not None:
progress(0, "Starting preprocessing")
# Initialize task tracking
tasks_completed = 0 # Initialize here
total_tasks = 4 # Total number of major tasks
preprocessing_prompt = f"""
Transform this business/app idea query into structured market research format.
Original query: {prompt}
Transform using these rules:
1. Begin with "Market analysis request:"
2. Include "Target sector:"
3. Specify "Primary features:"
4. Add "Business model category:"
5. End with "Technical requirements:"
Format as a single paragraph without the rule headers. Use professional business language.
"""
print(f"Generated preprocessing prompt: {preprocessing_prompt}")
# Initialize preprocessor
preprocessor = QueryPreprocessor()
try:
# First pass - structure the query
response = await fetch_with_timeout(
asyncio.to_thread(
lambda: agents['summary_model'].generate_content(preprocessing_prompt)
)
)
structured_prompt = response.text.strip()
print(f"After first pass structuring: {structured_prompt}")
# Second pass - format for API efficiency
format_prompt = f"""
Convert this market analysis into a concise, direct query suitable for API processing.
Keep all key details but remove unnecessary words.
Query: {structured_prompt}
"""
format_response = await fetch_with_timeout(
asyncio.to_thread(
lambda: agents['summary_model'].generate_content(format_prompt)
)
)
processed_prompt = format_response.text.strip()
print(f"After second pass formatting: {processed_prompt}")
# Check semantic similarity with core concept extraction
is_similar = await preprocessor.check_semantic_similarity(prompt, processed_prompt)
print(f"Semantic similarity check result: {is_similar}")
if not processed_prompt or not is_similar:
logger.warning("Query preprocessing validation failed, using original query")
logger.info(f"Original: {prompt}")
logger.info(f"Processed: {processed_prompt}")
processed_prompt = prompt
except Exception as e:
logger.error(f"Query preprocessing failed: {str(e)}")
processed_prompt = prompt
logger.info(f"Original prompt: {prompt}")
logger.info(f"Processed prompt: {processed_prompt}")
# Sequential execution with individual error handling
if progress is not None:
progress(0.2, "Processing ProductHunt data")
try:
print("\n=== CALLING PRODUCTHUNT AGENT ===")
producthunt_result = await fetch_with_timeout(
agents['producthunt_agent']['agent'].process_search(
agents['producthunt_agent']['model'],
processed_prompt
),
timeout=CONFIG['timeouts']['analysis']
)
print(f"ProductHunt result received: {'Empty' if not producthunt_result else 'Has content'}")
producthunt_result = str(producthunt_result)
tasks_completed += 1
await asyncio.sleep(5)
gc.collect()
except Exception as e:
producthunt_result = f"ProductHunt Error: {str(e)}"
logger.error(f"ProductHunt search failed: {str(e)}")
print(f"ProductHunt search failed: {str(e)}")
if progress is not None:
progress(0.4, "Processing GitHub data")
await asyncio.sleep(20)
try:
print("\n=== CALLING GITHUB AGENT ===")
github_result = await fetch_with_timeout(
agents['github_agent']['agent'].search_and_analyze(
processed_prompt,
CONFIG['github_settings']['search']['final_analysis_count'],
agents['github_agent']['model']
)
)
print(f"GitHub result received: {'Empty' if not github_result else 'Has content'}")
github_result = str(github_result)
tasks_completed += 1
except Exception as e:
github_result = f"GitHub Error: {str(e)}"
logger.error(f"GitHub search failed: {str(e)}")
print(f"GitHub search failed: {str(e)}")
if progress is not None:
progress(0.6, "Processing Arxiv data")
try:
arxiv_result = await fetch_with_timeout(
agents['arxiv_agent']['agent'].search_and_analyze(
processed_prompt, 5, agents['arxiv_agent']['model']
)
)
arxiv_result = str(arxiv_result)
tasks_completed += 1
except Exception as e:
arxiv_result = f"Arxiv Error: {str(e)}"
logger.error(f"Arxiv search failed: {str(e)}")
print(f"Arxiv search failed: {str(e)}")
if progress is not None:
progress(0.8, "Processing Reddit data")
try:
reddit_result = await fetch_with_timeout(
agents['reddit_agent']['agent'].search_and_analyze(
processed_prompt,
agents['reddit_agent']['model'],
num_posts=5
),
timeout=CONFIG['timeouts']['analysis']
)
reddit_result = str(reddit_result)
tasks_completed += 1
except Exception as e:
reddit_result = f"Reddit Error: {str(e)}"
logger.error(f"Reddit search failed: {str(e)}")
if progress is not None:
progress(0.9, "Generating summary")
template_env = jinja2.Environment(
loader=jinja2.FileSystemLoader('templates')
)
template = template_env.get_template('summary_template.txt')
prompt_text = template.render(
prompt=processed_prompt,
github_data=github_result,
arxiv_data=arxiv_result,
producthunt_data=producthunt_result,
reddit_data=reddit_result
)
API_LIMIT_MESSAGE = """
IdeaLens has reached its API query limits but you may still be able to see results from individual platform sections below. Please try again in a few minutes.
This temporary pause helps us maintain service quality and ensure fair access for all users.
Thank you for your patience!
"""
try:
max_retries = 3
retry_delay = 5
attempt = 0
while attempt < max_retries:
try:
loop = asyncio.get_event_loop()
response = await asyncio.wait_for(
loop.run_in_executor(
None,
lambda: agents['summary_model'].generate_content(prompt_text)
),
timeout=CONFIG['timeouts']['analysis']
)
executive_summary = response.text
break
except asyncio.TimeoutError:
print("Summary generation timeout")
if attempt < max_retries - 1:
print(f"Retry attempt {attempt + 1}/{max_retries}")
await asyncio.sleep(retry_delay)
retry_delay *= 2
attempt += 1
else:
raise Exception("Summary generation timeout")
except Exception as e:
if "429" in str(e) or attempt < max_retries - 1:
print(f"Rate limit or error, attempt {attempt + 1}/{max_retries}. Waiting {retry_delay} seconds.")
await asyncio.sleep(retry_delay)
retry_delay *= 2
attempt += 1
else:
raise
else:
raise Exception("Max retries exceeded for summary generation")
except Exception as e:
error_type = str(e)
print(f"Summary generation failed: {error_type}")
logger.error(f"Summary generation failed: {error_type}")
executive_summary = API_LIMIT_MESSAGE
if progress is not None:
progress(1, "Completed")
return (executive_summary, arxiv_result, github_result, producthunt_result, reddit_result)
except Exception as e:
print(f"Process prompt error: {str(e)}")
logger.error(f"Process prompt error: {str(e)}")
API_LIMIT_MESSAGE = """
IdeaLens has reached its API query limits. Please try again in a few minutes.
This temporary pause helps us maintain service quality and ensure fair access for all users.
Thank you for your patience!
"""
return (API_LIMIT_MESSAGE, "", "", "", "")
finally:
gc.collect()
def start_loading(prompt):
"""Show loader when search starts"""
print("Start loading")
if not prompt.strip():
return gr.update(visible=False)
return gr.update(visible=True)
def create_interface(agents: Dict[str, Any]) -> gr.Blocks:
"""Create and configure the Gradio interface."""
start_time = datetime.now()
print("Debug: Starting create_interface")
with gr.Blocks(css=custom_css) as interface:
gr.HTML(intro_text)
with gr.Row():
input_text = gr.Textbox(
lines=2,
placeholder="Enter your search prompt here",
label="Search Prompt",
elem_classes="center-label"
)
print("Debug: Input textbox created")
# Create the sample prompt buttons
with gr.Row(equal_height=True):
sample_prompts = [
"A crypto-backed decentralized marketplace for digital assets, enabling trustless peer-to-peer trading and licensing",
"A music app that adjusts soundscapes based on relaxation or focus detected via EEG",
"An AI app that turns real-world objects into interactive holographic tutorials using augmented reality and real-time object recognition",
]
for prompt in sample_prompts:
gr.Button(prompt, elem_classes="equal-button").click(
lambda p=prompt: p,
outputs=input_text
)
with gr.Row():
start_button = gr.Button("Start Search", variant="primary")
print("Debug: Start button created")
with gr.Row():
error_box = gr.Textbox(
label="Status/Error Messages",
visible=False
)
print("Debug: Error box created")
loader = gr.Textbox(
value="Processing your request... Please wait...",
visible=False,
label="Status",
elem_classes="loading-text"
)
with gr.Row():
executive_summary_output = gr.Markdown(
label="Executive Summary",
show_copy_button=True
)
print("Debug: Executive summary textbox created")
with gr.Column(visible=False) as output_column:
outputs = {}
buttons = {}
for source in ['reddit', 'producthunt', 'github', 'arxiv']:
outputs[source] = gr.Markdown(
label=f"{source.title()} Results",
visible=False,
show_copy_button=True
)
if source == "reddit":
button_label = "Show User Perspectives (Reddit)"
elif source == "producthunt":
button_label = "Show Similar Products (Producthunt)"
elif source == "arxiv":
button_label = "Show Related Research (Arxiv)"
elif source == "github":
button_label = "Explore Related Code (Github)"
else:
button_label = f"Show Full {source.title()} Results"
buttons[source] = gr.Button(button_label)
# Configure button handlers
async def handle_search(prompt: str) -> Tuple[str, str, str, str, str, gr.Textbox, gr.Column]:
start_time = datetime.now()
print(f"Debug: Starting handle_search with prompt: {prompt}")
API_LIMIT_MESSAGE = """
IdeaLens has reached its API query limits. Please try again in a few minutes.
This temporary pause helps us maintain service quality and ensure fair access for all users.
Thank you for your patience!
"""
try:
if not prompt.strip():
print("Debug: Prompt is empty")
return "Please enter a search query", "", "", "", "", gr.update(visible=False), gr.update(visible=True)
result = await process_prompt(prompt, agents, gr.Progress())
print("Debug: handle_search completed")
# Check if any of the results contain error messages
if any(isinstance(r, str) and "Error:" in r for r in result[1:]):
raise Exception("One or more data sources failed")
end_time = datetime.now()
print(f"Debug: Finished handle_search, Time taken: {end_time - start_time}")
return result[0], result[1], result[2], result[3], result[4], gr.update(visible=False), gr.update(visible=True)
except Exception as e:
print(f"Handle search error: {str(e)}")
logger.error(f"Handle search error: {str(e)}")
# Return API limit message for all error scenarios
return (
API_LIMIT_MESSAGE, # executive summary
"", # arxiv
"", # github
"", # producthunt
"", # reddit
gr.update(visible=False), # loader
gr.update(visible=True) # output column
)
# Wire up the start button handlers
start_button.click(
fn=start_loading,
inputs=[input_text],
outputs=[loader],
queue=False # Execute immediately
).then(
fn=handle_search,
inputs=[input_text],
outputs=[
executive_summary_output,
outputs['arxiv'],
outputs['github'],
outputs['producthunt'],
outputs['reddit'],
loader,
output_column
],
api_name="search",
queue=True # This will run after the loader is shown
)
# Configure view buttons
for source, button in buttons.items():
button.click(
lambda: gr.update(visible=True),
None,
outputs[source]
)
print(f"Debug: {source} button click handler configured")
return interface
def main() -> None:
"""Main application entry point."""
start_time = datetime.now()
print("Debug: Starting main function")
try:
# Configure environment
print("Debug: Configuring environment...")
configure_environment()
print("Debug: Environment configured successfully")
# Initialize agents
print("Debug: Initializing agents...")
agents = initialize_agents()
if not agents:
print("Debug: Agent initialization failed")
raise RuntimeError("Failed to initialize one or more agents")
print("Debug: Agents initialized successfully")
# Create and launch interface
print("Debug: Creating interface...")
interface = create_interface(agents)
print("Debug: Interface created successfully")
interface.launch(debug=True)
print("Debug: Gradio interface launched")
except Exception as e:
logger.error(f"Application startup failed: {str(e)}")
print(f"Debug: Application startup failed: {str(e)}")
logger.error(traceback.format_exc())
print(f"Debug: Traceback: {traceback.format_exc()}")
raise
finally:
end_time = datetime.now()
print(f"Debug: Exiting main function, Time taken: {end_time - start_time}")
if __name__ == "__main__":
main()