AI Web Researcher: Added Exa answer and Tavily answer to the metaphor search results
Added AI insights to the metaphor search results Better display of AI search results
This commit is contained in:
277
lib/alwrity_ui/display_google_serp_results.py
Normal file
277
lib/alwrity_ui/display_google_serp_results.py
Normal file
@@ -0,0 +1,277 @@
|
||||
import streamlit as st
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Dict, Optional, Any
|
||||
|
||||
# Configure module logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def display_research_results(results: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Display research results in a structured format with tabs.
|
||||
|
||||
Args:
|
||||
results (dict): Processed research results containing summary and data
|
||||
"""
|
||||
if not results:
|
||||
st.warning("No results to display")
|
||||
return
|
||||
|
||||
# Create tabs for different result sections
|
||||
tabs = st.tabs(["📊 Summary", "🔍 Results", "📈 Statistics"])
|
||||
|
||||
with tabs[0]:
|
||||
display_summary_section(results)
|
||||
|
||||
with tabs[1]:
|
||||
if results['source'] == 'gemini':
|
||||
display_gemini_results(results)
|
||||
else:
|
||||
display_serp_results(results)
|
||||
|
||||
with tabs[2]:
|
||||
display_statistics(results)
|
||||
|
||||
def process_research_results(results: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""Process and format research results."""
|
||||
logger.info("Processing research results")
|
||||
|
||||
try:
|
||||
if not results:
|
||||
return None
|
||||
|
||||
processed = {
|
||||
'timestamp': str(datetime.now()),
|
||||
'source': results.get('source', 'unknown'),
|
||||
'summary': {},
|
||||
'data': {}
|
||||
}
|
||||
|
||||
if results.get('source') == 'gemini':
|
||||
processed.update(process_gemini_results(results))
|
||||
else:
|
||||
processed.update(process_serp_results(results))
|
||||
|
||||
logger.info("Results processing completed")
|
||||
return processed
|
||||
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to process results: {err}", exc_info=True)
|
||||
return None
|
||||
|
||||
def process_search_results(search_results: Dict[str, Any], search_type: str = "general") -> Optional[Dict[str, Any]]:
|
||||
"""Process search results and prepare for display."""
|
||||
logger.info(f"Processing {search_type} search results")
|
||||
|
||||
try:
|
||||
if not search_results:
|
||||
return None
|
||||
|
||||
processed = {
|
||||
'organic': process_organic_results(search_results.get('organic', [])),
|
||||
'peopleAlsoAsk': process_paa_results(search_results.get('peopleAlsoAsk', [])),
|
||||
'relatedSearches': process_related_searches(search_results.get('relatedSearches', [])),
|
||||
'metadata': {
|
||||
'timestamp': str(datetime.now()),
|
||||
'type': search_type
|
||||
}
|
||||
}
|
||||
|
||||
return processed
|
||||
|
||||
except Exception as err:
|
||||
logger.error(f"Error processing search results: {err}", exc_info=True)
|
||||
return None
|
||||
|
||||
# Helper functions for result processing
|
||||
def process_organic_results(results):
|
||||
"""Process organic search results."""
|
||||
return [{
|
||||
'title': result.get('title', 'No Title'),
|
||||
'link': result.get('link', '#'),
|
||||
'snippet': result.get('snippet', 'No snippet available'),
|
||||
'position': result.get('position', 'N/A')
|
||||
} for result in results]
|
||||
|
||||
def process_paa_results(results):
|
||||
"""Process People Also Ask results."""
|
||||
return [{
|
||||
'question': result.get('title', ''),
|
||||
'answer': result.get('snippet', 'No answer available'),
|
||||
'link': result.get('link', '#')
|
||||
} for result in results]
|
||||
|
||||
def process_related_searches(results):
|
||||
"""Process related searches."""
|
||||
return [query.get('query', '') for query in results]
|
||||
|
||||
def process_gemini_results(results: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Process Gemini API research results.
|
||||
|
||||
Args:
|
||||
results (dict): Raw Gemini research results
|
||||
|
||||
Returns:
|
||||
dict: Processed results with summary and data
|
||||
"""
|
||||
gemini_data = results.get('results', {})
|
||||
return {
|
||||
'summary': {
|
||||
'main_findings': gemini_data.get('main_response', ''),
|
||||
'sources': gemini_data.get('grounding_data', []),
|
||||
'processing_time': gemini_data.get('metadata', {}).get('timestamp'),
|
||||
'total_sources': len(gemini_data.get('grounding_data', [])),
|
||||
'model': gemini_data.get('metadata', {}).get('model', 'unknown')
|
||||
},
|
||||
'data': gemini_data
|
||||
}
|
||||
|
||||
def process_serp_results(results: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Process SERP search results.
|
||||
|
||||
Args:
|
||||
results (dict): Raw SERP results
|
||||
|
||||
Returns:
|
||||
dict: Processed results with summary and data
|
||||
"""
|
||||
organic_results = results.get('organic', [])
|
||||
paa_results = results.get('peopleAlsoAsk', [])
|
||||
related_searches = results.get('relatedSearches', [])
|
||||
|
||||
return {
|
||||
'summary': {
|
||||
'total_results': len(organic_results),
|
||||
'sources': [result.get('link') for result in organic_results],
|
||||
'titles': [result.get('title') for result in organic_results],
|
||||
'total_questions': len(paa_results),
|
||||
'total_related': len(related_searches)
|
||||
},
|
||||
'data': {
|
||||
'organic': process_organic_results(organic_results),
|
||||
'peopleAlsoAsk': process_paa_results(paa_results),
|
||||
'relatedSearches': process_related_searches(related_searches)
|
||||
}
|
||||
}
|
||||
|
||||
# Display helper functions
|
||||
def display_summary_section(results):
|
||||
"""Display summary section of results."""
|
||||
st.markdown("### 📋 Research Summary")
|
||||
st.markdown(f"""
|
||||
- **Source**: {results['source'].title()}
|
||||
- **Time**: {results['timestamp']}
|
||||
- **Total Sources**: {len(results.get('summary', {}).get('sources', []))}
|
||||
""")
|
||||
|
||||
def display_gemini_results(results):
|
||||
"""Display Gemini-specific results."""
|
||||
st.markdown("### 🤖 Gemini Research Findings")
|
||||
st.write(results['summary']['main_findings'])
|
||||
|
||||
with st.expander("🌐 Sources and References", expanded=False):
|
||||
st.write(results['data'].get('grounding_data', 'No sources available'))
|
||||
|
||||
def display_serp_results(results):
|
||||
"""Display SERP-specific results."""
|
||||
st.markdown("### 🔍 Search Results")
|
||||
|
||||
for result in results['data'].get('organic', []):
|
||||
with st.expander(f"📄 {result['title']}", expanded=False):
|
||||
st.markdown(f"""
|
||||
**Rank:** {result['position']}
|
||||
|
||||
**Link:** [{result['link']}]({result['link']})
|
||||
|
||||
**Snippet:**
|
||||
{result['snippet']}
|
||||
""")
|
||||
|
||||
def display_statistics(results: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Display statistical information about search results.
|
||||
|
||||
Args:
|
||||
results (dict): Processed research results
|
||||
"""
|
||||
st.markdown("### 📈 Research Statistics")
|
||||
|
||||
# Source-specific metrics
|
||||
if results['source'] == 'gemini':
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
st.metric(
|
||||
"Sources Analyzed",
|
||||
results.get('summary', {}).get('total_sources', 0)
|
||||
)
|
||||
with col2:
|
||||
st.metric(
|
||||
"Model Used",
|
||||
results.get('summary', {}).get('model', 'Unknown')
|
||||
)
|
||||
|
||||
else: # SERP results
|
||||
col1, col2, col3 = st.columns(3)
|
||||
with col1:
|
||||
st.metric(
|
||||
"Organic Results",
|
||||
results.get('summary', {}).get('total_results', 0)
|
||||
)
|
||||
with col2:
|
||||
st.metric(
|
||||
"Related Questions",
|
||||
results.get('summary', {}).get('total_questions', 0)
|
||||
)
|
||||
with col3:
|
||||
st.metric(
|
||||
"Related Searches",
|
||||
results.get('summary', {}).get('total_related', 0)
|
||||
)
|
||||
|
||||
# Common metrics
|
||||
st.markdown("#### 🕒 Timing Information")
|
||||
st.info(f"Research completed at: {results['timestamp']}")
|
||||
|
||||
# Display data quality metrics
|
||||
st.markdown("#### 📊 Data Quality")
|
||||
quality_metrics = calculate_quality_metrics(results)
|
||||
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
st.progress(quality_metrics['completeness'])
|
||||
st.caption("Data Completeness")
|
||||
with col2:
|
||||
st.progress(quality_metrics['relevance'])
|
||||
st.caption("Estimated Relevance")
|
||||
|
||||
def calculate_quality_metrics(results: Dict[str, Any]) -> Dict[str, float]:
|
||||
"""
|
||||
Calculate quality metrics for the research results.
|
||||
|
||||
Args:
|
||||
results (dict): Processed research results
|
||||
|
||||
Returns:
|
||||
dict: Quality metrics including completeness and relevance scores
|
||||
"""
|
||||
try:
|
||||
if results['source'] == 'gemini':
|
||||
completeness = 1.0 if results['summary']['main_findings'] else 0.0
|
||||
relevance = 0.8 if results['summary']['sources'] else 0.4
|
||||
else:
|
||||
organic_results = results.get('summary', {}).get('total_results', 0)
|
||||
completeness = min(organic_results / 10, 1.0) # Normalize to 0-1
|
||||
has_paa = bool(results.get('summary', {}).get('total_questions', 0))
|
||||
has_related = bool(results.get('summary', {}).get('total_related', 0))
|
||||
relevance = (0.6 + (0.2 if has_paa else 0) + (0.2 if has_related else 0))
|
||||
|
||||
return {
|
||||
'completeness': completeness,
|
||||
'relevance': relevance
|
||||
}
|
||||
|
||||
except Exception as err:
|
||||
logger.error(f"Error calculating quality metrics: {err}")
|
||||
return {'completeness': 0.0, 'relevance': 0.0}
|
||||
@@ -323,7 +323,8 @@ def do_web_research():
|
||||
"num_results": 10,
|
||||
"time_range": "past month",
|
||||
"include_domains": "",
|
||||
"similar_url": ""
|
||||
"similar_url": "",
|
||||
"search_mode": "google" # Default search mode
|
||||
}
|
||||
|
||||
# Define the research options dialog function
|
||||
@@ -425,6 +426,12 @@ def do_web_research():
|
||||
horizontal=True,
|
||||
help="Choose your preferred research method"
|
||||
)
|
||||
|
||||
# Map the selected option to the search_mode value
|
||||
for mode, label, _, _ in search_options:
|
||||
if label == selected_option:
|
||||
st.session_state.research_options["search_mode"] = mode
|
||||
break
|
||||
else:
|
||||
st.warning("No search methods available. Please configure API keys.")
|
||||
|
||||
@@ -439,7 +446,7 @@ def do_web_research():
|
||||
st.rerun()
|
||||
|
||||
# Main interface
|
||||
st.title("Keyword Research Assistant")
|
||||
st.title("ALwrity Web Researcher")
|
||||
|
||||
# Primary search area with help popover
|
||||
with st.popover("ℹ️ Keyword Research Tips"):
|
||||
@@ -450,6 +457,7 @@ def do_web_research():
|
||||
3. **Search Depth**: Higher depth = more comprehensive but slower
|
||||
4. **Target Audience**: Affects content recommendations
|
||||
5. **Content Type**: Influences research focus
|
||||
6. **Search Mode**: Choose between traditional web research(Google), AI-powered search(Tavily and Metaphor) and Deep Researcher
|
||||
""")
|
||||
|
||||
col1, col2 = st.columns([3, 1])
|
||||
@@ -484,6 +492,7 @@ def do_web_research():
|
||||
# Execute search with all parameters
|
||||
web_research_result = gpt_web_researcher(
|
||||
search_keywords=st.session_state.research_options["primary_keywords"],
|
||||
search_mode=st.session_state.research_options["search_mode"],
|
||||
related_keywords=st.session_state.research_options["related_keywords"],
|
||||
target_audience=st.session_state.research_options["target_audience"],
|
||||
content_type=st.session_state.research_options["content_type"],
|
||||
|
||||
Reference in New Issue
Block a user