final version
This commit is contained in:
parent
d8825c00ee
commit
ceb218bc50
2 changed files with 0 additions and 299 deletions
|
|
@ -1,294 +0,0 @@
|
|||
from typing import Optional, Dict, Any
|
||||
import streamlit as st
|
||||
from agno.agent import Agent, RunResponse
|
||||
from agno.models.openai import OpenAIChat
|
||||
from agno.models.google import Gemini
|
||||
from e2b_code_interpreter import Sandbox
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
import base64
|
||||
load_dotenv()
|
||||
|
||||
def initialize_session_state() -> None:
|
||||
"""Initialize Streamlit session state variables."""
|
||||
if 'openai_key' not in st.session_state:
|
||||
st.session_state.openai_key = ''
|
||||
if 'gemini_key' not in st.session_state:
|
||||
st.session_state.gemini_key = ''
|
||||
if 'e2b_key' not in st.session_state:
|
||||
st.session_state.e2b_key = ''
|
||||
if 'sandbox' not in st.session_state:
|
||||
st.session_state.sandbox = None
|
||||
|
||||
def setup_sidebar() -> None:
|
||||
"""Setup sidebar with API key inputs."""
|
||||
with st.sidebar:
|
||||
st.title("API Configuration")
|
||||
st.session_state.openai_key = st.text_input("OpenAI API Key",
|
||||
value=st.session_state.openai_key,
|
||||
type="password")
|
||||
st.session_state.gemini_key = st.text_input("Gemini API Key",
|
||||
value=st.session_state.gemini_key,
|
||||
type="password")
|
||||
st.session_state.e2b_key = st.text_input("E2B API Key",
|
||||
value=st.session_state.e2b_key,
|
||||
type="password")
|
||||
|
||||
def create_agents() -> tuple[Agent, Agent, Agent]:
|
||||
"""Create vision, coding, and execution agents with API keys from session state."""
|
||||
vision_agent = Agent(
|
||||
model=Gemini(id="gemini-exp-1206", api_key=st.session_state.gemini_key),
|
||||
markdown=True,
|
||||
)
|
||||
|
||||
coding_agent = Agent(
|
||||
model=OpenAIChat(
|
||||
id="o3-mini",
|
||||
api_key=st.session_state.openai_key,
|
||||
system_prompt="""You are an expert Python programmer. You will receive coding problems similar to LeetCode questions,
|
||||
which may include problem statements, sample inputs, and examples. Your task is to:
|
||||
1. Analyze the problem carefully
|
||||
2. Write clean, efficient Python code to solve it
|
||||
3. Include proper documentation and type hints
|
||||
4. The code will be executed in an e2b sandbox environment
|
||||
Please ensure your code is complete and handles edge cases appropriately."""
|
||||
),
|
||||
markdown=True
|
||||
)
|
||||
|
||||
execution_agent = Agent(
|
||||
model=OpenAIChat(
|
||||
id="o3-mini",
|
||||
api_key=st.session_state.openai_key,
|
||||
system_prompt="""You are an expert at executing Python code in sandbox environments.
|
||||
Your task is to:
|
||||
1. Take the provided Python code
|
||||
2. Execute it in the e2b sandbox
|
||||
3. Format and explain the results clearly
|
||||
4. Handle any execution errors gracefully
|
||||
Always ensure proper error handling and clear output formatting."""
|
||||
),
|
||||
markdown=True
|
||||
)
|
||||
|
||||
return vision_agent, coding_agent, execution_agent
|
||||
|
||||
def initialize_sandbox() -> None:
|
||||
"""Initialize or reset the e2b sandbox with proper timeout configuration."""
|
||||
try:
|
||||
if st.session_state.sandbox:
|
||||
try:
|
||||
st.session_state.sandbox.close()
|
||||
except:
|
||||
pass
|
||||
os.environ['E2B_API_KEY'] = st.session_state.e2b_key
|
||||
# Initialize sandbox with 60 second timeout
|
||||
st.session_state.sandbox = Sandbox(timeout=60)
|
||||
except Exception as e:
|
||||
st.error(f"Failed to initialize sandbox: {str(e)}")
|
||||
st.session_state.sandbox = None
|
||||
|
||||
def run_code_in_sandbox(code: str) -> Dict[str, Any]:
|
||||
if not st.session_state.sandbox:
|
||||
initialize_sandbox()
|
||||
|
||||
execution = st.session_state.sandbox.run_code(code)
|
||||
return {
|
||||
"logs": execution.logs,
|
||||
"files": st.session_state.sandbox.files.list("/")
|
||||
}
|
||||
|
||||
def process_image_with_gemini(vision_agent: Agent, image: Image) -> str:
|
||||
"""
|
||||
Process uploaded image with Gemini Vision to extract code problem.
|
||||
"""
|
||||
prompt = """Analyze this image and extract any coding problem or code snippet shown.
|
||||
Describe it in clear natural language, including any:
|
||||
1. Problem statement
|
||||
2. Input/output examples
|
||||
3. Constraints or requirements
|
||||
Format it as a proper coding problem description."""
|
||||
|
||||
# Save image to a temporary file
|
||||
temp_path = "temp_image.png"
|
||||
try:
|
||||
# Convert to RGB if needed
|
||||
if image.mode != 'RGB':
|
||||
image = image.convert('RGB')
|
||||
image.save(temp_path, format="PNG")
|
||||
|
||||
# Read the file and create image data
|
||||
with open(temp_path, 'rb') as img_file:
|
||||
img_bytes = img_file.read()
|
||||
|
||||
# Pass image to Gemini
|
||||
response = vision_agent.run(
|
||||
prompt,
|
||||
images=[{"filepath": temp_path}] # Use filepath instead of content
|
||||
)
|
||||
return response.content
|
||||
except Exception as e:
|
||||
st.error(f"Error processing image: {str(e)}")
|
||||
return "Failed to process the image. Please try again or use text input instead."
|
||||
finally:
|
||||
# Clean up temporary file
|
||||
if os.path.exists(temp_path):
|
||||
os.remove(temp_path)
|
||||
|
||||
def execute_code_with_agent(execution_agent: Agent, code: str, sandbox: Sandbox) -> str:
|
||||
"""
|
||||
Use execution agent to run and explain code results.
|
||||
"""
|
||||
try:
|
||||
# Set timeout to 30 seconds for code execution
|
||||
sandbox.set_timeout(30)
|
||||
execution = sandbox.run_code(code)
|
||||
|
||||
# Handle execution errors
|
||||
if execution.error:
|
||||
if "TimeoutException" in str(execution.error):
|
||||
return "⚠️ Execution Timeout: The code took too long to execute (>30 seconds). Please optimize your solution or try a smaller input."
|
||||
|
||||
error_prompt = f"""The code execution resulted in an error:
|
||||
Error: {execution.error}
|
||||
|
||||
Please analyze the error and provide a clear explanation of what went wrong."""
|
||||
response = execution_agent.run(error_prompt)
|
||||
return f"⚠️ Execution Error:\n{response.content}"
|
||||
|
||||
# Get files list safely
|
||||
try:
|
||||
files = sandbox.files.list("/")
|
||||
except:
|
||||
files = []
|
||||
|
||||
prompt = f"""Here is the code execution result:
|
||||
Logs: {execution.logs}
|
||||
Files: {str(files)}
|
||||
|
||||
Please provide a clear explanation of the results and any outputs."""
|
||||
|
||||
response = execution_agent.run(prompt)
|
||||
return response.content
|
||||
except Exception as e:
|
||||
# Reinitialize sandbox on error
|
||||
try:
|
||||
initialize_sandbox()
|
||||
except:
|
||||
pass
|
||||
return f"⚠️ Sandbox Error: {str(e)}"
|
||||
|
||||
def main() -> None:
|
||||
"""Main application function."""
|
||||
st.title("O3-Mini Coding Agent")
|
||||
|
||||
# Add timeout info in sidebar
|
||||
initialize_session_state()
|
||||
setup_sidebar()
|
||||
with st.sidebar:
|
||||
st.info("⏱️ Code execution timeout: 30 seconds")
|
||||
|
||||
# Check all required API keys
|
||||
if not (st.session_state.openai_key and
|
||||
st.session_state.gemini_key and
|
||||
st.session_state.e2b_key):
|
||||
st.warning("Please enter all required API keys in the sidebar.")
|
||||
return
|
||||
|
||||
vision_agent, coding_agent, execution_agent = create_agents()
|
||||
|
||||
# Clean, single-column layout
|
||||
uploaded_image = st.file_uploader(
|
||||
"Upload an image of your coding problem (optional)",
|
||||
type=['png', 'jpg', 'jpeg']
|
||||
)
|
||||
|
||||
if uploaded_image:
|
||||
st.image(uploaded_image, caption="Uploaded Image", use_container_width=True)
|
||||
|
||||
user_query = st.text_area(
|
||||
"Or type your coding problem here:",
|
||||
placeholder="Example: Write a function to find the sum of two numbers. Include sample input/output cases.",
|
||||
height=100
|
||||
)
|
||||
|
||||
# Process button
|
||||
if st.button("Generate & Execute Solution", type="primary"):
|
||||
if uploaded_image and not user_query:
|
||||
# Process image with Gemini
|
||||
with st.spinner("Processing image..."):
|
||||
try:
|
||||
# Save uploaded file to temporary location
|
||||
image = Image.open(uploaded_image)
|
||||
extracted_query = process_image_with_gemini(vision_agent, image)
|
||||
|
||||
if extracted_query.startswith("Failed to process"):
|
||||
st.error(extracted_query)
|
||||
return
|
||||
|
||||
st.info("📝 Extracted Problem:")
|
||||
st.write(extracted_query)
|
||||
|
||||
# Pass extracted query to coding agent
|
||||
with st.spinner("Generating solution..."):
|
||||
response = coding_agent.run(extracted_query)
|
||||
except Exception as e:
|
||||
st.error(f"Error processing image: {str(e)}")
|
||||
return
|
||||
|
||||
elif user_query and not uploaded_image:
|
||||
# Direct text input processing
|
||||
with st.spinner("Generating solution..."):
|
||||
response = coding_agent.run(user_query)
|
||||
|
||||
elif user_query and uploaded_image:
|
||||
st.error("Please use either image upload OR text input, not both.")
|
||||
return
|
||||
else:
|
||||
st.warning("Please provide either an image or text description of your coding problem.")
|
||||
return
|
||||
|
||||
# Display and execute solution
|
||||
if 'response' in locals():
|
||||
st.divider()
|
||||
st.subheader("💻 Solution")
|
||||
|
||||
# Extract code from markdown response
|
||||
code_blocks = response.content.split("```python")
|
||||
if len(code_blocks) > 1:
|
||||
code = code_blocks[1].split("```")[0].strip()
|
||||
|
||||
# Display the code
|
||||
st.code(code, language="python")
|
||||
|
||||
# Execute code with execution agent
|
||||
with st.spinner("Executing code..."):
|
||||
# Always initialize a fresh sandbox for each execution
|
||||
initialize_sandbox()
|
||||
|
||||
if st.session_state.sandbox:
|
||||
execution_results = execute_code_with_agent(
|
||||
execution_agent,
|
||||
code,
|
||||
st.session_state.sandbox
|
||||
)
|
||||
|
||||
# Display execution results
|
||||
st.divider()
|
||||
st.subheader("🚀 Execution Results")
|
||||
st.markdown(execution_results)
|
||||
|
||||
# Try to display files if available
|
||||
try:
|
||||
files = st.session_state.sandbox.files.list("/")
|
||||
if files:
|
||||
st.markdown("📁 **Generated Files:**")
|
||||
st.json(files)
|
||||
except:
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
streamlit
|
||||
python-dotenv
|
||||
e2b
|
||||
agno
|
||||
Pillow
|
||||
Loading…
Reference in a new issue