diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ + diff --git a/README.md b/README.md index 5d64132..aeb610f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
@@ -16,89 +16,122 @@
+
+
+
+
๐จ Describe Your Meme Concept
', unsafe_allow_html=True) + + query = st.text_input( + "Meme Idea Input", + placeholder="Example: 'Ilya's SSI quietly looking at the OpenAI vs Deepseek debate while diligently working on ASI'", + label_visibility="collapsed" + ) + + if st.button("Generate Meme ๐"): + if not api_key: + st.warning(f"Please provide the {model_choice} API key") + st.stop() + if not query: + st.warning("Please enter a meme idea") + st.stop() + + with st.spinner(f"๐ง {model_choice} is generating your meme..."): + try: + meme_url = asyncio.run(generate_meme(query, model_choice, api_key)) + + if meme_url: + st.success("โ Meme Generated Successfully!") + st.image(meme_url, caption="Generated Meme Preview", use_container_width=True) + st.markdown(f""" + **Direct Link:** [Open in ImgFlip]({meme_url}) + **Embed URL:** `{meme_url}` + """) + else: + st.error("โ Failed to generate meme. Please try again with a different prompt.") + + except Exception as e: + st.error(f"Error: {str(e)}") + st.info("๐ก If using OpenAI, ensure your account has GPT-4o access") + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/ai_agent_tutorials/ai_meme_generator_agent_browseruse/requirements.txt b/ai_agent_tutorials/ai_meme_generator_agent_browseruse/requirements.txt new file mode 100644 index 0000000..0918b46 --- /dev/null +++ b/ai_agent_tutorials/ai_meme_generator_agent_browseruse/requirements.txt @@ -0,0 +1,6 @@ +streamlit +browser-use==0.1.26 +playwright==1.49.1 +langchain-openai +langchain-anthropic +asyncio diff --git a/ai_agent_tutorials/ai_mental_wellbeing_agent/README.md b/ai_agent_tutorials/ai_mental_wellbeing_agent/README.md new file mode 100644 index 0000000..a70b0bc --- /dev/null +++ b/ai_agent_tutorials/ai_mental_wellbeing_agent/README.md @@ -0,0 +1,73 @@ +# AI Mental Wellbeing Agent Team ๐ง + +The AI Mental Wellbeing Agent Team is a supportive mental health assessment and guidance system powered by [AG2](https://github.com/ag2ai/ag2?tab=readme-ov-file)(formerly AutoGen)'s AI Agent framework. This app provides personalized mental health support through the coordination of specialized AI agents, each focusing on different aspects of mental health care based on user inputs such as emotional state, stress levels, sleep patterns, and current symptoms. This is built on AG2's new swarm feature run through initiate_swarm_chat() method. + +## Features + +- **Specialized Mental Wellbeing Support Team** + - ๐ง **Assessment Agent**: Analyzes emotional state and psychological needs with clinical precision and empathy + - ๐ฏ **Action Agent**: Creates immediate action plans and connects users with appropriate resources + - ๐ **Follow-up Agent**: Designs long-term support strategies and prevention plans + +- **Comprehensive Mental Wellbeing Support**: + - Detailed psychological assessment + - Immediate coping strategies + - Resource recommendations + - Long-term support planning + - Crisis prevention strategies + - Progress monitoring systems + +- **Customizable Input Parameters**: + - Current emotional state + - Sleep patterns + - Stress levels + - Support system information + - Recent life changes + - Current symptoms + +- **Interactive Results**: + - Real-time assessment summaries + - Detailed recommendations in expandable sections + - Clear action steps and resources + - Long-term support strategies + +## How to Run + +Follow these steps to set up and run the application: + +1. **Clone the Repository**: + ```bash + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd ai_agent_tutorials/ai_mental_wellbeing_agent + ``` + +2. **Install Dependencies**: + ```bash + pip install -r requirements.txt + ``` + +3. **Create Environment File**: + Create a `.env` file in the project directory: + ```bash + echo "AUTOGEN_USE_DOCKER=0" > .env + ``` + This disables Docker requirement for code execution in AutoGen. + +4. **Set Up OpenAI API Key**: + - Obtain an OpenAI API key from [OpenAI's platform](https://platform.openai.com) + - You'll input this key in the app's sidebar when running + +5. **Run the Streamlit App**: + ```bash + streamlit run ai_mental_wellbeing_agent.py + ``` + + +## โ ๏ธ Important Notice + +This application is a supportive tool and does not replace professional mental health care. If you're experiencing thoughts of self-harm or severe crisis: + +- Call National Crisis Hotline: 988 +- Call Emergency Services: 911 +- Seek immediate professional help + diff --git a/ai_agent_tutorials/ai_mental_wellbeing_agent/ai_mental_wellbeing_agent.py b/ai_agent_tutorials/ai_mental_wellbeing_agent/ai_mental_wellbeing_agent.py new file mode 100644 index 0000000..2210743 --- /dev/null +++ b/ai_agent_tutorials/ai_mental_wellbeing_agent/ai_mental_wellbeing_agent.py @@ -0,0 +1,226 @@ +import streamlit as st +from autogen import (SwarmAgent, SwarmResult, initiate_swarm_chat, OpenAIWrapper,AFTER_WORK,UPDATE_SYSTEM_MESSAGE) +import os + +os.environ["AUTOGEN_USE_DOCKER"] = "0" + +if 'output' not in st.session_state: + st.session_state.output = { + 'assessment': '', + 'action': '', + 'followup': '' + } + +st.sidebar.title("OpenAI API Key") +api_key = st.sidebar.text_input("Enter your OpenAI API Key", type="password") + +st.sidebar.warning(""" +## โ ๏ธ Important Notice + +This application is a supportive tool and does not replace professional mental health care. If you're experiencing thoughts of self-harm or severe crisis: + +- Call National Crisis Hotline: 988 +- Call Emergency Services: 911 +- Seek immediate professional help +""") + +st.title("๐ง Mental Wellbeing Agent") + +st.info(""" +**Meet Your Mental Wellbeing Agent Team:** + +๐ง **Assessment Agent** - Analyzes your situation and emotional needs +๐ฏ **Action Agent** - Creates immediate action plan and connects you with resources +๐ **Follow-up Agent** - Designs your long-term support strategy +""") + +st.subheader("Personal Information") +col1, col2 = st.columns(2) + +with col1: + mental_state = st.text_area("How have you been feeling recently?", + placeholder="Describe your emotional state, thoughts, or concerns...") + sleep_pattern = st.select_slider( + "Sleep Pattern (hours per night)", + options=[f"{i}" for i in range(0, 13)], + value="7" + ) + +with col2: + stress_level = st.slider("Current Stress Level (1-10)", 1, 10, 5) + support_system = st.multiselect( + "Current Support System", + ["Family", "Friends", "Therapist", "Support Groups", "None"] + ) + +recent_changes = st.text_area( + "Any significant life changes or events recently?", + placeholder="Job changes, relationships, losses, etc..." +) + +current_symptoms = st.multiselect( + "Current Symptoms", + ["Anxiety", "Depression", "Insomnia", "Fatigue", "Loss of Interest", + "Difficulty Concentrating", "Changes in Appetite", "Social Withdrawal", + "Mood Swings", "Physical Discomfort"] +) + +if st.button("Get Support Plan"): + if not api_key: + st.error("Please enter your OpenAI API key.") + else: + with st.spinner('๐ค AI Agents are analyzing your situation...'): + try: + task = f""" + Create a comprehensive mental health support plan based on: + + Emotional State: {mental_state} + Sleep: {sleep_pattern} hours per night + Stress Level: {stress_level}/10 + Support System: {', '.join(support_system) if support_system else 'None reported'} + Recent Changes: {recent_changes} + Current Symptoms: {', '.join(current_symptoms) if current_symptoms else 'None reported'} + """ + + system_messages = { + "assessment_agent": """ + You are an experienced mental health professional speaking directly to the user. Your task is to: + 1. Create a safe space by acknowledging their courage in seeking support + 2. Analyze their emotional state with clinical precision and genuine empathy + 3. Ask targeted follow-up questions to understand their full situation + 4. Identify patterns in their thoughts, behaviors, and relationships + 5. Assess risk levels with validated screening approaches + 6. Help them understand their current mental health in accessible language + 7. Validate their experiences without minimizing or catastrophizing + + Always use "you" and "your" when addressing the user. Blend clinical expertise with genuine warmth and never rush to conclusions. + """, + + "action_agent": """ + You are a crisis intervention and resource specialist speaking directly to the user. Your task is to: + 1. Provide immediate evidence-based coping strategies tailored to their specific situation + 2. Prioritize interventions based on urgency and effectiveness + 3. Connect them with appropriate mental health services while acknowledging barriers (cost, access, stigma) + 4. Create a concrete daily wellness plan with specific times and activities + 5. Suggest specific support communities with details on how to join + 6. Balance crisis resources with empowerment techniques + 7. Teach simple self-regulation techniques they can use immediately + + Focus on practical, achievable steps that respect their current capacity and energy levels. Provide options ranging from minimal effort to more involved actions. + """, + + "followup_agent": """ + You are a mental health recovery planner speaking directly to the user. Your task is to: + 1. Design a personalized long-term support strategy with milestone markers + 2. Create a progress monitoring system that matches their preferences and habits + 3. Develop specific relapse prevention strategies based on their unique triggers + 4. Establish a support network mapping exercise to identify existing resources + 5. Build a graduated self-care routine that evolves with their recovery + 6. Plan for setbacks with self-compassion techniques + 7. Set up a maintenance schedule with clear check-in mechanisms + + Focus on building sustainable habits that integrate with their lifestyle and values. Emphasize progress over perfection and teach skills for self-directed care. + """ + } + + llm_config = { + "config_list": [{"model": "gpt-4o", "api_key": api_key}] + } + + context_variables = { + "assessment": None, + "action": None, + "followup": None, + } + + def update_assessment_overview(assessment_summary: str, context_variables: dict) -> SwarmResult: + context_variables["assessment"] = assessment_summary + st.sidebar.success('Assessment: ' + assessment_summary) + return SwarmResult(agent="action_agent", context_variables=context_variables) + + def update_action_overview(action_summary: str, context_variables: dict) -> SwarmResult: + context_variables["action"] = action_summary + st.sidebar.success('Action Plan: ' + action_summary) + return SwarmResult(agent="followup_agent", context_variables=context_variables) + + def update_followup_overview(followup_summary: str, context_variables: dict) -> SwarmResult: + context_variables["followup"] = followup_summary + st.sidebar.success('Follow-up Strategy: ' + followup_summary) + return SwarmResult(agent="assessment_agent", context_variables=context_variables) + + def update_system_message_func(agent: SwarmAgent, messages) -> str: + system_prompt = system_messages[agent.name] + current_gen = agent.name.split("_")[0] + + if agent._context_variables.get(current_gen) is None: + system_prompt += f"Call the update function provided to first provide a 2-3 sentence summary of your ideas on {current_gen.upper()} based on the context provided." + agent.llm_config['tool_choice'] = {"type": "function", "function": {"name": f"update_{current_gen}_overview"}} + else: + agent.llm_config["tools"] = None + agent.llm_config['tool_choice'] = None + system_prompt += f"\n\nYour task\nYou task is write the {current_gen} part of the report. Do not include any other parts. Do not use XML tags.\nStart your reponse with: '## {current_gen.capitalize()} Design'." + k = list(agent._oai_messages.keys())[-1] + agent._oai_messages[k] = agent._oai_messages[k][:1] + + system_prompt += f"\n\n\nBelow are some context for you to refer to:" + for k, v in agent._context_variables.items(): + if v is not None: + system_prompt += f"\n{k.capitalize()} Summary:\n{v}" + + agent.client = OpenAIWrapper(**agent.llm_config) + return system_prompt + + state_update = UPDATE_SYSTEM_MESSAGE(update_system_message_func) + + assessment_agent = SwarmAgent( + "assessment_agent", + llm_config=llm_config, + functions=update_assessment_overview, + update_agent_state_before_reply=[state_update] + ) + + action_agent = SwarmAgent( + "action_agent", + llm_config=llm_config, + functions=update_action_overview, + update_agent_state_before_reply=[state_update] + ) + + followup_agent = SwarmAgent( + "followup_agent", + llm_config=llm_config, + functions=update_followup_overview, + update_agent_state_before_reply=[state_update] + ) + + assessment_agent.register_hand_off(AFTER_WORK(action_agent)) + action_agent.register_hand_off(AFTER_WORK(followup_agent)) + followup_agent.register_hand_off(AFTER_WORK(assessment_agent)) + + result, _, _ = initiate_swarm_chat( + initial_agent=assessment_agent, + agents=[assessment_agent, action_agent, followup_agent], + user_agent=None, + messages=task, + max_rounds=13, + ) + + st.session_state.output = { + 'assessment': result.chat_history[-3]['content'], + 'action': result.chat_history[-2]['content'], + 'followup': result.chat_history[-1]['content'] + } + + with st.expander("Situation Assessment"): + st.markdown(st.session_state.output['assessment']) + + with st.expander("Action Plan & Resources"): + st.markdown(st.session_state.output['action']) + + with st.expander("Long-term Support Strategy"): + st.markdown(st.session_state.output['followup']) + + st.success('โจ Mental health support plan generated successfully!') + + except Exception as e: + st.error(f"An error occurred: {str(e)}") diff --git a/ai_agent_tutorials/ai_mental_wellbeing_agent/requirements.txt b/ai_agent_tutorials/ai_mental_wellbeing_agent/requirements.txt new file mode 100644 index 0000000..da4c21a --- /dev/null +++ b/ai_agent_tutorials/ai_mental_wellbeing_agent/requirements.txt @@ -0,0 +1,4 @@ +autogen-agentchat +autogen-ext +pyautogen +streamlit \ No newline at end of file diff --git a/ai_agent_tutorials/ai_movie_production_agent/README.md b/ai_agent_tutorials/ai_movie_production_agent/README.md index 0a1bf8e..3dac2c7 100644 --- a/ai_agent_tutorials/ai_movie_production_agent/README.md +++ b/ai_agent_tutorials/ai_movie_production_agent/README.md @@ -12,6 +12,7 @@ This Streamlit app is an AI-powered movie production assistant that helps bring ```bash git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git +cd awesome-llm-apps/ai_agent_tutorials/ai_movie_production_agent ``` 2. Install the required dependencies: diff --git a/ai_agent_tutorials/ai_movie_production_agent/movie_production_agent.py b/ai_agent_tutorials/ai_movie_production_agent/movie_production_agent.py index 064d2c2..b324bca 100644 --- a/ai_agent_tutorials/ai_movie_production_agent/movie_production_agent.py +++ b/ai_agent_tutorials/ai_movie_production_agent/movie_production_agent.py @@ -1,8 +1,8 @@ # Import the required libraries import streamlit as st -from phi.assistant import Assistant -from phi.tools.serpapi_tools import SerpApiTools -from phi.llm.anthropic import Claude +from agno.agent import Agent +from agno.tools.serpapi import SerpApiTools +from agno.models.anthropic import Claude from textwrap import dedent # Set up the Streamlit app @@ -15,9 +15,9 @@ anthropic_api_key = st.text_input("Enter Anthropic API Key to access Claude Sonn serp_api_key = st.text_input("Enter Serp API Key for Search functionality", type="password") if anthropic_api_key and serp_api_key: - script_writer = Assistant( + script_writer = Agent( name="ScriptWriter", - llm=Claude(model="claude-3-5-sonnet-20240620", api_key=anthropic_api_key), + model=Claude(id="claude-3-5-sonnet-20240620", api_key=anthropic_api_key), description=dedent( """\ You are an expert screenplay writer. Given a movie idea and genre, @@ -31,9 +31,9 @@ if anthropic_api_key and serp_api_key: ], ) - casting_director = Assistant( + casting_director = Agent( name="CastingDirector", - llm=Claude(model="claude-3-5-sonnet-20240620", api_key=anthropic_api_key), + model=Claude(id="claude-3-5-sonnet-20240620", api_key=anthropic_api_key), description=dedent( """\ You are a talented casting director. Given a script outline and character descriptions, @@ -49,9 +49,9 @@ if anthropic_api_key and serp_api_key: tools=[SerpApiTools(api_key=serp_api_key)], ) - movie_producer = Assistant( + movie_producer = Agent( name="MovieProducer", - llm=Claude(model="claude-3-5-sonnet-20240620", api_key=anthropic_api_key), + model=Claude(id="claude-3-5-sonnet-20240620", api_key=anthropic_api_key), team=[script_writer, casting_director], description="Experienced movie producer overseeing script and casting.", instructions=[ diff --git a/ai_agent_tutorials/ai_movie_production_agent/requirements.txt b/ai_agent_tutorials/ai_movie_production_agent/requirements.txt index 2c59945..fc46b55 100644 --- a/ai_agent_tutorials/ai_movie_production_agent/requirements.txt +++ b/ai_agent_tutorials/ai_movie_production_agent/requirements.txt @@ -1,5 +1,5 @@ streamlit -phidata +agno anthropic google-search-results lxml_html_clean \ No newline at end of file diff --git a/ai_agent_tutorials/ai_personal_finance_agent/README.md b/ai_agent_tutorials/ai_personal_finance_agent/README.md index 92683af..c96ae2b 100644 --- a/ai_agent_tutorials/ai_personal_finance_agent/README.md +++ b/ai_agent_tutorials/ai_personal_finance_agent/README.md @@ -12,6 +12,7 @@ This Streamlit app is an AI-powered personal finance planner that generates pers ```bash git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git +cd awesome-llm-apps/ai_agent_tutorials/ai_personal_finance_agent ``` 2. Install the required dependencies: diff --git a/ai_agent_tutorials/ai_personal_finance_agent/finance_agent.py b/ai_agent_tutorials/ai_personal_finance_agent/finance_agent.py index 55be0a4..4d59936 100644 --- a/ai_agent_tutorials/ai_personal_finance_agent/finance_agent.py +++ b/ai_agent_tutorials/ai_personal_finance_agent/finance_agent.py @@ -1,8 +1,8 @@ from textwrap import dedent -from phi.assistant import Assistant -from phi.tools.serpapi_tools import SerpApiTools +from agno.agent import Agent +from agno.tools.serpapi import SerpApiTools import streamlit as st -from phi.llm.openai import OpenAIChat +from agno.models.openai import OpenAIChat # Set up the Streamlit app st.title("AI Personal Finance Planner ๐ฐ") @@ -15,10 +15,10 @@ openai_api_key = st.text_input("Enter OpenAI API Key to access GPT-4o", type="pa serp_api_key = st.text_input("Enter Serp API Key for Search functionality", type="password") if openai_api_key and serp_api_key: - researcher = Assistant( + researcher = Agent( name="Researcher", role="Searches for financial advice, investment opportunities, and savings strategies based on user preferences", - llm=OpenAIChat(model="gpt-4o", api_key=openai_api_key), + model=OpenAIChat(id="gpt-4o", api_key=openai_api_key), description=dedent( """\ You are a world-class financial researcher. Given a user's financial goals and current financial situation, @@ -35,10 +35,10 @@ if openai_api_key and serp_api_key: tools=[SerpApiTools(api_key=serp_api_key)], add_datetime_to_instructions=True, ) - planner = Assistant( + planner = Agent( name="Planner", role="Generates a personalized financial plan based on user preferences and research results", - llm=OpenAIChat(model="gpt-4o", api_key=openai_api_key), + model=OpenAIChat(id="gpt-4o", api_key=openai_api_key), description=dedent( """\ You are a senior financial planner. Given a user's financial goals, current financial situation, and a list of research results, @@ -54,8 +54,6 @@ if openai_api_key and serp_api_key: "Never make up facts or plagiarize. Always provide proper attribution.", ], add_datetime_to_instructions=True, - add_chat_history_to_prompt=True, - num_history_messages=3, ) # Input fields for the user's financial goals and current financial situation @@ -66,4 +64,4 @@ if openai_api_key and serp_api_key: with st.spinner("Processing..."): # Get the response from the assistant response = planner.run(f"Financial goals: {financial_goals}, Current situation: {current_situation}", stream=False) - st.write(response) + st.write(response.content) diff --git a/ai_agent_tutorials/ai_personal_finance_agent/requirements.txt b/ai_agent_tutorials/ai_personal_finance_agent/requirements.txt index 549573b..ffff278 100644 --- a/ai_agent_tutorials/ai_personal_finance_agent/requirements.txt +++ b/ai_agent_tutorials/ai_personal_finance_agent/requirements.txt @@ -1,4 +1,4 @@ streamlit -phidata +agno openai google-search-results \ No newline at end of file diff --git a/ai_agent_tutorials/ai_real_estate_agent/README.md b/ai_agent_tutorials/ai_real_estate_agent/README.md new file mode 100644 index 0000000..c9e9f44 --- /dev/null +++ b/ai_agent_tutorials/ai_real_estate_agent/README.md @@ -0,0 +1,61 @@ +## ๐ AI Real Estate Agent - Powered by Firecrawl's Extract Endpoint + +The AI Real Estate Agent automates property search and market analysis using Firecrawl's Extract endpoint and Agno AI Agent's insights. It helps users find properties matching their criteria while providing detailed location trends and investment recommendations. This agent streamlines the property search process by combining data from multiple real estate websites and offering intelligent analysis. + +### Features +- **Smart Property Search**: Uses Firecrawl's Extract endpoint to find properties across multiple real estate websites +- **Multi-Source Integration**: Aggregates data from 99acres, Housing.com, Square Yards, Nobroker, and MagicBricks +- **Location Analysis**: Provides detailed price trends and investment insights for different localities +- **AI-Powered Recommendations**: Uses GPT models to analyze properties and provide structured recommendations +- **User-Friendly Interface**: Clean Streamlit UI for easy property search and results viewing +- **Customizable Search**: Filter by city, property type, category, and budget + +### How to Get Started +1. **Clone the repository**: + ```bash + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd ai_agent_tutorials/ai_real_estate_agent + ``` + +2. **Install the required packages**: + ```bash + pip install -r requirements.txt + ``` + +3. **Set up your API keys**: + - Get your Firecrawl API key from [Firecrawl's website](https://www.firecrawl.dev/app/api-keys) + - Get your OpenAI API key from [OpenAI's website](https://platform.openai.com/api-keys) + +4. **Run the application**: + ```bash + streamlit run ai_real_estate_agent.py + ``` + +### Using the Agent +1. **Enter API Keys**: + - Input your Firecrawl and OpenAI API keys in the sidebar + - Keys are securely stored in the session state + +2. **Set Search Criteria**: + - Enter the city name + - Select property category (Residential/Commercial) + - Choose property type (Flat/Individual House) + - Set maximum budget in Crores + +3. **View Results**: + - Property recommendations with detailed analysis + - Location trends with investment insights + - Expandable sections for easy reading + +### Features in Detail +- **Property Finding**: + - Searches across multiple real estate websites + - Returns 3-6 properties matching criteria + - Provides detailed property information and analysis + +- **Location Analysis**: + - Price trends for different localities + - Rental yield analysis + - Investment potential assessment + - Top performing areas identification + diff --git a/ai_agent_tutorials/ai_real_estate_agent/ai_real_estate_agent.py b/ai_agent_tutorials/ai_real_estate_agent/ai_real_estate_agent.py new file mode 100644 index 0000000..f9b65d2 --- /dev/null +++ b/ai_agent_tutorials/ai_real_estate_agent/ai_real_estate_agent.py @@ -0,0 +1,321 @@ +from typing import Dict, List +from pydantic import BaseModel, Field +from agno.agent import Agent +from agno.models.openai import OpenAIChat +from firecrawl import FirecrawlApp +import streamlit as st + +class PropertyData(BaseModel): + """Schema for property data extraction""" + building_name: str = Field(description="Name of the building/property", alias="Building_name") + property_type: str = Field(description="Type of property (commercial, residential, etc)", alias="Property_type") + location_address: str = Field(description="Complete address of the property") + price: str = Field(description="Price of the property", alias="Price") + description: str = Field(description="Detailed description of the property", alias="Description") + +class PropertiesResponse(BaseModel): + """Schema for multiple properties response""" + properties: List[PropertyData] = Field(description="List of property details") + +class LocationData(BaseModel): + """Schema for location price trends""" + location: str + price_per_sqft: float + percent_increase: float + rental_yield: float + +class LocationsResponse(BaseModel): + """Schema for multiple locations response""" + locations: List[LocationData] = Field(description="List of location data points") + +class FirecrawlResponse(BaseModel): + """Schema for Firecrawl API response""" + success: bool + data: Dict + status: str + expiresAt: str + +class PropertyFindingAgent: + """Agent responsible for finding properties and providing recommendations""" + + def __init__(self, firecrawl_api_key: str, openai_api_key: str, model_id: str = "o3-mini"): + self.agent = Agent( + model=OpenAIChat(id=model_id, api_key=openai_api_key), + markdown=True, + description="I am a real estate expert who helps find and analyze properties based on user preferences." + ) + self.firecrawl = FirecrawlApp(api_key=firecrawl_api_key) + + def find_properties( + self, + city: str, + max_price: float, + property_category: str = "Residential", + property_type: str = "Flat" + ) -> str: + """Find and analyze properties based on user preferences""" + formatted_location = city.lower() + + urls = [ + f"https://www.squareyards.com/sale/property-for-sale-in-{formatted_location}/*", + f"https://www.99acres.com/property-in-{formatted_location}-ffid/*", + f"https://housing.com/in/buy/{formatted_location}/{formatted_location}", + # f"https://www.nobroker.in/property/sale/{city}/{formatted_location}", + ] + + property_type_prompt = "Flats" if property_type == "Flat" else "Individual Houses" + + raw_response = self.firecrawl.extract( + urls=urls, + params={ + 'prompt': f"""Extract ONLY 10 OR LESS different {property_category} {property_type_prompt} from {city} that cost less than {max_price} crores. + + Requirements: + - Property Category: {property_category} properties only + - Property Type: {property_type_prompt} only + - Location: {city} + - Maximum Price: {max_price} crores + - Include complete property details with exact location + - IMPORTANT: Return data for at least 3 different properties. MAXIMUM 10. + - Format as a list of properties with their respective details + """, + 'schema': PropertiesResponse.model_json_schema() + } + ) + + print("Raw Property Response:", raw_response) + + if isinstance(raw_response, dict) and raw_response.get('success'): + properties = raw_response['data'].get('properties', []) + else: + properties = [] + + print("Processed Properties:", properties) + + + analysis = self.agent.run( + f"""As a real estate expert, analyze these properties and market trends: + + Properties Found in json format: + {properties} + + **IMPORTANT INSTRUCTIONS:** + 1. ONLY analyze properties from the above JSON data that match the user's requirements: + - Property Category: {property_category} + - Property Type: {property_type} + - Maximum Price: {max_price} crores + 2. DO NOT create new categories or property types + 3. From the matching properties, select 5-6 properties with prices closest to {max_price} crores + + Please provide your analysis in this format: + + ๐ SELECTED PROPERTIES + โข List only 5-6 best matching properties with prices closest to {max_price} crores + โข For each property include: + - Name and Location + - Price (with value analysis) + - Key Features + - Pros and Cons + + ๐ฐ BEST VALUE ANALYSIS + โข Compare the selected properties based on: + - Price per sq ft + - Location advantage + - Amenities offered + + ๐ LOCATION INSIGHTS + โข Specific advantages of the areas where selected properties are located + + ๐ก RECOMMENDATIONS + โข Top 3 properties from the selection with reasoning + โข Investment potential + โข Points to consider before purchase + + ๐ค NEGOTIATION TIPS + โข Property-specific negotiation strategies + + Format your response in a clear, structured way using the above sections. + """ + ) + + return analysis.content + + def get_location_trends(self, city: str) -> str: + """Get price trends for different localities in the city""" + raw_response = self.firecrawl.extract([ + f"https://www.99acres.com/property-rates-and-price-trends-in-{city.lower()}-prffid/*" + ], { + 'prompt': """Extract price trends data for ALL major localities in the city. + IMPORTANT: + - Return data for at least 5-10 different localities + - Include both premium and affordable areas + - Do not skip any locality mentioned in the source + - Format as a list of locations with their respective data + """, + 'schema': LocationsResponse.model_json_schema(), + }) + + if isinstance(raw_response, dict) and raw_response.get('success'): + locations = raw_response['data'].get('locations', []) + + analysis = self.agent.run( + f"""As a real estate expert, analyze these location price trends for {city}: + + {locations} + + Please provide: + 1. A bullet-point summary of the price trends for each location + 2. Identify the top 3 locations with: + - Highest price appreciation + - Best rental yields + - Best value for money + 3. Investment recommendations: + - Best locations for long-term investment + - Best locations for rental income + - Areas showing emerging potential + 4. Specific advice for investors based on these trends + + Format the response as follows: + + ๐ LOCATION TRENDS SUMMARY + โข [Bullet points for each location] + + ๐ TOP PERFORMING AREAS + โข [Bullet points for best areas] + + ๐ก INVESTMENT INSIGHTS + โข [Bullet points with investment advice] + + ๐ฏ RECOMMENDATIONS + โข [Bullet points with specific recommendations] + """ + ) + + return analysis.content + + return "No price trends data available" + +def create_property_agent(): + """Create PropertyFindingAgent with API keys from session state""" + if 'property_agent' not in st.session_state: + st.session_state.property_agent = PropertyFindingAgent( + firecrawl_api_key=st.session_state.firecrawl_key, + openai_api_key=st.session_state.openai_key, + model_id=st.session_state.model_id + ) + +def main(): + st.set_page_config( + page_title="AI Real Estate Agent", + page_icon="๐ ", + layout="wide" + ) + + with st.sidebar: + st.title("๐ API Configuration") + + st.subheader("๐ค Model Selection") + model_id = st.selectbox( + "Choose OpenAI Model", + options=["o3-mini", "gpt-4o"], + help="Select the AI model to use. Choose gpt-4o if your api doesn't have access to o3-mini" + ) + st.session_state.model_id = model_id + + st.divider() + + st.subheader("๐ API Keys") + firecrawl_key = st.text_input( + "Firecrawl API Key", + type="password", + help="Enter your Firecrawl API key" + ) + openai_key = st.text_input( + "OpenAI API Key", + type="password", + help="Enter your OpenAI API key" + ) + + if firecrawl_key and openai_key: + st.session_state.firecrawl_key = firecrawl_key + st.session_state.openai_key = openai_key + create_property_agent() + + st.title("๐ AI Real Estate Agent") + st.info( + """ + Welcome to the AI Real Estate Agent! + Enter your search criteria below to get property recommendations + and location insights. + """ + ) + + col1, col2 = st.columns(2) + + with col1: + city = st.text_input( + "City", + placeholder="Enter city name (e.g., Bangalore)", + help="Enter the city where you want to search for properties" + ) + + property_category = st.selectbox( + "Property Category", + options=["Residential", "Commercial"], + help="Select the type of property you're interested in" + ) + + with col2: + max_price = st.number_input( + "Maximum Price (in Crores)", + min_value=0.1, + max_value=100.0, + value=5.0, + step=0.1, + help="Enter your maximum budget in Crores" + ) + + property_type = st.selectbox( + "Property Type", + options=["Flat", "Individual House"], + help="Select the specific type of property" + ) + + if st.button("๐ Start Search", use_container_width=True): + if 'property_agent' not in st.session_state: + st.error("โ ๏ธ Please enter your API keys in the sidebar first!") + return + + if not city: + st.error("โ ๏ธ Please enter a city name!") + return + + try: + with st.spinner("๐ Searching for properties..."): + property_results = st.session_state.property_agent.find_properties( + city=city, + max_price=max_price, + property_category=property_category, + property_type=property_type + ) + + st.success("โ Property search completed!") + + st.subheader("๐๏ธ Property Recommendations") + st.markdown(property_results) + + st.divider() + + with st.spinner("๐ Analyzing location trends..."): + location_trends = st.session_state.property_agent.get_location_trends(city) + + st.success("โ Location analysis completed!") + + with st.expander("๐ Location Trends Analysis of the city"): + st.markdown(location_trends) + + except Exception as e: + st.error(f"โ An error occurred: {str(e)}") + +if __name__ == "__main__": + main() diff --git a/ai_agent_tutorials/ai_real_estate_agent/requirements.txt b/ai_agent_tutorials/ai_real_estate_agent/requirements.txt new file mode 100644 index 0000000..8590901 --- /dev/null +++ b/ai_agent_tutorials/ai_real_estate_agent/requirements.txt @@ -0,0 +1,5 @@ +agno +firecrawl-py==1.9.0 +pydantic +streamlit +openai \ No newline at end of file diff --git a/ai_agent_tutorials/ai_reasoning_agent/README.md b/ai_agent_tutorials/ai_reasoning_agent/README.md new file mode 100644 index 0000000..119bc83 --- /dev/null +++ b/ai_agent_tutorials/ai_reasoning_agent/README.md @@ -0,0 +1,51 @@ +## AI Reasoning Agent + +The AI Reasoning Agent leverages advanced AI models to provide insightful reasoning and decision-making capabilities. This agent is designed to assist users in various analytical tasks by processing information and generating structured outputs. + +### Features +- **Advanced Reasoning**: Utilizes the Ollama model to perform complex reasoning tasks +- **Interactive Playground**: Provides a user-friendly interface for interacting with the reasoning agent +- **Markdown Support**: Outputs results in markdown format for easy readability and sharing +- **Customizable Agent**: Easily configurable to suit different reasoning scenarios + +### How to Get Started +1. **Clone the repository**: + ```bash + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd ai_agent_tutorials/ai_reasoning_agent + ``` + +2. **Install the required packages**: + #### For Local AI Reasoning Agent + ```bash + pip install -r requirements_local_ai_reasoning_agent.txt + ``` + +3. **Run the application**: + ```bash + python local_ai_reasoning_agent.py + ``` + +### Using the Agent +1. **Access the Playground**: + - Open the provided URL to access the interactive playground + - The playground allows you to input queries and receive structured reasoning outputs + +2. **Input Queries**: + - Enter your queries in the provided input field + - The agent processes the input and provides detailed reasoning and analysis + +3. **View Results**: + - Results are displayed in markdown format + - Easily copy and share the outputs for further use + +### Features in Detail +- **Reasoning Capabilities**: + - Handles a wide range of analytical tasks + - Provides clear and structured outputs + - Supports markdown for easy sharing and readability + +- **Interactive Interface**: + - User-friendly playground for seamless interaction + - Real-time processing and output generation + - Configurable settings to tailor the agent's behavior \ No newline at end of file diff --git a/ai_agent_tutorials/ai_reasoning_agent/agents.db b/ai_agent_tutorials/ai_reasoning_agent/agents.db deleted file mode 100644 index c2d3d52..0000000 Binary files a/ai_agent_tutorials/ai_reasoning_agent/agents.db and /dev/null differ diff --git a/ai_agent_tutorials/ai_reasoning_agent/local_ai_reasoning_agent.py b/ai_agent_tutorials/ai_reasoning_agent/local_ai_reasoning_agent.py new file mode 100644 index 0000000..d31910c --- /dev/null +++ b/ai_agent_tutorials/ai_reasoning_agent/local_ai_reasoning_agent.py @@ -0,0 +1,12 @@ +from agno.agent import Agent +from agno.models.ollama import Ollama +from agno.playground import Playground, serve_playground_app + +reasoning_agent = Agent(name="Reasoning Agent", model=Ollama(id="qwq:32b"), markdown=True) + +# UI for Reasoning agent +app = Playground(agents=[reasoning_agent]).get_app() + +# Run the Playground app +if __name__ == "__main__": + serve_playground_app("local_ai_reasoning_agent:app", reload=True) \ No newline at end of file diff --git a/ai_agent_tutorials/ai_reasoning_agent/reasoning_agent.py b/ai_agent_tutorials/ai_reasoning_agent/reasoning_agent.py index 4f55d79..137b5d3 100644 --- a/ai_agent_tutorials/ai_reasoning_agent/reasoning_agent.py +++ b/ai_agent_tutorials/ai_reasoning_agent/reasoning_agent.py @@ -1,9 +1,9 @@ -from phi.agent import Agent -from phi.model.openai import OpenAIChat -from phi.cli.console import console +from agno.agent import Agent +from agno.models.openai import OpenAIChat +from rich.console import Console regular_agent = Agent(model=OpenAIChat(id="gpt-4o-mini"), markdown=True) - +console = Console() reasoning_agent = Agent( model=OpenAIChat(id="gpt-4o"), reasoning=True, diff --git a/ai_agent_tutorials/ai_reasoning_agent/requirements.txt b/ai_agent_tutorials/ai_reasoning_agent/requirements.txt new file mode 100644 index 0000000..88c5c83 --- /dev/null +++ b/ai_agent_tutorials/ai_reasoning_agent/requirements.txt @@ -0,0 +1,4 @@ +agno +ollama +fastapi +uvicorn \ No newline at end of file diff --git a/ai_agent_tutorials/ai_recruitment_agent_team/README.md b/ai_agent_tutorials/ai_recruitment_agent_team/README.md new file mode 100644 index 0000000..55c48dd --- /dev/null +++ b/ai_agent_tutorials/ai_recruitment_agent_team/README.md @@ -0,0 +1,101 @@ +# ๐ผ AI Recruitment Agent Team + +A Streamlit application that simulates a full-service recruitment team using multiple AI agents to automate and streamline the hiring process. Each agent represents a different recruitment specialist role - from resume analysis and candidate evaluation to interview scheduling and communication - working together to provide comprehensive hiring solutions. The system combines the expertise of technical recruiters, HR coordinators, and scheduling specialists into a cohesive automated workflow. + +## Features + +#### Specialized AI Agents + +- Technical Recruiter Agent: Analyzes resumes and evaluates technical skills +- Communication Agent: Handles professional email correspondence +- Scheduling Coordinator Agent: Manages interview scheduling and coordination +- Each agent has specific expertise and collaborates for comprehensive recruitment + + +#### End-to-End Recruitment Process +- Automated resume screening and analysis +- Role-specific technical evaluation +- Professional candidate communication +- Automated interview scheduling +- Integrated feedback system + +## Important Things to do before running the application + +- Create/Use a new Gmail account for the recruiter +- Enable 2-Step Verification and generate an App Password for the Gmail account +- The App Password is a 16 digit code (use without spaces) that should be generated here - [Google App Password](https://support.google.com/accounts/answer/185833?hl=en) Please go through the steps to generate the password - it will of the format - 'afec wejf awoj fwrv' (remove the spaces and enter it in the streamlit app) +- Create/ Use a Zoom account and go to the Zoom App Marketplace to get the API credentials : +[Zoom Marketplace](https://marketplace.zoom.us) +- Go to Developer Dashboard and create a new app - Select Server to Server OAuth and get the credentials, You see 3 credentials - Client ID, Client Secret and Account ID +- After that, you need to add a few scopes to the app - so that the zoom link of the candidate is sent and created through the mail. +- The Scopes are meeting:write:invite_links:admin, meeting:write:meeting:admin, meeting:write:meeting:master, meeting:write:invite_links:master, meeting:write:open_app:admin, user:read:email:admin, user:read:list_users:admin, billing:read:user_entitlement:admin, dashboard:read:list_meeting_participants:admin [last 3 are optional] + +## How to Run + +1. **Setup Environment** + ```bash + # Clone the repository + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd ai_agent_tutorials/ai_recruitment_agent_team + + # Install dependencies + pip install -r requirements.txt + ``` + +2. **Configure API Keys** + - OpenAI API key for GPT-4o access + - Zoom API credentials (Account ID, Client ID, Client Secret) + - Email App Password of Recruiter's Email + +3. **Run the Application** + ```bash + streamlit run ai_recruitment_agent_team.py + ``` + +## System Components + +- **Resume Analyzer Agent** + - Skills matching algorithm + - Experience verification + - Technical assessment + - Selection decision making + +- **Email Communication Agent** + - Professional email drafting + - Automated notifications + - Feedback communication + - Follow-up management + +- **Interview Scheduler Agent** + - Zoom meeting coordination + - Calendar management + - Timezone handling + - Reminder system + +- **Candidate Experience** + - Simple upload interface + - Real-time feedback + - Clear communication + - Streamlined process + +## Technical Stack + +- **Framework**: Phidata +- **Model**: OpenAI GPT-4o +- **Integration**: Zoom API, EmailTools Tool from Phidata +- **PDF Processing**: PyPDF2 +- **Time Management**: pytz +- **State Management**: Streamlit Session State + + +## Disclaimer + +This tool is designed to assist in the recruitment process but should not completely replace human judgment in hiring decisions. All automated decisions should be reviewed by human recruiters for final approval. + +## Future Enhancements + +- Integration with ATS systems +- Advanced candidate scoring +- Video interview capabilities +- Skills assessment integration +- Multi-language support diff --git a/ai_agent_tutorials/ai_recruitment_agent_team/ai_recruitment_agent_team.py b/ai_agent_tutorials/ai_recruitment_agent_team/ai_recruitment_agent_team.py new file mode 100644 index 0000000..59e56dc --- /dev/null +++ b/ai_agent_tutorials/ai_recruitment_agent_team/ai_recruitment_agent_team.py @@ -0,0 +1,521 @@ +from typing import Literal, Tuple, Dict, Optional +import os +import time +import json +import requests +import PyPDF2 +from datetime import datetime, timedelta +import pytz + +import streamlit as st +from agno.agent import Agent +from agno.models.openai import OpenAIChat +from agno.tools.email import EmailTools +from phi.tools.zoom import ZoomTool +from phi.utils.log import logger +from streamlit_pdf_viewer import pdf_viewer + + + +class CustomZoomTool(ZoomTool): + def __init__(self, *, account_id: Optional[str] = None, client_id: Optional[str] = None, client_secret: Optional[str] = None, name: str = "zoom_tool"): + super().__init__(account_id=account_id, client_id=client_id, client_secret=client_secret, name=name) + self.token_url = "https://zoom.us/oauth/token" + self.access_token = None + self.token_expires_at = 0 + + def get_access_token(self) -> str: + if self.access_token and time.time() < self.token_expires_at: + return str(self.access_token) + + headers = {"Content-Type": "application/x-www-form-urlencoded"} + data = {"grant_type": "account_credentials", "account_id": self.account_id} + + try: + response = requests.post(self.token_url, headers=headers, data=data, auth=(self.client_id, self.client_secret)) + response.raise_for_status() + + token_info = response.json() + self.access_token = token_info["access_token"] + expires_in = token_info["expires_in"] + self.token_expires_at = time.time() + expires_in - 60 + + self._set_parent_token(str(self.access_token)) + return str(self.access_token) + + except requests.RequestException as e: + logger.error(f"Error fetching access token: {e}") + return "" + + def _set_parent_token(self, token: str) -> None: + """Helper method to set the token in the parent ZoomTool class""" + if token: + self._ZoomTool__access_token = token + + +# Role requirements as a constant dictionary +ROLE_REQUIREMENTS: Dict[str, str] = { + "ai_ml_engineer": """ + Required Skills: + - Python, PyTorch/TensorFlow + - Machine Learning algorithms and frameworks + - Deep Learning and Neural Networks + - Data preprocessing and analysis + - MLOps and model deployment + - RAG, LLM, Finetuning and Prompt Engineering + """, + + "frontend_engineer": """ + Required Skills: + - React/Vue.js/Angular + - HTML5, CSS3, JavaScript/TypeScript + - Responsive design + - State management + - Frontend testing + """, + + "backend_engineer": """ + Required Skills: + - Python/Java/Node.js + - REST APIs + - Database design and management + - System architecture + - Cloud services (AWS/GCP/Azure) + - Kubernetes, Docker, CI/CD + """ +} + + +def init_session_state() -> None: + """Initialize only necessary session state variables.""" + defaults = { + 'candidate_email': "", 'openai_api_key': "", 'resume_text': "", 'analysis_complete': False, + 'is_selected': False, 'zoom_account_id': "", 'zoom_client_id': "", 'zoom_client_secret': "", + 'email_sender': "", 'email_passkey': "", 'company_name': "", 'current_pdf': None + } + for key, value in defaults.items(): + if key not in st.session_state: + st.session_state[key] = value + + +def create_resume_analyzer() -> Agent: + """Creates and returns a resume analysis agent.""" + if not st.session_state.openai_api_key: + st.error("Please enter your OpenAI API key first.") + return None + + return Agent( + model=OpenAIChat( + id="gpt-4o", + api_key=st.session_state.openai_api_key + ), + description="You are an expert technical recruiter who analyzes resumes.", + instructions=[ + "Analyze the resume against the provided job requirements", + "Be lenient with AI/ML candidates who show strong potential", + "Consider project experience as valid experience", + "Value hands-on experience with key technologies", + "Return a JSON response with selection decision and feedback" + ], + markdown=True + ) + +def create_email_agent() -> Agent: + return Agent( + model=OpenAIChat( + id="gpt-4o", + api_key=st.session_state.openai_api_key + ), + tools=[EmailTools( + receiver_email=st.session_state.candidate_email, + sender_email=st.session_state.email_sender, + sender_name=st.session_state.company_name, + sender_passkey=st.session_state.email_passkey + )], + description="You are a professional recruitment coordinator handling email communications.", + instructions=[ + "Draft and send professional recruitment emails", + "Act like a human writing an email and use all lowercase letters", + "Maintain a friendly yet professional tone", + "Always end emails with exactly: 'best,\nthe ai recruiting team'", + "Never include the sender's or receiver's name in the signature", + f"The name of the company is '{st.session_state.company_name}'" + ], + markdown=True, + show_tool_calls=True + ) + + +def create_scheduler_agent() -> Agent: + zoom_tools = CustomZoomTool( + account_id=st.session_state.zoom_account_id, + client_id=st.session_state.zoom_client_id, + client_secret=st.session_state.zoom_client_secret + ) + + return Agent( + name="Interview Scheduler", + model=OpenAIChat( + id="gpt-4o", + api_key=st.session_state.openai_api_key + ), + tools=[zoom_tools], + description="You are an interview scheduling coordinator.", + instructions=[ + "You are an expert at scheduling technical interviews using Zoom.", + "Schedule interviews during business hours (9 AM - 5 PM EST)", + "Create meetings with proper titles and descriptions", + "Ensure all meeting details are included in responses", + "Use ISO 8601 format for dates", + "Handle scheduling errors gracefully" + ], + markdown=True, + show_tool_calls=True + ) + + +def extract_text_from_pdf(pdf_file) -> str: + try: + pdf_reader = PyPDF2.PdfReader(pdf_file) + text = "" + for page in pdf_reader.pages: + text += page.extract_text() + return text + except Exception as e: + st.error(f"Error extracting PDF text: {str(e)}") + return "" + + +def analyze_resume( + resume_text: str, + role: Literal["ai_ml_engineer", "frontend_engineer", "backend_engineer"], + analyzer: Agent +) -> Tuple[bool, str]: + try: + response = analyzer.run( + f"""Please analyze this resume against the following requirements and provide your response in valid JSON format: + Role Requirements: + {ROLE_REQUIREMENTS[role]} + Resume Text: + {resume_text} + Your response must be a valid JSON object like this: + {{ + "selected": true/false, + "feedback": "Detailed feedback explaining the decision", + "matching_skills": ["skill1", "skill2"], + "missing_skills": ["skill3", "skill4"], + "experience_level": "junior/mid/senior" + }} + Evaluation criteria: + 1. Match at least 70% of required skills + 2. Consider both theoretical knowledge and practical experience + 3. Value project experience and real-world applications + 4. Consider transferable skills from similar technologies + 5. Look for evidence of continuous learning and adaptability + Important: Return ONLY the JSON object without any markdown formatting or backticks. + """ + ) + + assistant_message = next((msg.content for msg in response.messages if msg.role == 'assistant'), None) + if not assistant_message: + raise ValueError("No assistant message found in response.") + + result = json.loads(assistant_message.strip()) + if not isinstance(result, dict) or not all(k in result for k in ["selected", "feedback"]): + raise ValueError("Invalid response format") + + return result["selected"], result["feedback"] + + except (json.JSONDecodeError, ValueError) as e: + st.error(f"Error processing response: {str(e)}") + return False, f"Error analyzing resume: {str(e)}" + + +def send_selection_email(email_agent: Agent, to_email: str, role: str) -> None: + email_agent.run( + f""" + Send an email to {to_email} regarding their selection for the {role} position. + The email should: + 1. Congratulate them on being selected + 2. Explain the next steps in the process + 3. Mention that they will receive interview details shortly + 4. The name of the company is 'AI Recruiting Team' + """ + ) + + +def send_rejection_email(email_agent: Agent, to_email: str, role: str, feedback: str) -> None: + """ + Send a rejection email with constructive feedback. + """ + email_agent.run( + f""" + Send an email to {to_email} regarding their application for the {role} position. + Use this specific style: + 1. use all lowercase letters + 2. be empathetic and human + 3. mention specific feedback from: {feedback} + 4. encourage them to upskill and try again + 5. suggest some learning resources based on missing skills + 6. end the email with exactly: + best, + the ai recruiting team + + Do not include any names in the signature. + The tone should be like a human writing a quick but thoughtful email. + """ + ) + + +def schedule_interview(scheduler: Agent, candidate_email: str, email_agent: Agent, role: str) -> None: + """ + Schedule interviews during business hours (9 AM - 5 PM IST). + """ + try: + # Get current time in IST + ist_tz = pytz.timezone('Asia/Kolkata') + current_time_ist = datetime.now(ist_tz) + + tomorrow_ist = current_time_ist + timedelta(days=1) + interview_time = tomorrow_ist.replace(hour=11, minute=0, second=0, microsecond=0) + formatted_time = interview_time.strftime('%Y-%m-%dT%H:%M:%S') + + meeting_response = scheduler.run( + f"""Schedule a 60-minute technical interview with these specifications: + - Title: '{role} Technical Interview' + - Date: {formatted_time} + - Timezone: IST (India Standard Time) + - Attendee: {candidate_email} + + Important Notes: + - The meeting must be between 9 AM - 5 PM IST + - Use IST (UTC+5:30) timezone for all communications + - Include timezone information in the meeting details + """ + ) + + email_agent.run( + f"""Send an interview confirmation email with these details: + - Role: {role} position + - Meeting Details: {meeting_response} + + Important: + - Clearly specify that the time is in IST (India Standard Time) + - Ask the candidate to join 5 minutes early + - Include timezone conversion link if possible + - Ask him to be confident and not so nervous and prepare well for the interview + """ + ) + + st.success("Interview scheduled successfully! Check your email for details.") + + except Exception as e: + logger.error(f"Error scheduling interview: {str(e)}") + st.error("Unable to schedule interview. Please try again.") + + +def main() -> None: + st.title("AI Recruitment System") + + init_session_state() + with st.sidebar: + st.header("Configuration") + + # OpenAI Configuration + st.subheader("OpenAI Settings") + api_key = st.text_input("OpenAI API Key", type="password", value=st.session_state.openai_api_key, help="Get your API key from platform.openai.com") + if api_key: st.session_state.openai_api_key = api_key + + st.subheader("Zoom Settings") + zoom_account_id = st.text_input("Zoom Account ID", type="password", value=st.session_state.zoom_account_id) + zoom_client_id = st.text_input("Zoom Client ID", type="password", value=st.session_state.zoom_client_id) + zoom_client_secret = st.text_input("Zoom Client Secret", type="password", value=st.session_state.zoom_client_secret) + + st.subheader("Email Settings") + email_sender = st.text_input("Sender Email", value=st.session_state.email_sender, help="Email address to send from") + email_passkey = st.text_input("Email App Password", type="password", value=st.session_state.email_passkey, help="App-specific password for email") + company_name = st.text_input("Company Name", value=st.session_state.company_name, help="Name to use in email communications") + + if zoom_account_id: st.session_state.zoom_account_id = zoom_account_id + if zoom_client_id: st.session_state.zoom_client_id = zoom_client_id + if zoom_client_secret: st.session_state.zoom_client_secret = zoom_client_secret + if email_sender: st.session_state.email_sender = email_sender + if email_passkey: st.session_state.email_passkey = email_passkey + if company_name: st.session_state.company_name = company_name + + required_configs = {'OpenAI API Key': st.session_state.openai_api_key, 'Zoom Account ID': st.session_state.zoom_account_id, + 'Zoom Client ID': st.session_state.zoom_client_id, 'Zoom Client Secret': st.session_state.zoom_client_secret, + 'Email Sender': st.session_state.email_sender, 'Email Password': st.session_state.email_passkey, + 'Company Name': st.session_state.company_name} + + missing_configs = [k for k, v in required_configs.items() if not v] + if missing_configs: + st.warning(f"Please configure the following in the sidebar: {', '.join(missing_configs)}") + return + + if not st.session_state.openai_api_key: + st.warning("Please enter your OpenAI API key in the sidebar to continue.") + return + + role = st.selectbox("Select the role you're applying for:", ["ai_ml_engineer", "frontend_engineer", "backend_engineer"]) + with st.expander("View Required Skills", expanded=True): st.markdown(ROLE_REQUIREMENTS[role]) + + # Add a "New Application" button before the resume upload + if st.button("๐ New Application"): + # Clear only the application-related states + keys_to_clear = ['resume_text', 'analysis_complete', 'is_selected', 'candidate_email', 'current_pdf'] + for key in keys_to_clear: + if key in st.session_state: + st.session_state[key] = None if key == 'current_pdf' else "" + st.rerun() + + resume_file = st.file_uploader("Upload your resume (PDF)", type=["pdf"], key="resume_uploader") + if resume_file is not None and resume_file != st.session_state.get('current_pdf'): + st.session_state.current_pdf = resume_file + st.session_state.resume_text = "" + st.session_state.analysis_complete = False + st.session_state.is_selected = False + st.rerun() + + if resume_file: + st.subheader("Uploaded Resume") + col1, col2 = st.columns([4, 1]) + + with col1: + import tempfile, os + with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file: + tmp_file.write(resume_file.read()) + tmp_file_path = tmp_file.name + resume_file.seek(0) + try: pdf_viewer(tmp_file_path) + finally: os.unlink(tmp_file_path) + + with col2: + st.download_button(label="๐ฅ Download", data=resume_file, file_name=resume_file.name, mime="application/pdf") + # Process the resume text + if not st.session_state.resume_text: + with st.spinner("Processing your resume..."): + resume_text = extract_text_from_pdf(resume_file) + if resume_text: + st.session_state.resume_text = resume_text + st.success("Resume processed successfully!") + else: + st.error("Could not process the PDF. Please try again.") + + # Email input with session state + email = st.text_input( + "Candidate's email address", + value=st.session_state.candidate_email, + key="email_input" + ) + st.session_state.candidate_email = email + + # Analysis and next steps + if st.session_state.resume_text and email and not st.session_state.analysis_complete: + if st.button("Analyze Resume"): + with st.spinner("Analyzing your resume..."): + resume_analyzer = create_resume_analyzer() + email_agent = create_email_agent() # Create email agent here + + if resume_analyzer and email_agent: + print("DEBUG: Starting resume analysis") + is_selected, feedback = analyze_resume( + st.session_state.resume_text, + role, + resume_analyzer + ) + print(f"DEBUG: Analysis complete - Selected: {is_selected}, Feedback: {feedback}") + + if is_selected: + st.success("Congratulations! Your skills match our requirements.") + st.session_state.analysis_complete = True + st.session_state.is_selected = True + st.rerun() + else: + st.warning("Unfortunately, your skills don't match our requirements.") + st.write(f"Feedback: {feedback}") + + # Send rejection email + with st.spinner("Sending feedback email..."): + try: + send_rejection_email( + email_agent=email_agent, + to_email=email, + role=role, + feedback=feedback + ) + st.info("We've sent you an email with detailed feedback.") + except Exception as e: + logger.error(f"Error sending rejection email: {e}") + st.error("Could not send feedback email. Please try again.") + + if st.session_state.get('analysis_complete') and st.session_state.get('is_selected', False): + st.success("Congratulations! Your skills match our requirements.") + st.info("Click 'Proceed with Application' to continue with the interview process.") + + if st.button("Proceed with Application", key="proceed_button"): + print("DEBUG: Proceed button clicked") # Debug + with st.spinner("๐ Processing your application..."): + try: + print("DEBUG: Creating email agent") # Debug + email_agent = create_email_agent() + print(f"DEBUG: Email agent created: {email_agent}") # Debug + + print("DEBUG: Creating scheduler agent") # Debug + scheduler_agent = create_scheduler_agent() + print(f"DEBUG: Scheduler agent created: {scheduler_agent}") # Debug + + # 3. Send selection email + with st.status("๐ง Sending confirmation email...", expanded=True) as status: + print(f"DEBUG: Attempting to send email to {st.session_state.candidate_email}") # Debug + send_selection_email( + email_agent, + st.session_state.candidate_email, + role + ) + print("DEBUG: Email sent successfully") # Debug + status.update(label="โ Confirmation email sent!") + + # 4. Schedule interview + with st.status("๐ Scheduling interview...", expanded=True) as status: + print("DEBUG: Attempting to schedule interview") # Debug + schedule_interview( + scheduler_agent, + st.session_state.candidate_email, + email_agent, + role + ) + print("DEBUG: Interview scheduled successfully") # Debug + status.update(label="โ Interview scheduled!") + + print("DEBUG: All processes completed successfully") # Debug + st.success(""" + ๐ Application Successfully Processed! + + Please check your email for: + 1. Selection confirmation โ + 2. Interview details with Zoom link ๐ + + Next steps: + 1. Review the role requirements + 2. Prepare for your technical interview + 3. Join the interview 5 minutes early + """) + + except Exception as e: + print(f"DEBUG: Error occurred: {str(e)}") # Debug + print(f"DEBUG: Error type: {type(e)}") # Debug + import traceback + print(f"DEBUG: Full traceback: {traceback.format_exc()}") # Debug + st.error(f"An error occurred: {str(e)}") + st.error("Please try again or contact support.") + + # Reset button + if st.sidebar.button("Reset Application"): + for key in st.session_state.keys(): + if key != 'openai_api_key': + del st.session_state[key] + st.rerun() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ai_agent_tutorials/ai_recruitment_agent_team/requirements.txt b/ai_agent_tutorials/ai_recruitment_agent_team/requirements.txt new file mode 100644 index 0000000..caaaa4e --- /dev/null +++ b/ai_agent_tutorials/ai_recruitment_agent_team/requirements.txt @@ -0,0 +1,13 @@ +# Core dependencies +phidata +agno +streamlit==1.40.2 +PyPDF2==3.0.1 +streamlit-pdf-viewer==0.0.19 +requests==2.32.3 +pytz==2023.4 +typing-extensions>=4.9.0 + +# Optional but recommended +black>=24.1.1 # for code formatting +python-dateutil>=2.8.2 # for date parsing diff --git a/ai_agent_tutorials/ai_services_agency/README.md b/ai_agent_tutorials/ai_services_agency/README.md new file mode 100644 index 0000000..4003cea --- /dev/null +++ b/ai_agent_tutorials/ai_services_agency/README.md @@ -0,0 +1,80 @@ +# AI Services Agency ๐จโ๐ผ + +An AI application that simulates a full-service digital agency using multiple AI agents to analyze and plan software projects. Each agent represents a different role in the project lifecycle, from strategic planning to technical implementation. + +## Demo: + +https://github.com/user-attachments/assets/a0befa3a-f4c3-400d-9790-4b9e37254405 + +## Features + +### Five specialized AI agents + +- **CEO Agent**: Strategic leader and final decision maker + - Analyzes startup ideas using structured evaluation + - Makes strategic decisions across product, technical, marketing, and financial domains + - Uses AnalyzeStartupTool and MakeStrategicDecision tools + +- **CTO Agent**: Technical architecture and feasibility expert + - Evaluates technical requirements and feasibility + - Provides architecture decisions + - Uses QueryTechnicalRequirements and EvaluateTechnicalFeasibility tools + +- **Product Manager Agent**: Product strategy specialist + - Defines product strategy and roadmap + - Coordinates between technical and marketing teams + - Focuses on product-market fit + +- **Developer Agent**: Technical implementation expert + - Provides detailed technical implementation guidance + - Suggests optimal tech stack and cloud solutions + - Estimates development costs and timelines + +- **Client Success Agent**: Marketing strategy leader + - Develops go-to-market strategies + - Plans customer acquisition approaches + - Coordinates with product team + +### Custom Tools + +The agency uses specialized tools built with OpenAI Schema for structured analysis: +- **Analysis Tools**: AnalyzeProjectRequirements for market evaluation and analysis of startup idea +- **Technical Tools**: CreateTechnicalSpecification for technical assessment + +### ๐ Asynchronous Communication + +The agency operates in async mode, enabling: +- Parallel processing of analyses from different agents +- Efficient multi-agent collaboration +- Real-time communication between agents +- Non-blocking operations for better performance + +### ๐ Agent Communication Flows +- CEO โ๏ธ All Agents (Strategic Oversight) +- CTO โ๏ธ Developer (Technical Implementation) +- Product Manager โ๏ธ Marketing Manager (Go-to-Market Strategy) +- Product Manager โ๏ธ Developer (Feature Implementation) +- (and more!) + +## How to Run + +Follow the steps below to set up and run the application: +Before anything else, Please get your OpenAI API Key here: https://platform.openai.com/api-keys + +1. **Clone the Repository**: + ```bash + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd awesome-llm-apps/ai_agent_tutorials/ai_services_agency + ``` + +2. **Install the dependencies**: + ```bash + pip install -r requirements.txt + ``` + +3. **Run the Streamlit app**: + ```bash + streamlit run ai_services_agency/agency.py + ``` + +4. **Enter your OpenAI API Key** in the sidebar when prompted and start analyzing your startup idea! diff --git a/ai_agent_tutorials/ai_services_agency/agency.py b/ai_agent_tutorials/ai_services_agency/agency.py new file mode 100644 index 0000000..43ab885 --- /dev/null +++ b/ai_agent_tutorials/ai_services_agency/agency.py @@ -0,0 +1,365 @@ +from typing import List, Literal, Dict, Optional +from agency_swarm import Agent, Agency, set_openai_key, BaseTool +from pydantic import Field, BaseModel +import streamlit as st + +class AnalyzeProjectRequirements(BaseTool): + project_name: str = Field(..., description="Name of the project") + project_description: str = Field(..., description="Project description and goals") + project_type: Literal["Web Application", "Mobile App", "API Development", + "Data Analytics", "AI/ML Solution", "Other"] = Field(..., + description="Type of project") + budget_range: Literal["$10k-$25k", "$25k-$50k", "$50k-$100k", "$100k+"] = Field(..., + description="Budget range for the project") + + class ToolConfig: + name = "analyze_project" + description = "Analyzes project requirements and feasibility" + one_call_at_a_time = True + + def run(self) -> str: + """Analyzes project and stores results in shared state""" + if self._shared_state.get("project_analysis", None) is not None: + raise ValueError("Project analysis already exists. Please proceed with technical specification.") + + analysis = { + "name": self.project_name, + "type": self.project_type, + "complexity": "high", + "timeline": "6 months", + "budget_feasibility": "within range", + "requirements": ["Scalable architecture", "Security", "API integration"] + } + + self._shared_state.set("project_analysis", analysis) + return "Project analysis completed. Please proceed with technical specification." + +class CreateTechnicalSpecification(BaseTool): + architecture_type: Literal["monolithic", "microservices", "serverless", "hybrid"] = Field( + ..., + description="Proposed architecture type" + ) + core_technologies: str = Field( + ..., + description="Comma-separated list of main technologies and frameworks" + ) + scalability_requirements: Literal["high", "medium", "low"] = Field( + ..., + description="Scalability needs" + ) + + class ToolConfig: + name = "create_technical_spec" + description = "Creates technical specifications based on project analysis" + one_call_at_a_time = True + + def run(self) -> str: + """Creates technical specification based on analysis""" + project_analysis = self._shared_state.get("project_analysis", None) + if project_analysis is None: + raise ValueError("Please analyze project requirements first using AnalyzeProjectRequirements tool.") + + spec = { + "project_name": project_analysis["name"], + "architecture": self.architecture_type, + "technologies": self.core_technologies.split(","), + "scalability": self.scalability_requirements + } + + self._shared_state.set("technical_specification", spec) + return f"Technical specification created for {project_analysis['name']}." + +def init_session_state() -> None: + """Initialize session state variables""" + if 'messages' not in st.session_state: + st.session_state.messages = [] + if 'api_key' not in st.session_state: + st.session_state.api_key = None + +def main() -> None: + st.set_page_config(page_title="AI Services Agency", layout="wide") + init_session_state() + + st.title("๐ AI Services Agency") + + # API Configuration + with st.sidebar: + st.header("๐ API Configuration") + openai_api_key = st.text_input( + "OpenAI API Key", + type="password", + help="Enter your OpenAI API key to continue" + ) + + if openai_api_key: + st.session_state.api_key = openai_api_key + st.success("API Key accepted!") + else: + st.warning("โ ๏ธ Please enter your OpenAI API Key to proceed") + st.markdown("[Get your API key here](https://platform.openai.com/api-keys)") + return + + # Initialize agents with the provided API key + set_openai_key(st.session_state.api_key) + api_headers = {"Authorization": f"Bearer {st.session_state.api_key}"} + + # Project Input Form + with st.form("project_form"): + st.subheader("Project Details") + + project_name = st.text_input("Project Name") + project_description = st.text_area( + "Project Description", + help="Describe the project, its goals, and any specific requirements" + ) + + col1, col2 = st.columns(2) + with col1: + project_type = st.selectbox( + "Project Type", + ["Web Application", "Mobile App", "API Development", + "Data Analytics", "AI/ML Solution", "Other"] + ) + timeline = st.selectbox( + "Expected Timeline", + ["1-2 months", "3-4 months", "5-6 months", "6+ months"] + ) + + with col2: + budget_range = st.selectbox( + "Budget Range", + ["$10k-$25k", "$25k-$50k", "$50k-$100k", "$100k+"] + ) + priority = st.selectbox( + "Project Priority", + ["High", "Medium", "Low"] + ) + + tech_requirements = st.text_area( + "Technical Requirements (optional)", + help="Any specific technical requirements or preferences" + ) + + special_considerations = st.text_area( + "Special Considerations (optional)", + help="Any additional information or special requirements" + ) + + submitted = st.form_submit_button("Analyze Project") + + if submitted and project_name and project_description: + try: + # Set OpenAI key + set_openai_key(st.session_state.api_key) + + # Create agents + ceo = Agent( + name="Project Director", + description="You are a CEO of multiple companies in the past and have a lot of experience in evaluating projects and making strategic decisions.", + instructions=""" + You are an experienced CEO who evaluates projects. Follow these steps strictly: + + 1. FIRST, use the AnalyzeProjectRequirements tool with: + - project_name: The name from the project details + - project_description: The full project description + - project_type: The type of project (Web Application, Mobile App, etc) + - budget_range: The specified budget range + + 2. WAIT for the analysis to complete before proceeding. + + 3. Review the analysis results and provide strategic recommendations. + """, + tools=[AnalyzeProjectRequirements], + api_headers=api_headers, + temperature=0.7, + max_prompt_tokens=25000 + ) + + cto = Agent( + name="Technical Architect", + description="Senior technical architect with deep expertise in system design.", + instructions=""" + You are a technical architect. Follow these steps strictly: + + 1. WAIT for the project analysis to be completed by the CEO. + + 2. Use the CreateTechnicalSpecification tool with: + - architecture_type: Choose from monolithic/microservices/serverless/hybrid + - core_technologies: List main technologies as comma-separated values + - scalability_requirements: Choose high/medium/low based on project needs + + 3. Review the technical specification and provide additional recommendations. + """, + tools=[CreateTechnicalSpecification], + api_headers=api_headers, + temperature=0.5, + max_prompt_tokens=25000 + ) + + product_manager = Agent( + name="Product Manager", + description="Experienced product manager focused on delivery excellence.", + instructions=""" + - Manage project scope and timeline giving the roadmap of the project + - Define product requirements and you should give potential products and features that can be built for the startup + """, + api_headers=api_headers, + temperature=0.4, + max_prompt_tokens=25000 + ) + + developer = Agent( + name="Lead Developer", + description="Senior developer with full-stack expertise.", + instructions=""" + - Plan technical implementation + - Provide effort estimates + - Review technical feasibility + """, + api_headers=api_headers, + temperature=0.3, + max_prompt_tokens=25000 + ) + + client_manager = Agent( + name="Client Success Manager", + description="Experienced client manager focused on project delivery.", + instructions=""" + - Ensure client satisfaction + - Manage expectations + - Handle feedback + """, + api_headers=api_headers, + temperature=0.6, + max_prompt_tokens=25000 + ) + + # Create agency + agency = Agency( + [ + ceo, cto, product_manager, developer, client_manager, + [ceo, cto], + [ceo, product_manager], + [ceo, developer], + [ceo, client_manager], + [cto, developer], + [product_manager, developer], + [product_manager, client_manager] + ], + async_mode='threading', + shared_files='shared_files' + ) + + # Prepare project info + project_info = { + "name": project_name, + "description": project_description, + "type": project_type, + "timeline": timeline, + "budget": budget_range, + "priority": priority, + "technical_requirements": tech_requirements, + "special_considerations": special_considerations + } + + st.session_state.messages.append({"role": "user", "content": str(project_info)}) + # Create tabs and run analysis + with st.spinner("AI Services Agency is analyzing your project..."): + try: + # Get analysis from each agent using agency.get_completion() + ceo_response = agency.get_completion( + message=f"""Analyze this project using the AnalyzeProjectRequirements tool: + Project Name: {project_name} + Project Description: {project_description} + Project Type: {project_type} + Budget Range: {budget_range} + + Use these exact values with the tool and wait for the analysis results.""", + recipient_agent=ceo + ) + + cto_response = agency.get_completion( + message=f"""Review the project analysis and create technical specifications using the CreateTechnicalSpecification tool. + Choose the most appropriate: + - architecture_type (monolithic/microservices/serverless/hybrid) + - core_technologies (comma-separated list) + - scalability_requirements (high/medium/low) + + Base your choices on the project requirements and analysis.""", + recipient_agent=cto + ) + + pm_response = agency.get_completion( + message=f"Analyze project management aspects: {str(project_info)}", + recipient_agent=product_manager, + additional_instructions="Focus on product-market fit and roadmap development, and coordinate with technical and marketing teams." + ) + + developer_response = agency.get_completion( + message=f"Analyze technical implementation based on CTO's specifications: {str(project_info)}", + recipient_agent=developer, + additional_instructions="Provide technical implementation details, optimal tech stack you would be using including the costs of cloud services (if any) and feasibility feedback, and coordinate with product manager and CTO to build the required products for the startup." + ) + + client_response = agency.get_completion( + message=f"Analyze client success aspects: {str(project_info)}", + recipient_agent=client_manager, + additional_instructions="Provide detailed go-to-market strategy and customer acquisition plan, and coordinate with product manager." + ) + + # Create tabs for different analyses + tabs = st.tabs([ + "CEO's Project Analysis", + "CTO's Technical Specification", + "Product Manager's Plan", + "Developer's Implementation", + "Client Success Strategy" + ]) + + with tabs[0]: + st.markdown("## CEO's Strategic Analysis") + st.markdown(ceo_response) + st.session_state.messages.append({"role": "assistant", "content": ceo_response}) + + with tabs[1]: + st.markdown("## CTO's Technical Specification") + st.markdown(cto_response) + st.session_state.messages.append({"role": "assistant", "content": cto_response}) + + with tabs[2]: + st.markdown("## Product Manager's Plan") + st.markdown(pm_response) + st.session_state.messages.append({"role": "assistant", "content": pm_response}) + + with tabs[3]: + st.markdown("## Lead Developer's Development Plan") + st.markdown(developer_response) + st.session_state.messages.append({"role": "assistant", "content": developer_response}) + + with tabs[4]: + st.markdown("## Client Success Strategy") + st.markdown(client_response) + st.session_state.messages.append({"role": "assistant", "content": client_response}) + + except Exception as e: + st.error(f"Error during analysis: {str(e)}") + st.error("Please check your inputs and API key and try again.") + + except Exception as e: + st.error(f"Error during analysis: {str(e)}") + st.error("Please check your API key and try again.") + + # Add history management in sidebar + with st.sidebar: + st.subheader("Options") + if st.checkbox("Show Analysis History"): + for message in st.session_state.messages: + with st.chat_message(message["role"]): + st.markdown(message["content"]) + + if st.button("Clear History"): + st.session_state.messages = [] + st.rerun() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ai_agent_tutorials/ai_services_agency/requirements.txt b/ai_agent_tutorials/ai_services_agency/requirements.txt new file mode 100644 index 0000000..a41c04a --- /dev/null +++ b/ai_agent_tutorials/ai_services_agency/requirements.txt @@ -0,0 +1,3 @@ +python-dotenv==1.0.1 +agency-swarm==0.4.1 +streamlit \ No newline at end of file diff --git a/ai_agent_tutorials/ai_startup_trend_analysis_agent/README.md b/ai_agent_tutorials/ai_startup_trend_analysis_agent/README.md new file mode 100644 index 0000000..5402738 --- /dev/null +++ b/ai_agent_tutorials/ai_startup_trend_analysis_agent/README.md @@ -0,0 +1,42 @@ +## ๐ AI Startup Trend Analysis Agent +The AI Startup Trend Analysis Agent is tool for budding entrepreneurs that generates actionable insights by identifying nascent trends, potential market gaps, and growth opportunities in specific sectors. Entrepreneurs can use these data-driven insights to validate ideas, spot market opportunities, and make informed decisions about their startup ventures. It combines Newspaper4k and DuckDuckGo to scan and analyze startup-focused articles and market data. Using Claude 3.5 Sonnet, it processes this information to extract emerging patterns and enable entrepreneurs to identify promising startup opportunities. + + +### Features +- **User Prompt**: Entrepreneurs can input specific startup sectors or technologies of interest for research. +- **News Collection**: This agent gathers recent startup news, funding rounds, and market analyses using DuckDuckGo. +- **Summary Generation**: Concise summaries of verified information are generated using Newspaper4k. +- **Trend Analysis**: The system identifies emerging patterns in startup funding, technology adoption, and market opportunities across analyzed stories. +- **Streamlit UI**: The application features a user-friendly interface built with Streamlit for easy interaction. + +### How to Get Started +1. **Clone the repository**: + ```bash + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd awesome-llm-apps/ai_agent_tutorials/ai_startup_trend_analysis_agent + ``` + +2. **Create and activate a virtual environment**: + ```bash + # For macOS/Linux + python -m venv venv + source venv/bin/activate + + # For Windows + python -m venv venv + .\venv\Scripts\activate + ``` + +3. **Install the required packages**: + ```bash + pip install -r requirements.txt + ``` + +4. **Run the application**: + ```bash + streamlit run startup_trends_agent.py + ``` +### Important Note +- The system specifically uses Claude's API for advanced language processing. You can obtain your Anthropic API key from [Anthropic's website](https://www.anthropic.com/api). + + diff --git a/ai_agent_tutorials/ai_startup_trend_analysis_agent/requirements.txt b/ai_agent_tutorials/ai_startup_trend_analysis_agent/requirements.txt new file mode 100644 index 0000000..00ecb40 --- /dev/null +++ b/ai_agent_tutorials/ai_startup_trend_analysis_agent/requirements.txt @@ -0,0 +1,5 @@ +agno +streamlit==1.40.2 +duckduckgo_search==6.3.7 +newspaper4k==0.9.3.1 +lxml_html_clean==0.4.1 \ No newline at end of file diff --git a/ai_agent_tutorials/ai_startup_trend_analysis_agent/startup_trends_agent.py b/ai_agent_tutorials/ai_startup_trend_analysis_agent/startup_trends_agent.py new file mode 100644 index 0000000..8b9a722 --- /dev/null +++ b/ai_agent_tutorials/ai_startup_trend_analysis_agent/startup_trends_agent.py @@ -0,0 +1,99 @@ +import streamlit as st +from agno.agent import Agent +from agno.tools.duckduckgo import DuckDuckGoTools +from agno.models.anthropic import Claude +from agno.tools.newspaper4k import Newspaper4kTools +from agno.tools import Tool +import logging + +logging.basicConfig(level=logging.DEBUG) + +# Setting up Streamlit app +st.title("AI Startup Trend Analysis Agent ๐") +st.caption("Get the latest trend analysis and startup opportunities based on your topic of interest in a click!.") + +topic = st.text_input("Enter the area of interest for your Startup:") +anthropic_api_key = st.sidebar.text_input("Enter Anthropic API Key", type="password") + +if st.button("Generate Analysis"): + if not anthropic_api_key: + st.warning("Please enter the required API key.") + else: + with st.spinner("Processing your request..."): + try: + # Initialize Anthropic model + anthropic_model = Claude(id ="claude-3-5-sonnet-20240620",api_key=anthropic_api_key) + + # Define News Collector Agent - Duckduckgo_search tool enables an Agent to search the web for information. + search_tool = DuckDuckGoTools(search=True, news=True, fixed_max_results=5) + news_collector = Agent( + name="News Collector", + role="Collects recent news articles on the given topic", + tools=[search_tool], + model=anthropic_model, + instructions=["Gather latest articles on the topic"], + show_tool_calls=True, + markdown=True, + ) + + # Define Summary Writer Agent + news_tool = Newspaper4kTools(read_article=True, include_summary=True) + summary_writer = Agent( + name="Summary Writer", + role="Summarizes collected news articles", + tools=[news_tool], + model=anthropic_model, + instructions=["Provide concise summaries of the articles"], + show_tool_calls=True, + markdown=True, + ) + + # Define Trend Analyzer Agent + trend_analyzer = Agent( + name="Trend Analyzer", + role="Analyzes trends from summaries", + model=anthropic_model, + instructions=["Identify emerging trends and startup opportunities"], + show_tool_calls=True, + markdown=True, + ) + + # The multi agent Team setup of phidata: + agent_team = Agent( + agents=[news_collector, summary_writer, trend_analyzer], + instructions=[ + "First, search DuckDuckGo for recent news articles related to the user's specified topic.", + "Then, provide the collected article links to the summary writer.", + "Important: you must ensure that the summary writer receives all the article links to read.", + "Next, the summary writer will read the articles and prepare concise summaries of each.", + "After summarizing, the summaries will be passed to the trend analyzer.", + "Finally, the trend analyzer will identify emerging trends and potential startup opportunities based on the summaries provided in a detailed Report form so that any young entreprenur can get insane value reading this easily" + ], + show_tool_calls=True, + markdown=True, + ) + + # Executing the workflow + # Step 1: Collect news + news_response = news_collector.run(f"Collect recent news on {topic}") + articles = news_response.content + + # Step 2: Summarize articles + summary_response = summary_writer.run(f"Summarize the following articles:\n{articles}") + summaries = summary_response.content + + # Step 3: Analyze trends + trend_response = trend_analyzer.run(f"Analyze trends from the following summaries:\n{summaries}") + analysis = trend_response.content + + # Display results - if incase you want to use this furthur, you can uncomment the below 2 lines to get the summaries too! + # st.subheader("News Summaries") + # # st.write(summaries) + + st.subheader("Trend Analysis and Potential Startup Opportunities") + st.write(analysis) + + except Exception as e: + st.error(f"An error occurred: {e}") +else: + st.info("Enter the topic and API keys, then click 'Generate Analysis' to start.") diff --git a/ai_agent_tutorials/ai_system_architect_r1/README.md b/ai_agent_tutorials/ai_system_architect_r1/README.md new file mode 100644 index 0000000..a78e925 --- /dev/null +++ b/ai_agent_tutorials/ai_system_architect_r1/README.md @@ -0,0 +1,74 @@ +# ๐ค AI System Architect Advisor with R1 + +An Agno agentic system that provides expert software architecture analysis and recommendations using a dual-model approach combining DeepSeek R1's Reasoning and Claude. The system provides detailed technical analysis, implementation roadmaps, and architectural decisions for complex software systems. + +## Features + +- **Dual AI Model Architecture** + - **DeepSeek Reasoner**: Provides initial technical analysis and structured reasoning about architecture patterns, tools, and implementation strategies + - **Claude-3.5**: Generates detailed explanations, implementation roadmaps, and technical specifications based on DeepSeek's analysis + +- **Comprehensive Analysis Components** + - Architecture Pattern Selection + - Infrastructure Resource Planning + - Security Measures and Compliance + - Database Architecture + - Performance Requirements + - Cost Estimation + - Risk Assessment + +- **Analysis Types** + - Real-time Event Processing Systems + - Healthcare Data Platforms + - Financial Trading Platforms + - Multi-tenant SaaS Solutions + - Digital Content Delivery Networks + - Supply Chain Management Systems + +## How to Run + +1. **Setup Environment** + ```bash + # Clone the repository + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd awesome-llm-apps/ai_agent_tutorials/ai_system_architect_r1 + + # Install dependencies + pip install -r requirements.txt + ``` + +2. **Configure API Keys** + - Get DeepSeek API key from DeepSeek platform + - Get Anthropic API key from [Anthropic Platform](https://www.anthropic.com) + +3. **Run the Application** + ```bash + streamlit run ai_system_architect_r1.py + ``` + +4. **Use the Interface** + - Enter API credentials in sidebar + - Structure your prompt with: + - Project Context + - Requirements + - Constraints + - Scale + - Security/Compliance needs + - View detailed analysis results + +## Example Test Prompts: + +### 1. Financial Trading Platform +"We need to build a high-frequency trading platform that processes market data streams, executes trades with sub-millisecond latency, maintains audit trails, and handles complex risk calculations. The system needs to be globally distributed, handle 100,000 transactions per second, and have robust disaster recovery capabilities." +### 2. Multi-tenant SaaS Platform +"Design a multi-tenant SaaS platform for enterprise resource planning that needs to support customization per tenant, handle different data residency requirements, support offline capabilities, and maintain performance isolation between tenants. The system should scale to 10,000 concurrent users and support custom integrations." + +## Notes + +- Requires both DeepSeek and Anthropic API keys +- Provides real-time analysis with detailed explanations +- Supports chat-based interaction +- Includes clear reasoning for all architectural decisions +- API usage costs apply + + diff --git a/ai_agent_tutorials/ai_system_architect_r1/ai_system_architect_r1.py b/ai_agent_tutorials/ai_system_architect_r1/ai_system_architect_r1.py new file mode 100644 index 0000000..5236c94 --- /dev/null +++ b/ai_agent_tutorials/ai_system_architect_r1/ai_system_architect_r1.py @@ -0,0 +1,315 @@ +from typing import Optional, List, Dict, Any, Union +import os +import time +import streamlit as st +from openai import OpenAI +import anthropic +from dotenv import load_dotenv +from pydantic import BaseModel, Field +from enum import Enum +import json +from agno.agent import Agent, RunResponse +from agno.models.anthropic import Claude + +# Model Constants +DEEPSEEK_MODEL: str = "deepseek-reasoner" +CLAUDE_MODEL: str = "claude-3-5-sonnet-20241022" + +class ArchitecturePattern(str, Enum): + """Architectural patterns for system design.""" + MICROSERVICES = "microservices" # Decomposed into small, independent services + MONOLITHIC = "monolithic" # Single, unified codebase + SERVERLESS = "serverless" # Function-as-a-Service architecture + EVENT_DRIVEN = "event_driven" # Asynchronous event-based communication + +class DatabaseType(str, Enum): + """Types of database systems.""" + SQL = "sql" # Relational databases with ACID properties + NOSQL = "nosql" # Non-relational databases for flexible schemas + HYBRID = "hybrid" # Combined SQL and NoSQL approach + +class ComplianceStandard(str, Enum): + """Regulatory compliance standards.""" + HIPAA = "hipaa" # Healthcare data protection + GDPR = "gdpr" # EU data privacy regulation + SOC2 = "soc2" # Service organization security controls + ISO27001 = "iso27001" # Information security management + +class ArchitectureDecision(BaseModel): + """Represents architectural decisions and their justifications.""" + pattern: ArchitecturePattern + rationale: str = Field(..., min_length=50) # Detailed explanation for the choice + trade_offs: Dict[str, List[str]] = Field(..., alias="trade_offs") # Pros and cons + estimated_cost: Dict[str, float] # Cost breakdown + +class SecurityMeasure(BaseModel): + """Security controls and implementation details.""" + measure_type: str # Type of security measure + implementation_priority: int = Field(..., ge=1, le=5) # Priority level 1-5 + compliance_standards: List[ComplianceStandard] # Applicable standards + data_classification: str # Data sensitivity level + +class InfrastructureResource(BaseModel): + """Infrastructure components and specifications.""" + resource_type: str # Type of infrastructure resource + specifications: Dict[str, str] # Technical specifications + scaling_policy: Dict[str, str] # Scaling rules and thresholds + estimated_cost: float # Estimated cost per resource + +class TechnicalAnalysis(BaseModel): + """Complete technical analysis of the system architecture.""" + architecture_decision: ArchitectureDecision # Core architecture choices + infrastructure_resources: List[InfrastructureResource] # Required resources + security_measures: List[SecurityMeasure] # Security controls + database_choice: DatabaseType # Database architecture + compliance_requirements: List[ComplianceStandard] = [] # Required standards + performance_requirements: List[Dict[str, Union[str, float]]] = [] # Performance metrics + risk_assessment: Dict[str, str] = {} # Identified risks and mitigations + + +class ModelChain: + def __init__(self, deepseek_api_key: str, anthropic_api_key: str) -> None: + self.client = OpenAI( + api_key=deepseek_api_key, + base_url="https://api.deepseek.com" + ) + self.claude_client = anthropic.Anthropic(api_key=anthropic_api_key) + + # Create Claude model with system prompt + claude_model = Claude( + id="claude-3-5-sonnet-20241022", + api_key=anthropic_api_key, + system_prompt="""Given the user's query and the DeepSeek reasoning: + 1. Provide a detailed analysis of the architecture decisions + 2. Generate a project implementation roadmap + 3. Create a comprehensive technical specification document + 4. Format the output in clean markdown with proper sections + 5. Include diagrams descriptions in mermaid.js format""" + ) + + # Initialize agent with configured model + self.agent = Agent( + model=claude_model, + markdown=True + ) + + self.deepseek_messages: List[Dict[str, str]] = [] + self.claude_messages: List[Dict[str, Any]] = [] + self.current_model: str = CLAUDE_MODEL + def get_deepseek_reasoning(self, user_input: str) -> tuple[str, str]: + start_time = time.time() + + system_prompt = """You are an expert software architect and technical advisor. Analyze the user's project requirements + and provide structured reasoning about architecture, tools, and implementation strategies. + + IMPORTANT: Reason why you are choosing a particular architecture pattern, database type, etc. for user understanding in your reasoning. + + IMPORTANT: Your response must be a valid JSON object (not a string or any other format) that matches the schema provided below. + Do not include any explanatory text, markdown formatting, or code blocks - only return the JSON object. + + Schema: + { + "architecture_decision": { + "pattern": "one of: microservices|monolithic|serverless|event_driven|layered", + "rationale": "string", + "trade_offs": {"advantage": ["list of strings"], "disadvantage": ["list of strings"]}, + "estimated_cost": {"implementation": float, "maintenance": float} + }, + "infrastructure_resources": [{ + "resource_type": "string", + "specifications": {"key": "value"}, + "scaling_policy": {"key": "value"}, + "estimated_cost": float + }], + "security_measures": [{ + "measure_type": "string", + "implementation_priority": "integer 1-5", + "compliance_standards": ["hipaa", "gdpr", "soc2", "hitech", "iso27001", "pci_dss"], + "estimated_setup_time_days": "integer", + "data_classification": "one of: protected_health_information|personally_identifiable_information|confidential|public", + "encryption_requirements": {"key": "value"}, + "access_control_policy": {"role": ["permissions"]}, + "audit_requirements": ["list of strings"] + }], + "database_choice": "one of: sql|nosql|graph|time_series|hybrid", + "ml_capabilities": [{ + "model_type": "string", + "training_frequency": "string", + "input_data_types": ["list of strings"], + "performance_requirements": {"metric": float}, + "hardware_requirements": {"resource": "specification"}, + "regulatory_constraints": ["list of strings"] + }], + "data_integrations": [{ + "integration_type": "one of: hl7|fhir|dicom|rest|soap|custom", + "data_format": "string", + "frequency": "string", + "volume": "string", + "security_requirements": {"key": "value"} + }], + "performance_requirements": [{ + "metric_name": "string", + "target_value": float, + "measurement_unit": "string", + "priority": "integer 1-5" + }], + "audit_config": { + "log_retention_period": "integer", + "audit_events": ["list of strings"], + "compliance_mapping": {"standard": ["requirements"]} + }, + "api_config": { + "version": "string", + "auth_method": "string", + "rate_limits": {"role": "requests_per_minute"}, + "documentation_url": "string" + }, + "error_handling": { + "retry_policy": {"key": "value"}, + "fallback_strategies": ["list of strings"], + "notification_channels": ["list of strings"] + }, + "estimated_team_size": "integer", + "critical_path_components": ["list of strings"], + "risk_assessment": {"risk": "mitigation"}, + "maintenance_considerations": ["list of strings"], + "compliance_requirements": ["list of compliance standards"], + "data_retention_policy": {"data_type": "retention_period"}, + "disaster_recovery": {"key": "value"}, + "interoperability_standards": ["list of strings"] + } + + Consider scalability, security, maintenance, and technical debt in your analysis. + Focus on practical, modern solutions while being mindful of trade-offs.""" + + try: + deepseek_response = self.client.chat.completions.create( + model="deepseek-reasoner", + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_input} + ], + max_tokens=3000, + stream=False + ) + + reasoning_content = deepseek_response.choices[0].message.reasoning_content + normal_content = deepseek_response.choices[0].message.content + + # Display the reasoning separately + with st.expander("DeepSeek Reasoning", expanded=True): + st.markdown(reasoning_content) + + + with st.expander("๐ญ Technical Analysis", expanded=True): + st.markdown(normal_content) + elapsed_time = time.time() - start_time + time_str = f"{elapsed_time/60:.1f} minutes" if elapsed_time >= 60 else f"{elapsed_time:.1f} seconds" + st.caption(f"โฑ๏ธ Analysis completed in {time_str}") + + # Return both reasoning and normal content + return reasoning_content, normal_content + + except Exception as e: + st.error(f"Error in DeepSeek analysis: {str(e)}") + return "Error occurred while analyzing", "" + + def get_claude_response(self, user_input: str, deepseek_output: tuple[str, str]) -> str: + try: + reasoning_content, normal_content = deepseek_output + + # Create expander for Claude's response + with st.expander("๐ค Claude's Response", expanded=True): + response_placeholder = st.empty() + + # Prepare the message with user input, reasoning and normal output + message = f"""User Query: {user_input} + + DeepSeek Reasoning: {reasoning_content} + + DeepSeek Technical Analysis: {normal_content} + Give detailed explanation for each key value pair in brief in the JSON object, and why we chose it clearly. Dont use your own opinions, use the reasoning and the structured output to explain the choices.""" + + # Use Phi Agent to get response + response: RunResponse = self.agent.run( + message=message + ) + + dub = response.content + st.markdown(dub) + return dub + + except Exception as e: + st.error(f"Error in Claude response: {str(e)}") + return "Error occurred while getting response" + +def main() -> None: + """Main function to run the Streamlit app.""" + st.title("๐ค AI System Architect Advisor with R1") + + # Add prompt guidance + st.info(""" + ๐ For best results, structure your prompt with: + + 1. **Project Context**: Brief description of your project/system + 2. **Requirements**: Key functional and non-functional requirements + 3. **Constraints**: Any technical, budget, or time constraints + 4. **Scale**: Expected user base and growth projections + 5. **Security/Compliance**: Any specific security or regulatory needs + + Example: + ``` + I need to build a healthcare data management system that: + - Handles patient records and appointments + - Needs to scale to 10,000 users + - Must be HIPAA compliant + - Budget constraint of $50k for initial setup + - Should integrate with existing hospital systems + ``` + """) + + # Sidebar for API keys + with st.sidebar: + st.header("โ๏ธ Configuration") + deepseek_api_key = st.text_input("DeepSeek API Key", type="password") + anthropic_api_key = st.text_input("Anthropic API Key", type="password") + + if st.button("๐๏ธ Clear Chat History"): + st.session_state.messages = [] + st.rerun() + + # Initialize session state for messages + if "messages" not in st.session_state: + st.session_state.messages = [] + + # Display chat messages + for message in st.session_state.messages: + with st.chat_message(message["role"]): + st.markdown(message["content"]) + + # Chat input + if prompt := st.chat_input("What would you like to know?"): + if not deepseek_api_key or not anthropic_api_key: + st.error("โ ๏ธ Please enter both API keys in the sidebar.") + return + + # Initialize ModelChain + chain = ModelChain(deepseek_api_key, anthropic_api_key) + + # Add user message to chat + st.session_state.messages.append({"role": "user", "content": prompt}) + with st.chat_message("user"): + st.markdown(prompt) + + # Get AI response + with st.chat_message("assistant"): + with st.spinner("๐ค Thinking..."): + deepseek_output = chain.get_deepseek_reasoning(prompt) + + + with st.spinner("โ๏ธ Responding..."): + response = chain.get_claude_response(prompt, deepseek_output) + st.session_state.messages.append({"role": "assistant", "content": response}) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ai_agent_tutorials/ai_system_architect_r1/requirements.txt b/ai_agent_tutorials/ai_system_architect_r1/requirements.txt new file mode 100644 index 0000000..e8fce4b --- /dev/null +++ b/ai_agent_tutorials/ai_system_architect_r1/requirements.txt @@ -0,0 +1,4 @@ +streamlit +openai +anthropic +agno \ No newline at end of file diff --git a/ai_agent_tutorials/ai_teaching_agent_team/README.md b/ai_agent_tutorials/ai_teaching_agent_team/README.md new file mode 100644 index 0000000..5a67383 --- /dev/null +++ b/ai_agent_tutorials/ai_teaching_agent_team/README.md @@ -0,0 +1,75 @@ +# ๐จโ๐ซ AI Teaching Agent Team + +A Streamlit application that brings together a team of specialized AI teaching agents who collaborate like a professional teaching faculty. Each agent acts as a specialized educator: a curriculum designer, learning path expert, resource librarian, and practice instructor - working together to create a complete educational experience through Google Docs. + +## ๐ช Meet your AI Teaching Agent Team + +#### ๐ง Professor Agent +- Creates fundamental knowledge base in Google Docs +- Organizes content with proper headings and sections +- Includes detailed explanations and examples +- Output: Comprehensive knowledge base document with table of contents + +#### ๐บ๏ธ Academic Advisor Agent +- Designs learning path in a structured Google Doc +- Creates progressive milestone markers +- Includes time estimates and prerequisites +- Output: Visual roadmap document with clear progression paths + +#### ๐ Research Librarian Agent +- Compiles resources in an organized Google Doc +- Includes links to academic papers and tutorials +- Adds descriptions and difficulty levels +- Output: Categorized resource list with quality ratings + +#### โ๏ธ Teaching Assistant Agent +- Develops exercises in an interactive Google Doc +- Creates structured practice sections +- Includes solution guides +- Output: Complete practice workbook with answers + + +## How to Run + +1. Clone the repository + ```bash + # Clone the repository + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd ai_agent_tutorials/ai_personal_learning_agent + + # Install dependencies + pip install -r requirements.txt + ``` + +## Configuration - IMPORTANT STEP + +1. Get your OpenAI API Key +- Create an account on [OpenAI Platform](https://platform.openai.com/) +- Navigate to API Keys section +- Create a new API key + +2. Get your Composio API Key +- Create an account on [Composio Platform](https://composio.ai/) +- **IMPORTANT** - For you to use the app, you need to make new connection ID with google docs and composio.Follow the below two steps to do so: + - composio add googledocs (IN THE TERMINAL) + - Create a new connection + - Select OAUTH2 + - Select Google Account and Done. + - On the composio account website, go to apps, select google docs tool, and [click create integration](https://app.composio.dev/app/googledocs) (violet button) and click Try connecting defaultโs googldocs button and we are done. + +3. Sign up and get the [SerpAPI Key](https://serpapi.com/) + +## How to Use? + +1. Start the Streamlit app +```bash +streamlit run teaching_agent_team.py +``` + +2. Use the application +- Enter your OpenAI API key in the sidebar (if not set in environment) +- Enter your Composio API key in the sidebar +- Type a topic you want to learn about (e.g., "Python Programming", "Machine Learning") +- Click "Generate Learning Plan" +- Wait for the agents to generate your personalized learning plan +- View the results and terminal output in the interface diff --git a/ai_agent_tutorials/ai_teaching_agent_team/requirements.txt b/ai_agent_tutorials/ai_teaching_agent_team/requirements.txt new file mode 100644 index 0000000..7b16c6c --- /dev/null +++ b/ai_agent_tutorials/ai_teaching_agent_team/requirements.txt @@ -0,0 +1,9 @@ +streamlit==1.41.1 +openai==1.58.1 +duckduckgo-search==6.4.1 +typing-extensions>=4.5.0 +agno +composio-phidata==0.6.9 +composio_core +composio==0.1.1 +google-search-results==2.4.2 \ No newline at end of file diff --git a/ai_agent_tutorials/ai_teaching_agent_team/teaching_agent_team.py b/ai_agent_tutorials/ai_teaching_agent_team/teaching_agent_team.py new file mode 100644 index 0000000..8306ae3 --- /dev/null +++ b/ai_agent_tutorials/ai_teaching_agent_team/teaching_agent_team.py @@ -0,0 +1,210 @@ +import streamlit as st +from agno.agent import Agent, RunResponse +from agno.models.openai import OpenAIChat +from composio_phidata import Action, ComposioToolSet +import os +from agno.tools.arxiv import ArxivTools +from agno.utils.pprint import pprint_run_response +from agno.tools.serpapi import SerpApiTools + +# Set page configuration +st.set_page_config(page_title="๐จโ๐ซ AI Teaching Agent Team", layout="centered") + +# Initialize session state for API keys and topic +if 'openai_api_key' not in st.session_state: + st.session_state['openai_api_key'] = '' +if 'composio_api_key' not in st.session_state: + st.session_state['composio_api_key'] = '' +if 'serpapi_api_key' not in st.session_state: + st.session_state['serpapi_api_key'] = '' +if 'topic' not in st.session_state: + st.session_state['topic'] = '' + +# Streamlit sidebar for API keys +with st.sidebar: + st.title("API Keys Configuration") + st.session_state['openai_api_key'] = st.text_input("Enter your OpenAI API Key", type="password").strip() + st.session_state['composio_api_key'] = st.text_input("Enter your Composio API Key", type="password").strip() + st.session_state['serpapi_api_key'] = st.text_input("Enter your SerpAPI Key", type="password").strip() + + # Add info about terminal responses + st.info("Note: You can also view detailed agent responses\nin your terminal after execution.") + +# Validate API keys +if not st.session_state['openai_api_key'] or not st.session_state['composio_api_key'] or not st.session_state['serpapi_api_key']: + st.error("Please enter OpenAI, Composio, and SerpAPI keys in the sidebar.") + st.stop() + +# Set the OpenAI API key and Composio API key from session state +os.environ["OPENAI_API_KEY"] = st.session_state['openai_api_key'] + +try: + composio_toolset = ComposioToolSet(api_key=st.session_state['composio_api_key']) + google_docs_tool = composio_toolset.get_tools(actions=[Action.GOOGLEDOCS_CREATE_DOCUMENT])[0] + google_docs_tool_update = composio_toolset.get_tools(actions=[Action.GOOGLEDOCS_UPDATE_EXISTING_DOCUMENT])[0] +except Exception as e: + st.error(f"Error initializing ComposioToolSet: {e}") + st.stop() + +# Create the Professor agent (formerly KnowledgeBuilder) +professor_agent = Agent( + name="Professor", + role="Research and Knowledge Specialist", + model=OpenAIChat(id="gpt-4o-mini", api_key=st.session_state['openai_api_key']), + tools=[google_docs_tool], + instructions=[ + "Create a comprehensive knowledge base that covers fundamental concepts, advanced topics, and current developments of the given topic.", + "Exlain the topic from first principles first. Include key terminology, core principles, and practical applications and make it as a detailed report that anyone who's starting out can read and get maximum value out of it.", + "Make sure it is formatted in a way that is easy to read and understand. DONT FORGET TO CREATE THE GOOGLE DOCUMENT.", + "Open a new Google Doc and write down the response of the agent neatly with great formatting and structure in it. **Include the Google Doc link in your response.**", + ], + show_tool_calls=True, + markdown=True, +) + +# Create the Academic Advisor agent (formerly RoadmapArchitect) +academic_advisor_agent = Agent( + name="Academic Advisor", + role="Learning Path Designer", + model=OpenAIChat(id="gpt-4o-mini", api_key=st.session_state['openai_api_key']), + tools=[google_docs_tool], + instructions=[ + "Using the knowledge base for the given topic, create a detailed learning roadmap.", + "Break down the topic into logical subtopics and arrange them in order of progression, a detailed report of roadmap that includes all the subtopics in order to be an expert in this topic.", + "Include estimated time commitments for each section.", + "Present the roadmap in a clear, structured format. DONT FORGET TO CREATE THE GOOGLE DOCUMENT.", + "Open a new Google Doc and write down the response of the agent neatly with great formatting and structure in it. **Include the Google Doc link in your response.**", + + ], + show_tool_calls=True, + markdown=True +) + +# Create the Research Librarian agent (formerly ResourceCurator) +research_librarian_agent = Agent( + name="Research Librarian", + role="Learning Resource Specialist", + model=OpenAIChat(id="gpt-4o-mini", api_key=st.session_state['openai_api_key']), + tools=[google_docs_tool, SerpApiTools(api_key=st.session_state['serpapi_api_key']) ], + instructions=[ + "Make a list of high-quality learning resources for the given topic.", + "Use the SerpApi search tool to find current and relevant learning materials.", + "Using SerpApi search tool, Include technical blogs, GitHub repositories, official documentation, video tutorials, and courses.", + "Present the resources in a curated list with descriptions and quality assessments. DONT FORGET TO CREATE THE GOOGLE DOCUMENT.", + "Open a new Google Doc and write down the response of the agent neatly with great formatting and structure in it. **Include the Google Doc link in your response.**", + ], + show_tool_calls=True, + markdown=True, +) + +# Create the Teaching Assistant agent (formerly PracticeDesigner) +teaching_assistant_agent = Agent( + name="Teaching Assistant", + role="Exercise Creator", + model=OpenAIChat(id="gpt-4o-mini", api_key=st.session_state['openai_api_key']), + tools=[google_docs_tool, SerpApiTools(api_key=st.session_state['serpapi_api_key'])], + instructions=[ + "Create comprehensive practice materials for the given topic.", + "Use the SerpApi search tool to find example problems and real-world applications.", + "Include progressive exercises, quizzes, hands-on projects, and real-world application scenarios.", + "Ensure the materials align with the roadmap progression.", + "Provide detailed solutions and explanations for all practice materials.DONT FORGET TO CREATE THE GOOGLE DOCUMENT.", + "Open a new Google Doc and write down the response of the agent neatly with great formatting and structure in it. **Include the Google Doc link in your response.**", + ], + show_tool_calls=True, + markdown=True, +) + +# Streamlit main UI +st.title("๐จโ๐ซ AI Teaching Agent Team") +st.markdown("Enter a topic to generate a detailed learning path and resources") + +# Add info message about Google Docs +st.info("๐ The agents will create detailed Google Docs for each section (Professor, Academic Advisor, Research Librarian, and Teaching Assistant). The links to these documents will be displayed below after processing.") + +# Query bar for topic input +st.session_state['topic'] = st.text_input("Enter the topic you want to learn about:", placeholder="e.g., Machine Learning, LoRA, etc.") + +# Start button +if st.button("Start"): + if not st.session_state['topic']: + st.error("Please enter a topic.") + else: + # Display loading animations while generating responses + with st.spinner("Generating Knowledge Base..."): + professor_response: RunResponse = professor_agent.run( + f"the topic is: {st.session_state['topic']},Don't forget to add the Google Doc link in your response.", + stream=False + ) + + with st.spinner("Generating Learning Roadmap..."): + academic_advisor_response: RunResponse = academic_advisor_agent.run( + f"the topic is: {st.session_state['topic']},Don't forget to add the Google Doc link in your response.", + stream=False + ) + + with st.spinner("Curating Learning Resources..."): + research_librarian_response: RunResponse = research_librarian_agent.run( + f"the topic is: {st.session_state['topic']},Don't forget to add the Google Doc link in your response.", + stream=False + ) + + with st.spinner("Creating Practice Materials..."): + teaching_assistant_response: RunResponse = teaching_assistant_agent.run( + f"the topic is: {st.session_state['topic']},Don't forget to add the Google Doc link in your response.", + stream=False + ) + + # Extract Google Doc links from the responses + def extract_google_doc_link(response_content): + # Assuming the Google Doc link is embedded in the response content + # You may need to adjust this logic based on the actual response format + if "https://docs.google.com" in response_content: + return response_content.split("https://docs.google.com")[1].split()[0] + return None + + professor_doc_link = extract_google_doc_link(professor_response.content) + academic_advisor_doc_link = extract_google_doc_link(academic_advisor_response.content) + research_librarian_doc_link = extract_google_doc_link(research_librarian_response.content) + teaching_assistant_doc_link = extract_google_doc_link(teaching_assistant_response.content) + + # Display Google Doc links at the top of the Streamlit UI + st.markdown("### Google Doc Links:") + if professor_doc_link: + st.markdown(f"- **Professor Document:** [View Document](https://docs.google.com{professor_doc_link})") + if academic_advisor_doc_link: + st.markdown(f"- **Academic Advisor Document:** [View Document](https://docs.google.com{academic_advisor_doc_link})") + if research_librarian_doc_link: + st.markdown(f"- **Research Librarian Document:** [View Document](https://docs.google.com{research_librarian_doc_link})") + if teaching_assistant_doc_link: + st.markdown(f"- **Teaching Assistant Document:** [View Document](https://docs.google.com{teaching_assistant_doc_link})") + + # Display responses in the Streamlit UI using pprint_run_response + st.markdown("### Professor Response:") + st.markdown(professor_response.content) + pprint_run_response(professor_response, markdown=True) + st.divider() + + st.markdown("### Academic Advisor Response:") + st.markdown(academic_advisor_response.content) + pprint_run_response(academic_advisor_response, markdown=True) + st.divider() + + st.markdown("### Research Librarian Response:") + st.markdown(research_librarian_response.content) + pprint_run_response(research_librarian_response, markdown=True) + st.divider() + + st.markdown("### Teaching Assistant Response:") + st.markdown(teaching_assistant_response.content) + pprint_run_response(teaching_assistant_response, markdown=True) + st.divider() +# Information about the agents +st.markdown("---") +st.markdown("### About the Agents:") +st.markdown(""" +- **Professor**: Researches the topic and creates a detailed knowledge base. +- **Academic Advisor**: Designs a structured learning roadmap for the topic. +- **Research Librarian**: Curates high-quality learning resources. +- **Teaching Assistant**: Creates practice materials, exercises, and projects. +""") diff --git a/ai_agent_tutorials/ai_tic_tac_toe_agent/README.md b/ai_agent_tutorials/ai_tic_tac_toe_agent/README.md new file mode 100644 index 0000000..8ba563e --- /dev/null +++ b/ai_agent_tutorials/ai_tic_tac_toe_agent/README.md @@ -0,0 +1,106 @@ +# ๐ฎ Agent X vs Agent O: Tic-Tac-Toe Game + +An interactive Tic-Tac-Toe game where two AI agents powered by different language models compete against each other built on Agno Agent Framework and Streamlit as UI. + +This example shows how to build an interactive Tic Tac Toe game where AI agents compete against each other. The application showcases how to: +- Coordinate multiple AI agents in a turn-based game +- Use different language models for different players +- Create an interactive web interface with Streamlit +- Handle game state and move validation +- Display real-time game progress and move history + +## Features +- Multiple AI models support (GPT-4, Claude, Gemini, etc.) +- Real-time game visualization +- Move history tracking with board states +- Interactive player selection +- Game state management +- Move validation and coordination + +## How to Run? + +1. **Setup Environment** + ```bash + # Clone the repository + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd ai_agent_tutorials/ai_tic_tac_toe_agent + + # Install dependencies + pip install -r requirements.txt + ``` + +### 2. Install dependencies + +```shell +pip install -r requirements.txt +``` + +### 3. Export API Keys + +The game supports multiple AI models. Export the API keys for the models you want to use: + +```shell +# Required for OpenAI models +export OPENAI_API_KEY=*** + +# Optional - for additional models +export ANTHROPIC_API_KEY=*** # For Claude models +export GOOGLE_API_KEY=*** # For Gemini models +export GROQ_API_KEY=*** # For Groq models +``` + +### 4. Run the Game + +```shell +streamlit run app.py +``` + +- Open [localhost:8501](http://localhost:8501) to view the game interface + +## How It Works + +The game consists of three agents: + +1. **Master Agent (Referee)** + - Coordinates the game + - Validates moves + - Maintains game state + - Determines game outcome + +2. **Two Player Agents** + - Make strategic moves + - Analyze board state + - Follow game rules + - Respond to opponent moves + +## Available Models + +The game supports various AI models: +- GPT-4o (OpenAI) +- GPT-o3-mini (OpenAI) +- Gemini (Google) +- Llama 3 (Groq) +- Claude (Anthropic) + +## Game Features + +1. **Interactive Board** + - Real-time updates + - Visual move tracking + - Clear game status display + +2. **Move History** + - Detailed move tracking + - Board state visualization + - Player action timeline + +3. **Game Controls** + - Start/Pause game + - Reset board + - Select AI models + - View game history + +4. **Performance Analysis** + - Move timing + - Strategy tracking + - Game statistics diff --git a/ai_agent_tutorials/ai_tic_tac_toe_agent/agents.py b/ai_agent_tutorials/ai_tic_tac_toe_agent/agents.py new file mode 100644 index 0000000..6be0dc8 --- /dev/null +++ b/ai_agent_tutorials/ai_tic_tac_toe_agent/agents.py @@ -0,0 +1,165 @@ +""" +Tic Tac Toe Battle +--------------------------------- +This example shows how to build a Tic Tac Toe game where two AI agents play against each other. +The game features a referee agent coordinating between two player agents using different +language models. + +Usage Examples: +--------------- +1. Quick game with default settings: + referee_agent = get_tic_tac_toe_referee() + play_tic_tac_toe() + +2. Game with debug mode off: + referee_agent = get_tic_tac_toe_referee(debug_mode=False) + play_tic_tac_toe(debug_mode=False) + +The game integrates: + - Multiple AI models (Claude, GPT-4, etc.) + - Turn-based gameplay coordination + - Move validation and game state management +""" + +import sys +from pathlib import Path +from textwrap import dedent +from typing import Tuple + +from agno.agent import Agent +from agno.models.anthropic import Claude +from agno.models.google import Gemini +from agno.models.groq import Groq +from agno.models.openai import OpenAIChat + +project_root = str(Path(__file__).parent.parent.parent.parent) +if project_root not in sys.path: + sys.path.append(project_root) + + +def get_model_for_provider(provider: str, model_name: str): + """ + Creates and returns the appropriate model instance based on the provider. + + Args: + provider: The model provider (e.g., 'openai', 'google', 'anthropic', 'groq') + model_name: The specific model name/ID + + Returns: + An instance of the appropriate model class + + Raises: + ValueError: If the provider is not supported + """ + if provider == "openai": + return OpenAIChat(id=model_name) + elif provider == "google": + return Gemini(id=model_name) + elif provider == "anthropic": + if model_name == "claude-3-5-sonnet": + return Claude(id="claude-3-5-sonnet-20241022", max_tokens=8192) + elif model_name == "claude-3-7-sonnet": + return Claude( + id="claude-3-7-sonnet-20250219", + max_tokens=8192, + ) + elif model_name == "claude-3-7-sonnet-thinking": + return Claude( + id="claude-3-7-sonnet-20250219", + max_tokens=8192, + thinking={"type": "enabled", "budget_tokens": 4096}, + ) + else: + return Claude(id=model_name) + elif provider == "groq": + return Groq(id=model_name) + else: + raise ValueError(f"Unsupported model provider: {provider}") + + +def get_tic_tac_toe_players( + model_x: str = "openai:gpt-4o", + model_o: str = "openai:o3-mini", + debug_mode: bool = True, +) -> Tuple[Agent, Agent]: + """ + Returns an instance of the Tic Tac Toe Referee Agent that coordinates the game. + + Args: + model_x: ModelConfig for player X + model_o: ModelConfig for player O + model_referee: ModelConfig for the referee agent + debug_mode: Enable logging and debug features + + Returns: + An instance of the configured Referee Agent + """ + # Parse model provider and name + provider_x, model_name_x = model_x.split(":") + provider_o, model_name_o = model_o.split(":") + + # Create model instances using the helper function + model_x = get_model_for_provider(provider_x, model_name_x) + model_o = get_model_for_provider(provider_o, model_name_o) + + player_x = Agent( + name="Player X", + description=dedent("""\ + You are Player X in a Tic Tac Toe game. Your goal is to win by placing three X's in a row (horizontally, vertically, or diagonally). + + BOARD LAYOUT: + - The board is a 3x3 grid with coordinates from (0,0) to (2,2) + - Top-left is (0,0), bottom-right is (2,2) + + RULES: + - You can only place X in empty spaces (shown as " " on the board) + - Players take turns placing their marks + - First to get 3 marks in a row (horizontal, vertical, or diagonal) wins + - If all spaces are filled with no winner, the game is a draw + + YOUR RESPONSE: + - Provide ONLY two numbers separated by a space (row column) + - Example: "1 2" places your X in row 1, column 2 + - Choose only from the valid moves list provided to you + + STRATEGY TIPS: + - Study the board carefully and make strategic moves + - Block your opponent's potential winning moves + - Create opportunities for multiple winning paths + - Pay attention to the valid moves and avoid illegal moves + """), + model=model_x, + debug_mode=debug_mode, + ) + + player_o = Agent( + name="Player O", + description=dedent("""\ + You are Player O in a Tic Tac Toe game. Your goal is to win by placing three O's in a row (horizontally, vertically, or diagonally). + + BOARD LAYOUT: + - The board is a 3x3 grid with coordinates from (0,0) to (2,2) + - Top-left is (0,0), bottom-right is (2,2) + + RULES: + - You can only place X in empty spaces (shown as " " on the board) + - Players take turns placing their marks + - First to get 3 marks in a row (horizontal, vertical, or diagonal) wins + - If all spaces are filled with no winner, the game is a draw + + YOUR RESPONSE: + - Provide ONLY two numbers separated by a space (row column) + - Example: "1 2" places your X in row 1, column 2 + - Choose only from the valid moves list provided to you + + STRATEGY TIPS: + - Study the board carefully and make strategic moves + - Block your opponent's potential winning moves + - Create opportunities for multiple winning paths + - Pay attention to the valid moves and avoid illegal moves + """), + model=model_o, + debug_mode=debug_mode, + ) + + return player_x, player_o diff --git a/ai_agent_tutorials/ai_tic_tac_toe_agent/app.py b/ai_agent_tutorials/ai_tic_tac_toe_agent/app.py new file mode 100644 index 0000000..17faeff --- /dev/null +++ b/ai_agent_tutorials/ai_tic_tac_toe_agent/app.py @@ -0,0 +1,261 @@ +import nest_asyncio +import streamlit as st +from agents import get_tic_tac_toe_players +from agno.utils.log import logger +from utils import ( + CUSTOM_CSS, + TicTacToeBoard, + display_board, + display_move_history, + show_agent_status, +) + +nest_asyncio.apply() + +# Page configuration +st.set_page_config( + page_title="Agent Tic Tac Toe", + page_icon="๐ฎ", + layout="wide", + initial_sidebar_state="expanded", +) + +# Load custom CSS with dark mode support +st.markdown(CUSTOM_CSS, unsafe_allow_html=True) + + +def main(): + #################################################################### + # App header + #################################################################### + st.markdown( + "
+ โข Upload clear, high-resolution images
+ โข Include multiple views/screens for better context
+ โข Add competitor designs for comparative analysis
+ โข Provide specific context about your target audience
+
Important Notes:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rag_tutorials/rag_chain/app.py b/rag_tutorials/rag_chain/app.py
new file mode 100644
index 0000000..714999d
--- /dev/null
+++ b/rag_tutorials/rag_chain/app.py
@@ -0,0 +1,200 @@
+import os
+import streamlit as st
+
+from langchain_google_genai import GoogleGenerativeAIEmbeddings
+from langchain_chroma import Chroma
+from langchain_community.document_loaders import PyPDFLoader
+from langchain_text_splitters.sentence_transformers import SentenceTransformersTokenTextSplitter
+from langchain_core.prompts import ChatPromptTemplate
+from langchain_google_genai import ChatGoogleGenerativeAI
+from langchain_core.output_parsers import StrOutputParser
+from langchain_core.runnables import RunnablePassthrough
+
+
+# Initialize embedding model
+embedding_model = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
+
+# Initialize pharma database
+db = Chroma(collection_name="pharma_database",
+ embedding_function=embedding_model,
+ persist_directory='./pharma_db')
+
+def format_docs(docs):
+ """Formats a list of document objects into a single string.
+
+ Args:
+ docs (list): A list of document objects, each having a 'page_content' attribute.
+
+ Returns:
+ str: A single string containing the page content from each document,
+ separated by double newlines."""
+ return "\n\n".join(doc.page_content for doc in docs)
+
+def add_to_db(uploaded_files):
+ """Processes and adds uploaded PDF files to the database.
+
+ This function checks if any files have been uploaded. If files are uploaded,
+ it saves each file to a temporary location, processes the content using a PDF loader,
+ and splits the content into smaller chunks. Each chunk, along with its metadata,
+ is then added to the database. Temporary files are removed after processing.
+
+ Args:
+ uploaded_files (list): A list of uploaded file objects to be processed.
+
+ Returns:
+ None"""
+ # Check if files are uploaded
+ if not uploaded_files:
+ st.error("No files uploaded!")
+ return
+
+ for uploaded_file in uploaded_files:
+ # Save the uploaded file to a temporary path
+ temp_file_path = os.path.join("./temp", uploaded_file.name)
+ os.makedirs(os.path.dirname(temp_file_path), exist_ok=True)
+
+ with open(temp_file_path, "wb") as temp_file:
+ temp_file.write(uploaded_file.getbuffer())
+
+ # Load the file using PyPDFLoader
+ loader = PyPDFLoader(temp_file_path)
+ data = loader.load()
+
+ # Store metadata and content
+ doc_metadata = [data[i].metadata for i in range(len(data))]
+ doc_content = [data[i].page_content for i in range(len(data))]
+
+ # Split documents into smaller chunks
+ st_text_splitter = SentenceTransformersTokenTextSplitter(
+ model_name="sentence-transformers/all-mpnet-base-v2",
+ chunk_size=100,
+ chunk_overlap=50
+ )
+ st_chunks = st_text_splitter.create_documents(doc_content, doc_metadata)
+
+ # Add chunks to database
+ db.add_documents(st_chunks)
+
+ # Remove the temporary file after processing
+ os.remove(temp_file_path)
+
+def run_rag_chain(query):
+ """Processes a query using a Retrieval-Augmented Generation (RAG) chain.
+
+ This function utilizes a RAG chain to answer a given query. It retrieves
+ relevant context using similarity search and then generates a response
+ based on this context using a chat model. The chat model is pre-configured
+ with a prompt template specialized in pharmaceutical sciences.
+
+ Args:
+ query (str): The user's question that needs to be answered.
+
+ Returns:
+ str: A response generated by the chat model, based on the retrieved context."""
+ # Create a Retriever Object and apply Similarity Search
+ retriever = db.as_retriever(search_type="similarity", search_kwargs={'k': 5})
+
+ # Initialize a Chat Prompt Template
+ PROMPT_TEMPLATE = """
+ You are a highly knowledgeable assistant specializing in pharmaceutical sciences.
+ Answer the question based only on the following context:
+ {context}
+
+ Answer the question based on the above context:
+ {question}
+
+ Use the provided context to answer the user's question accurately and concisely.
+ Don't justify your answers.
+ Don't give information not mentioned in the CONTEXT INFORMATION.
+ Do not say "according to the context" or "mentioned in the context" or similar.
+ """
+
+ prompt_template = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
+
+ # Initialize a Generator (i.e. Chat Model)
+ chat_model = ChatGoogleGenerativeAI(
+ model="gemini-1.5-pro",
+ api_key=st.session_state.get("gemini_api_key"),
+ temperature=1
+ )
+
+ # Initialize a Output Parser
+ output_parser = StrOutputParser()
+
+ # RAG Chain
+ rag_chain = {"context": retriever | format_docs, "question": RunnablePassthrough()} | prompt_template | chat_model | output_parser
+
+ # Invoke the Chain
+ response = rag_chain.invoke(query)
+
+ return response
+
+def main():
+ """Initialize and manage the PharmaQuery application interface.
+
+ This function sets up the Streamlit application interface for PharmaQuery,
+ a Pharmaceutical Insight Retrieval System. Users can enter queries related
+ to the pharmaceutical industry, upload research documents, and manage API
+ keys for enhanced functionality.
+
+ The main features include:
+ - Query input area for users to ask questions about the pharmaceutical industry.
+ - Submission button to process the query and display the retrieved insights.
+ - Sidebar for API key input and management.
+ - File uploader for adding research documents to the database, enhancing query responses.
+
+ Args:
+ None
+
+ Returns:
+ None"""
+ st.set_page_config(page_title="PharmaQuery", page_icon=":microscope:")
+ st.header("Pharmaceutical Insight Retrieval System")
+
+ query = st.text_area(
+ ":bulb: Enter your query about the Pharmaceutical Industry:",
+ placeholder="e.g., What are the AI applications in drug discovery?"
+ )
+
+ if st.button("Submit"):
+ if not query:
+ st.warning("Please ask a question")
+
+ else:
+ with st.spinner("Thinking..."):
+ result = run_rag_chain(query=query)
+ st.write(result)
+
+ with st.sidebar:
+ st.title("API Keys")
+ gemini_api_key = st.text_input("Enter your Gemini API key:", type="password")
+
+ if st.button("Enter"):
+ if gemini_api_key:
+ st.session_state.gemini_api_key = gemini_api_key
+ st.success("API key saved!")
+
+ else:
+ st.warning("Please enter your Gemini API key to proceed.")
+
+ with st.sidebar:
+ st.markdown("---")
+ pdf_docs = st.file_uploader("Upload your research documents related to Pharmaceutical Sciences (Optional) :memo:",
+ type=["pdf"],
+ accept_multiple_files=True
+ )
+
+ if st.button("Submit & Process"):
+ if not pdf_docs:
+ st.warning("Please upload the file")
+
+ else:
+ with st.spinner("Processing your documents..."):
+ add_to_db(pdf_docs)
+ st.success(":file_folder: Documents successfully added to the database!")
+
+ # Sidebar Footer
+ st.sidebar.write("Built with โค๏ธ by [Charan](https://www.linkedin.com/in/codewithcharan/)")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/rag_tutorials/rag_chain/requirements.txt b/rag_tutorials/rag_chain/requirements.txt
new file mode 100644
index 0000000..7b5fa46
--- /dev/null
+++ b/rag_tutorials/rag_chain/requirements.txt
@@ -0,0 +1,9 @@
+streamlit
+langchain-google-genai
+langchain-chroma
+langchain-community
+langchain-core
+chromadb
+sentence-transformers
+PyPDF2
+python-dotenv
diff --git a/rag_tutorials/rag_database_routing/README.md b/rag_tutorials/rag_database_routing/README.md
new file mode 100644
index 0000000..5a325a5
--- /dev/null
+++ b/rag_tutorials/rag_database_routing/README.md
@@ -0,0 +1,73 @@
+# ๐ RAG Agent with Database Routing
+
+A Streamlit application that demonstrates an advanced implementation of RAG Agent with intelligent query routing. The system combines multiple specialized databases with smart fallback mechanisms to ensure reliable and accurate responses to user queries.
+
+## Features
+
+- **Document Upload**: Users can upload multiple PDF documents related to a particular company. These documents are processed and stored in one of the three databases: Product Information, Customer Support & FAQ, or Financial Information.
+
+- **Natural Language Querying**: Users can ask questions in natural language. The system automatically routes the query to the most relevant database using a phidata agent as the router.
+
+- **RAG Orchestration**: Utilizes Langchain for orchestrating the retrieval augmented generation process, ensuring that the most relevant information is retrieved and presented to the user.
+
+- **Fallback Mechanism**: If no relevant documents are found in the databases, a LangGraph agent with a DuckDuckGo search tool is used to perform web research and provide an answer.
+
+## How to Run?
+
+1. **Clone the Repository**:
+ ```bash
+ git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git
+ cd rag_tutorials/rag_database_routing
+ ```
+
+2. **Install Dependencies**:
+ ```bash
+ pip install -r requirements.txt
+ ```
+
+3. **Run the Application**:
+ ```bash
+ streamlit run rag_database_routing.py
+ ```
+
+4. **Get OpenAI API Key**: Obtain an OpenAI API key and set it in the application. This is required for initializing the language models used in the application.
+
+5. **Setup Qdrant Cloud**
+- Visit [Qdrant Cloud](https://cloud.qdrant.io/)
+- Create an account or sign in
+- Create a new cluster
+- Get your credentials:
+ - Qdrant API Key: Found in API Keys section
+ - Qdrant URL: Your cluster URL (format: https://xxx-xxx.aws.cloud.qdrant.io)
+
+5. **Upload Documents**: Use the document upload section to add PDF documents to the desired database.
+
+6. **Ask Questions**: Enter your questions in the query section. The application will route your question to the appropriate database and provide an answer.
+
+## Technologies Used
+
+- **Langchain**: For RAG orchestration, ensuring efficient retrieval and generation of information.
+- **Phidata Agent**: Used as the router agent to determine the most relevant database for a given query.
+- **LangGraph Agent**: Acts as a fallback mechanism, utilizing DuckDuckGo for web research when necessary.
+- **Streamlit**: Provides a user-friendly interface for document upload and querying.
+- **Qdrant**: Used for managing the databases, storing and retrieving document embeddings efficiently.
+
+## How It Works?
+
+**1. Query Routing**
+The system uses a three-stage routing approach:
+- Vector similarity search across all databases
+- LLM-based routing for ambiguous queries
+- Web search fallback for unknown topics
+
+**2. Document Processing**
+- Automatic text extraction from PDFs
+- Smart text chunking with overlap
+- Vector embedding generation
+- Efficient database storage
+
+**3. Answer Generation**
+- Context-aware retrieval
+- Smart document combination
+- Confidence-based responses
+- Web research integration
\ No newline at end of file
diff --git a/rag_tutorials/rag_database_routing/rag_database_routing.py b/rag_tutorials/rag_database_routing/rag_database_routing.py
new file mode 100644
index 0000000..7e83a68
--- /dev/null
+++ b/rag_tutorials/rag_database_routing/rag_database_routing.py
@@ -0,0 +1,387 @@
+import os
+from typing import List, Dict, Any, Literal, Optional
+from dataclasses import dataclass
+import streamlit as st
+from langchain_core.documents import Document
+from langchain.text_splitter import RecursiveCharacterTextSplitter
+from langchain_community.document_loaders import PyPDFLoader
+from langchain_community.vectorstores import Qdrant
+from langchain_openai import OpenAIEmbeddings
+from langchain_openai import ChatOpenAI
+import tempfile
+from agno.agent import Agent
+from agno.models.openai import OpenAIChat
+from langchain.schema import HumanMessage
+from langchain.chains.combine_documents import create_stuff_documents_chain
+from langchain.chains import create_retrieval_chain
+from langchain import hub
+from langgraph.prebuilt import create_react_agent
+from langchain_community.tools import DuckDuckGoSearchRun
+from langchain_core.language_models import BaseLanguageModel
+from langchain.prompts import ChatPromptTemplate
+from qdrant_client import QdrantClient
+from qdrant_client.models import Distance, VectorParams
+
+def init_session_state():
+ """Initialize session state variables"""
+ if 'openai_api_key' not in st.session_state:
+ st.session_state.openai_api_key = ""
+ if 'qdrant_url' not in st.session_state:
+ st.session_state.qdrant_url = ""
+ if 'qdrant_api_key' not in st.session_state:
+ st.session_state.qdrant_api_key = ""
+ if 'embeddings' not in st.session_state:
+ st.session_state.embeddings = None
+ if 'llm' not in st.session_state:
+ st.session_state.llm = None
+ if 'databases' not in st.session_state:
+ st.session_state.databases = {}
+
+init_session_state()
+
+DatabaseType = Literal["products", "support", "finance"]
+PERSIST_DIRECTORY = "db_storage"
+
+@dataclass
+class CollectionConfig:
+ name: str
+ description: str
+ collection_name: str # This will be used as Qdrant collection name
+
+# Collection configurations
+COLLECTIONS: Dict[DatabaseType, CollectionConfig] = {
+ "products": CollectionConfig(
+ name="Product Information",
+ description="Product details, specifications, and features",
+ collection_name="products_collection"
+ ),
+ "support": CollectionConfig(
+ name="Customer Support & FAQ",
+ description="Customer support information, frequently asked questions, and guides",
+ collection_name="support_collection"
+ ),
+ "finance": CollectionConfig(
+ name="Financial Information",
+ description="Financial data, revenue, costs, and liabilities",
+ collection_name="finance_collection"
+ )
+}
+
+def initialize_models():
+ """Initialize OpenAI models and Qdrant client"""
+ if (st.session_state.openai_api_key and
+ st.session_state.qdrant_url and
+ st.session_state.qdrant_api_key):
+
+ os.environ["OPENAI_API_KEY"] = st.session_state.openai_api_key
+ st.session_state.embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
+ st.session_state.llm = ChatOpenAI(temperature=0)
+
+ try:
+ client = QdrantClient(
+ url=st.session_state.qdrant_url,
+ api_key=st.session_state.qdrant_api_key
+ )
+
+ # Test connection
+ client.get_collections()
+ vector_size = 1536
+ st.session_state.databases = {}
+ for db_type, config in COLLECTIONS.items():
+ try:
+ client.get_collection(config.collection_name)
+ except Exception:
+ # Create collection if it doesn't exist
+ client.create_collection(
+ collection_name=config.collection_name,
+ vectors_config=VectorParams(size=vector_size, distance=Distance.COSINE)
+ )
+
+ st.session_state.databases[db_type] = Qdrant(
+ client=client,
+ collection_name=config.collection_name,
+ embeddings=st.session_state.embeddings
+ )
+
+ return True
+ except Exception as e:
+ st.error(f"Failed to connect to Qdrant: {str(e)}")
+ return False
+ return False
+
+def process_document(file) -> List[Document]:
+ """Process uploaded PDF document"""
+ try:
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
+ tmp_file.write(file.getvalue())
+ tmp_path = tmp_file.name
+
+ loader = PyPDFLoader(tmp_path)
+ documents = loader.load()
+
+ # Clean up temporary file
+ os.unlink(tmp_path)
+
+ text_splitter = RecursiveCharacterTextSplitter(
+ chunk_size=1000,
+ chunk_overlap=200
+ )
+ texts = text_splitter.split_documents(documents)
+
+ return texts
+ except Exception as e:
+ st.error(f"Error processing document: {e}")
+ return []
+
+def create_routing_agent() -> Agent:
+ """Creates a routing agent using phidata framework"""
+ return Agent(
+ model=OpenAIChat(
+ id="gpt-4o",
+ api_key=st.session_state.openai_api_key
+ ),
+ tools=[],
+ description="""You are a query routing expert. Your only job is to analyze questions and determine which database they should be routed to.
+ You must respond with exactly one of these three options: 'products', 'support', or 'finance'. The user's question is: {question}""",
+ instructions=[
+ "Follow these rules strictly:",
+ "1. For questions about products, features, specifications, or item details, or product manuals โ return 'products'",
+ "2. For questions about help, guidance, troubleshooting, or customer service, FAQ, or guides โ return 'support'",
+ "3. For questions about costs, revenue, pricing, or financial data, or financial reports and investments โ return 'finance'",
+ "4. Return ONLY the database name, no other text or explanation",
+ "5. If you're not confident about the routing, return an empty response"
+ ],
+ markdown=False,
+ show_tool_calls=False
+ )
+
+def route_query(question: str) -> Optional[DatabaseType]:
+ """Route query by searching all databases and comparing relevance scores.
+ Returns None if no suitable database is found."""
+ try:
+ best_score = -1
+ best_db_type = None
+ all_scores = {} # Store all scores for debugging
+
+ # Search each database and compare relevance scores
+ for db_type, db in st.session_state.databases.items():
+ results = db.similarity_search_with_score(
+ question,
+ k=3
+ )
+
+ if results:
+ avg_score = sum(score for _, score in results) / len(results)
+ all_scores[db_type] = avg_score
+
+ if avg_score > best_score:
+ best_score = avg_score
+ best_db_type = db_type
+
+ confidence_threshold = 0.5
+ if best_score >= confidence_threshold and best_db_type:
+ st.success(f"Using vector similarity routing: {best_db_type} (confidence: {best_score:.3f})")
+ return best_db_type
+
+ st.warning(f"Low confidence scores (below {confidence_threshold}), falling back to LLM routing")
+
+ # Fallback to LLM routing
+ routing_agent = create_routing_agent()
+ response = routing_agent.run(question)
+
+ db_type = (response.content
+ .strip()
+ .lower()
+ .translate(str.maketrans('', '', '`\'"')))
+
+ if db_type in COLLECTIONS:
+ st.success(f"Using LLM routing decision: {db_type}")
+ return db_type
+
+ st.warning("No suitable database found, will use web search fallback")
+ return None
+
+ except Exception as e:
+ st.error(f"Routing error: {str(e)}")
+ return None
+
+def create_fallback_agent(chat_model: BaseLanguageModel):
+ """Create a LangGraph agent for web research."""
+
+ def web_research(query: str) -> str:
+ """Web search with result formatting."""
+ try:
+ search = DuckDuckGoSearchRun(num_results=5)
+ results = search.run(query)
+ return results
+ except Exception as e:
+ return f"Search failed: {str(e)}. Providing answer based on general knowledge."
+
+ tools = [web_research]
+
+ agent = create_react_agent(model=chat_model,
+ tools=tools,
+ debug=False)
+
+ return agent
+
+def query_database(db: Qdrant, question: str) -> tuple[str, list]:
+ """Query the database and return answer and relevant documents"""
+ try:
+ retriever = db.as_retriever(
+ search_type="similarity",
+ search_kwargs={"k": 4}
+ )
+
+ relevant_docs = retriever.get_relevant_documents(question)
+
+ if relevant_docs:
+ # Use simpler chain creation with hub prompt
+ retrieval_qa_prompt = ChatPromptTemplate.from_messages([
+ ("system", """You are a helpful AI assistant that answers questions based on provided context.
+ Always be direct and concise in your responses.
+ If the context doesn't contain enough information to fully answer the question, acknowledge this limitation.
+ Base your answers strictly on the provided context and avoid making assumptions."""),
+ ("human", "Here is the context:\n{context}"),
+ ("human", "Question: {input}"),
+ ("assistant", "I'll help answer your question based on the context provided."),
+ ("human", "Please provide your answer:"),
+ ])
+ combine_docs_chain = create_stuff_documents_chain(st.session_state.llm, retrieval_qa_prompt)
+ retrieval_chain = create_retrieval_chain(retriever, combine_docs_chain)
+
+ response = retrieval_chain.invoke({"input": question})
+ return response['answer'], relevant_docs
+
+ raise ValueError("No relevant documents found in database")
+
+ except Exception as e:
+ st.error(f"Error: {str(e)}")
+ return "I encountered an error. Please try rephrasing your question.", []
+
+def _handle_web_fallback(question: str) -> tuple[str, list]:
+ st.info("No relevant documents found. Searching web...")
+ fallback_agent = create_fallback_agent(st.session_state.llm)
+
+ with st.spinner('Researching...'):
+ agent_input = {
+ "messages": [
+ HumanMessage(content=f"Research and provide a detailed answer for: '{question}'")
+ ],
+ "is_last_step": False
+ }
+
+ try:
+ response = fallback_agent.invoke(agent_input, config={"recursion_limit": 100})
+ if isinstance(response, dict) and "messages" in response:
+ answer = response["messages"][-1].content
+ return f"Web Search Result:\n{answer}", []
+
+ except Exception:
+ # Fallback to general LLM response
+ fallback_response = st.session_state.llm.invoke(question).content
+ return f"Web search unavailable. General response: {fallback_response}", []
+
+def main():
+ """Main application function."""
+ st.set_page_config(page_title="RAG Agent with Database Routing", page_icon="๐")
+ st.title("๐ RAG Agent with Database Routing")
+
+ # Sidebar for API keys and configuration
+ with st.sidebar:
+ st.header("Configuration")
+
+ # OpenAI API Key
+ api_key = st.text_input(
+ "Enter OpenAI API Key:",
+ type="password",
+ value=st.session_state.openai_api_key,
+ key="api_key_input"
+ )
+
+ # Qdrant Configuration
+ qdrant_url = st.text_input(
+ "Enter Qdrant URL:",
+ value=st.session_state.qdrant_url,
+ help="Example: https://your-cluster.qdrant.tech"
+ )
+
+ qdrant_api_key = st.text_input(
+ "Enter Qdrant API Key:",
+ type="password",
+ value=st.session_state.qdrant_api_key
+ )
+
+ # Update session state
+ if api_key:
+ st.session_state.openai_api_key = api_key
+ if qdrant_url:
+ st.session_state.qdrant_url = qdrant_url
+ if qdrant_api_key:
+ st.session_state.qdrant_api_key = qdrant_api_key
+
+ # Initialize models if all credentials are provided
+ if (st.session_state.openai_api_key and
+ st.session_state.qdrant_url and
+ st.session_state.qdrant_api_key):
+ if initialize_models():
+ st.success("Connected to OpenAI and Qdrant successfully!")
+ else:
+ st.error("Failed to initialize. Please check your credentials.")
+ else:
+ st.warning("Please enter all required credentials to continue")
+ st.stop()
+
+ st.markdown("---")
+
+ st.header("Document Upload")
+ st.info("Upload documents to populate the databases. Each tab corresponds to a different database.")
+ tabs = st.tabs([collection_config.name for collection_config in COLLECTIONS.values()])
+
+ for (collection_type, collection_config), tab in zip(COLLECTIONS.items(), tabs):
+ with tab:
+ st.write(collection_config.description)
+ uploaded_files = st.file_uploader(
+ f"Upload PDF documents to {collection_config.name}",
+ type="pdf",
+ key=f"upload_{collection_type}",
+ accept_multiple_files=True
+ )
+
+ if uploaded_files:
+ with st.spinner('Processing documents...'):
+ all_texts = []
+ for uploaded_file in uploaded_files:
+ texts = process_document(uploaded_file)
+ all_texts.extend(texts)
+
+ if all_texts:
+ db = st.session_state.databases[collection_type]
+ db.add_documents(all_texts)
+ st.success("Documents processed and added to the database!")
+
+ # Query section
+ st.header("Ask Questions")
+ st.info("Enter your question below to find answers from the relevant database.")
+ question = st.text_input("Enter your question:")
+
+ if question:
+ with st.spinner('Finding answer...'):
+ # Route the question
+ collection_type = route_query(question)
+
+ if collection_type is None:
+ # Use web search fallback directly
+ answer, relevant_docs = _handle_web_fallback(question)
+ st.write("### Answer (from web search)")
+ st.write(answer)
+ else:
+ # Display routing information and query the database
+ st.info(f"Routing question to: {COLLECTIONS[collection_type].name}")
+ db = st.session_state.databases[collection_type]
+ answer, relevant_docs = query_database(db, question)
+ st.write("### Answer")
+ st.write(answer)
+
+if __name__ == "__main__":
+ main()
diff --git a/rag_tutorials/rag_database_routing/requirements.txt b/rag_tutorials/rag_database_routing/requirements.txt
new file mode 100644
index 0000000..0c69e77
--- /dev/null
+++ b/rag_tutorials/rag_database_routing/requirements.txt
@@ -0,0 +1,11 @@
+langchain==0.3.12
+langchain-community==0.3.12
+langchain-core==0.3.28
+qdrant-client==1.12.1
+streamlit>=1.29.0
+pypdf>=4.0.0
+sentence-transformers>=2.2.2
+phidata==2.7.3
+langchain-openai==0.2.14
+langgraph==0.2.53
+duckduckgo-search==6.4.1
\ No newline at end of file