In Part I of this series, we built the foundation of our multicloud employee management solution by extracting data from Oracle NetSuite, storing it in Oracle Exadata Database Service on Exascale Infrastructure on Azure, and generating vector embeddings using Azure OpenAI.

Now, in Part II, we’ll create an intelligent search interface that leverages vector similarity search to provide natural language querying capabilities. Users can ask questions like “Find all managers hired in 2023” or “Compose and email to all Sales reps inviting them to a happy hour this Friday” and receive contextual, AI-generated responses.

What We’ll Build

Our AI-powered search interface will:

  • Accept natural language queries from users
  • Convert queries to vector embeddings using Azure OpenAI
  • Perform similarity searches against our employee database
  • Generate intelligent responses using GPT models
  • Present results through an intuitive Streamlit web interface

Architecture Overview

User Query → Azure OpenAI (Embeddings) → Oracle Vector Search → GPT Response → Streamlit UI
    

The flow works as follows:

  1. User enters a natural language query
  2. Convert query to vector embedding using Azure OpenAI
  3. Search similar employee records using Oracle’s vector distance functions
  4. Pass matching records and original query to GPT for response generation
  5. Display the AI-generated response in the Streamlit interface

Step 1: Setting Up the Streamlit Environment

First, install the required dependencies:

pip install streamlit
    pip install oracledb
    pip install openai
    pip install array
    

Step 2: Creating the Streamlit Application

Create a new Python file employee_search_app.py with the following structure:

import streamlit as st
    import oracledb
    import array
    import os
    from openai import AzureOpenAI
    
    print("Successfully imported libraries and modules")
    

Step 3: Database and AI Service Connections

Configure connections to both Oracle Database and Azure OpenAI:

# Azure OpenAI Configuration
    os.environ['AZURE_OPENAI_API_KEY'] = "your_api_key_here"
    os.environ['AZURE_OPENAI_ENDPOINT'] = "https://your-endpoint.openai.azure.com"
    
    # Initialize Azure OpenAI client
    client = AzureOpenAI(
        api_key=os.getenv("AZURE_OPENAI_API_KEY"),
        api_version="2024-06-01",
        azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT")
    )
    
    # Oracle Database Connection Parameters
    username = "sys"
    password = "your_password"
    hostname = "your-scan-hostname.oracle.com"
    port = 1521
    service_name = "your_service_name"
    
    # Create connection
    def get_database_connection():
        """Establish connection to Oracle Database"""
        dsn = f"{hostname}:{port}/{service_name}"
        
        try:
            connection = oracledb.connect(
                user=username,
                password=password,
                dsn=dsn,
                mode=oracledb.SYSDBA
            )
            print("Connected to Oracle Database successfully")
            return connection
        except Exception as e:
            st.error(f"Database connection failed: {e}")
            return None
    
    # Establish database connection
    connection = get_database_connection()
    if connection:
        cursor = connection.cursor()
    

Step 4: Building the Vector Search Function

Implement the core vector similarity search functionality:

# 
    #Code truncated for brevity 
    #
    def perform_vector_search(query_text, limit=5):
        """
        Perform vector similarity search on employee data
        
        Args:
            query_text (str): User's natural language query
            limit (int): Number of similar records to return
        
        Returns:
            list: Matching employee records
        """
        try:
            # Generate embedding for the user query
            print(f"Processing query: {query_text}")
            
            response = client.embeddings.create(
                input=query_text,
                model="text-embedding-3-large"
            )
            
            # Convert embedding to Oracle-compatible format
            query_vector = array.array("f", response.data[0].embedding)
            
            # Execute vector similarity search
            sql = """
                SELECT PersonId, FirstName, LastName, HireDate, 
                       WorkEmail, Title, ExpenseLimit
                FROM EMPLOYEES
                ORDER BY VECTOR_DISTANCE(EMBEDDINGS, :query_vector, EUCLIDEAN)
                FETCH FIRST :limit ROWS ONLY
            """
            
            cursor.execute(sql, {"query_vector": query_vector, "limit": limit})
            results = cursor.fetchall()
            
            print(f"Found {len(results)} similar records")
            return results
            
        except Exception as e:
            st.error(f"Vector search failed: {e}")
            return []
    
    def generate_ai_response(user_query, search_results):
        """
        Generate an AI response based on search results
        
        Args:
            user_query (str): Original user query
            search_results (list): Matching employee records
        
        Returns:
            str: AI-generated response
        """
        if not search_results:
            return "I couldn't find any relevant employee information for your query."
        
        # Build context from search results
        context = f"User query: {user_query}\n\nRelevant employee information:\n\n"
        
        for row in search_results:
            person_id, first_name, last_name, hire_date, work_email, title, expense_limit = row
            context += f"• {first_name} {last_name} (ID: {person_id})\n"
            context += f"  Title: {title}\n"
            context += f"  Hire Date: {hire_date}\n"
            context += f"  Email: {work_email}\n"
            context += f"  Expense Limit: ${expense_limit}\n\n"
        
        try:
            # Generate response using GPT
            response = client.chat.completions.create(
                model="gpt-35-turbo",
                messages=[
                    {
                        "role": "system", 
                        "content": "You are a helpful HR assistant. Analyze the employee data and provide a clear, informative response to the user's query. Be concise but comprehensive."
                    },
                    {
                        "role": "user", 
                        "content": context
                    }
                ],
                max_tokens=500,
                temperature=0.7
            )
            
            return response.choices[0].message.content
            
        except Exception as e:
            st.error(f"AI response generation failed: {e}")
            return "I encountered an error while generating a response."
    

Step 5: Creating the Streamlit User Interface

Build an intuitive web interface for the search functionality:

#
    #Code truncated for brevity
    #
    def main():
        """Main Streamlit application"""
        
        # Page configuration
        st.set_page_config(
            page_title="Employee Search AI",
            page_icon="🔍",
            layout="wide"
        )
        
        # Header and description
        st.title('Multicloud Employee Search AI')
        st.markdown("""
        **Powered by Oracle Exadata on Azure + Azure OpenAI**
        
        This intelligent search system:
        - Extracts data from SaaS applications (NetSuite on OCI)
        - Stores data in Oracle Database on Azure with vector embeddings
        - Performs AI-powered similarity search
        - Generates natural language responses
        """)
        
        # Sidebar with examples
        with st.sidebar:
            st.header("Example Queries:")
            st.markdown("""
            Try asking:
            - "Find all managers hired in 2023"
            - "Who are the software engineers?"
            - "List recent hires in the sales department"
            """)
            
            st.header("System Status")
            if connection:
                st.success("Database Connected")
            else:
                st.error("Database Connection Failed")
        
        # Main search interface
        with st.form('search_form'):
            st.subheader("Ask me anything about our employees")
            
            user_query = st.text_area(
                'Enter your question:',
                placeholder="e.g., Find all managers with high expense limits",
                height=100
            )
            
            col1, col2 = st.columns([1, 4])
            with col1:
                submitted = st.form_submit_button('Search', use_container_width=True)
            with col2:
                limit = st.slider("Number of results to consider", 1, 20, 5)
        
        # Process search query
        if submitted and user_query.strip():
                # Perform vector search
                search_results = perform_vector_search(user_query, limit)
                
                if search_results:
                    # Generate AI response
                    with st.spinner('Generating intelligent response...'):
                        ai_response = generate_ai_response(user_query, search_results)
                    
                    # Display results
                    st.subheader("AI Response")
                    st.info(ai_response)
                    
                    # Show detailed results in expandable section               
                else:
                    st.warning("No matching employees found. Try rephrasing your query.")
        
        elif submitted:
            st.warning("Please enter a search query.")
    
    # Application cleanup
    def cleanup():
        """Clean up database connections"""
        if connection:
            cursor.close()
            connection.close()
            print("Database connection closed")
    
    # Run the application
    if __name__ == "__main__":
        try:
            main()
        except KeyboardInterrupt:
            cleanup()
            st.stop()
    

Step 6: Running the Application

To start your AI-powered employee search application:

streamlit run employee_search_app.py
    

The application will be available at http://localhost:8501

Key Features and Benefits

Advanced Vector Search

  • Semantic Understanding: The system understands intent, not just keywords
  • Fuzzy Matching: Finds relevant results even with imprecise queries
  • Contextual Responses: AI generates human-like explanations of search results

Oracle Database 23ai Vector Capabilities

  • VECTOR_DISTANCE Function: Efficient similarity calculations using Euclidean distance
  • Vector Indexing: High-performance searches on large datasets
  • Native Vector Storage: No need for external vector databases

User Experience

  • Natural Language Interface: Users query in plain English
  • Interactive Results: Expandable details for deeper exploration
  • Real-time Processing: Fast responses powered by Exascale infrastructure

Conclusion

This AI-powered employee search system demonstrates the power of combining Oracle’s database capabilities with Azure’s AI services. Key capabilities include:

  • Seamless Integration: Oracle Exadata on Exascale infrastructure at Azure with Azure OpenAI services
  • Intelligent Search: Vector similarity enables semantic understanding
  • Natural Interactions: Users can query using natural language
  • Scalable Architecture: Built on enterprise-grade infrastructure

The solution showcases how modern businesses can leverage multicloud architectures to build sophisticated, AI-driven applications that enhance productivity and user experience.

For organizations seeking even greater automation, this solution can also be built using Oracle Autonomous Database at Azure, combining self-managing database technology with Azure’s AI capabilities.

Resources