183 lines
6.9 KiB
Python
183 lines
6.9 KiB
Python
"""
|
|
Research API Utilities
|
|
|
|
Helper functions for research endpoints.
|
|
"""
|
|
|
|
from typing import Dict, Any
|
|
from services.research.core import (
|
|
ResearchContext,
|
|
ResearchPersonalizationContext,
|
|
ContentType,
|
|
ResearchGoal,
|
|
ResearchDepth,
|
|
ProviderPreference,
|
|
)
|
|
from models.research_intent_models import TrendAnalysis
|
|
|
|
|
|
def convert_to_research_context(request, user_id: str) -> ResearchContext:
|
|
"""Convert API request to ResearchContext."""
|
|
from .models import ResearchRequest
|
|
|
|
# Map string enums
|
|
goal_map = {
|
|
"factual": ResearchGoal.FACTUAL,
|
|
"trending": ResearchGoal.TRENDING,
|
|
"competitive": ResearchGoal.COMPETITIVE,
|
|
"educational": ResearchGoal.EDUCATIONAL,
|
|
"technical": ResearchGoal.TECHNICAL,
|
|
"inspirational": ResearchGoal.INSPIRATIONAL,
|
|
}
|
|
|
|
depth_map = {
|
|
"quick": ResearchDepth.QUICK,
|
|
"standard": ResearchDepth.STANDARD,
|
|
"comprehensive": ResearchDepth.COMPREHENSIVE,
|
|
"expert": ResearchDepth.EXPERT,
|
|
}
|
|
|
|
provider_map = {
|
|
"auto": ProviderPreference.AUTO,
|
|
"exa": ProviderPreference.EXA,
|
|
"tavily": ProviderPreference.TAVILY,
|
|
"google": ProviderPreference.GOOGLE,
|
|
"hybrid": ProviderPreference.HYBRID,
|
|
}
|
|
|
|
content_type_map = {
|
|
"blog": ContentType.BLOG,
|
|
"podcast": ContentType.PODCAST,
|
|
"video": ContentType.VIDEO,
|
|
"social": ContentType.SOCIAL,
|
|
"email": ContentType.EMAIL,
|
|
"newsletter": ContentType.NEWSLETTER,
|
|
"whitepaper": ContentType.WHITEPAPER,
|
|
"general": ContentType.GENERAL,
|
|
}
|
|
|
|
# Build personalization context
|
|
personalization = ResearchPersonalizationContext(
|
|
creator_id=user_id,
|
|
content_type=content_type_map.get(request.content_type or "general", ContentType.GENERAL),
|
|
industry=request.industry,
|
|
target_audience=request.target_audience,
|
|
tone=request.tone,
|
|
)
|
|
|
|
return ResearchContext(
|
|
query=request.query,
|
|
keywords=request.keywords,
|
|
goal=goal_map.get(request.goal or "factual", ResearchGoal.FACTUAL),
|
|
depth=depth_map.get(request.depth or "standard", ResearchDepth.STANDARD),
|
|
provider_preference=provider_map.get(request.provider or "auto", ProviderPreference.AUTO),
|
|
personalization=personalization,
|
|
max_sources=request.max_sources,
|
|
recency=request.recency,
|
|
include_domains=request.include_domains,
|
|
exclude_domains=request.exclude_domains,
|
|
advanced_mode=request.advanced_mode,
|
|
exa_category=request.exa_category,
|
|
exa_search_type=request.exa_search_type,
|
|
tavily_topic=request.tavily_topic,
|
|
tavily_search_depth=request.tavily_search_depth,
|
|
tavily_include_answer=request.tavily_include_answer,
|
|
tavily_time_range=request.tavily_time_range,
|
|
)
|
|
|
|
|
|
def map_purpose_to_goal(purpose: str) -> ResearchGoal:
|
|
"""Map intent purpose to research goal."""
|
|
mapping = {
|
|
"learn": ResearchGoal.EDUCATIONAL,
|
|
"create_content": ResearchGoal.FACTUAL,
|
|
"make_decision": ResearchGoal.FACTUAL,
|
|
"compare": ResearchGoal.COMPETITIVE,
|
|
"solve_problem": ResearchGoal.EDUCATIONAL,
|
|
"find_data": ResearchGoal.FACTUAL,
|
|
"explore_trends": ResearchGoal.TRENDING,
|
|
"validate": ResearchGoal.FACTUAL,
|
|
"generate_ideas": ResearchGoal.INSPIRATIONAL,
|
|
}
|
|
return mapping.get(purpose, ResearchGoal.FACTUAL)
|
|
|
|
|
|
def map_depth_to_engine_depth(depth: str) -> ResearchDepth:
|
|
"""Map intent depth to research engine depth."""
|
|
mapping = {
|
|
"overview": ResearchDepth.QUICK,
|
|
"detailed": ResearchDepth.STANDARD,
|
|
"expert": ResearchDepth.COMPREHENSIVE,
|
|
}
|
|
return mapping.get(depth, ResearchDepth.STANDARD)
|
|
|
|
|
|
def map_provider_to_preference(provider: str) -> ProviderPreference:
|
|
"""Map query provider to engine preference."""
|
|
mapping = {
|
|
"exa": ProviderPreference.EXA,
|
|
"tavily": ProviderPreference.TAVILY,
|
|
"google": ProviderPreference.GOOGLE,
|
|
}
|
|
return mapping.get(provider, ProviderPreference.AUTO)
|
|
|
|
|
|
def merge_trends_data(analyzed_result: Any, trends_data: Dict[str, Any]) -> Any:
|
|
"""
|
|
Merge Google Trends data into analyzed result trends.
|
|
|
|
Enhances AI-extracted trends with Google Trends data.
|
|
"""
|
|
from services.research.intent.intent_aware_analyzer import IntentDrivenResearchResult
|
|
|
|
if not analyzed_result.trends:
|
|
return analyzed_result
|
|
|
|
# Enhance each trend with Google Trends data
|
|
enhanced_trends = []
|
|
for trend in analyzed_result.trends:
|
|
# Create enhanced trend with Google Trends data
|
|
trend_dict = trend.dict() if hasattr(trend, 'dict') else trend
|
|
trend_dict["google_trends_data"] = trends_data
|
|
|
|
# Add interest score if available
|
|
if trends_data.get("interest_over_time"):
|
|
# Calculate average interest score
|
|
interest_values = []
|
|
for point in trends_data["interest_over_time"]:
|
|
for key, value in point.items():
|
|
if key not in ["date", "isPartial"] and isinstance(value, (int, float)):
|
|
interest_values.append(value)
|
|
if interest_values:
|
|
trend_dict["interest_score"] = sum(interest_values) / len(interest_values)
|
|
|
|
# Add related topics/queries
|
|
if trends_data.get("related_topics"):
|
|
top_topics = [t.get("topic_title", "") for t in trends_data["related_topics"].get("top", [])[:5]]
|
|
rising_topics = [t.get("topic_title", "") for t in trends_data["related_topics"].get("rising", [])[:5]]
|
|
trend_dict["related_topics"] = {"top": top_topics, "rising": rising_topics}
|
|
|
|
if trends_data.get("related_queries"):
|
|
top_queries = [q.get("query", "") for q in trends_data["related_queries"].get("top", [])[:5]]
|
|
rising_queries = [q.get("query", "") for q in trends_data["related_queries"].get("rising", [])[:5]]
|
|
trend_dict["related_queries"] = {"top": top_queries, "rising": rising_queries}
|
|
|
|
# Add regional interest
|
|
if trends_data.get("interest_by_region"):
|
|
regional_interest = {}
|
|
for region in trends_data["interest_by_region"][:10]: # Top 10 regions
|
|
region_name = region.get("geoName", "")
|
|
if region_name:
|
|
# Get interest value (first numeric column)
|
|
for key, value in region.items():
|
|
if key != "geoName" and isinstance(value, (int, float)):
|
|
regional_interest[region_name] = value
|
|
break
|
|
trend_dict["regional_interest"] = regional_interest
|
|
|
|
enhanced_trends.append(TrendAnalysis(**trend_dict))
|
|
|
|
# Update analyzed result with enhanced trends
|
|
analyzed_result.trends = enhanced_trends
|
|
return analyzed_result
|