AI Analysis and Content Strategy fixes. Enhanced Strategy Routes refactoring.
This commit is contained in:
@@ -100,7 +100,8 @@ class ResearchConfig(BaseModel):
|
||||
exa_category: Optional[str] = None # company, research paper, news, linkedin profile, github, tweet, movie, song, personal site, pdf, financial report
|
||||
exa_include_domains: List[str] = [] # Domain whitelist
|
||||
exa_exclude_domains: List[str] = [] # Domain blacklist
|
||||
exa_search_type: Optional[str] = "auto" # "auto", "keyword", "neural"
|
||||
exa_search_type: Optional[str] = "auto" # "auto", "keyword", "neural", "fast", "deep"
|
||||
exa_additional_queries: Optional[List[str]] = None # Additional query variations for Deep search (only works with type="deep")
|
||||
|
||||
# Tavily-specific options
|
||||
tavily_topic: Optional[str] = "general" # general, news, finance
|
||||
|
||||
@@ -203,6 +203,10 @@ class ResearchIntent(BaseModel):
|
||||
default_factory=list,
|
||||
description="Specific aspects to focus on"
|
||||
)
|
||||
also_answering: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Additional questions or topics that should be addressed in the research results, even if not explicitly asked"
|
||||
)
|
||||
|
||||
# Constraints
|
||||
perspective: Optional[str] = Field(
|
||||
@@ -258,6 +262,28 @@ class ResearchQuery(BaseModel):
|
||||
provider: str = Field("exa", description="Preferred provider: exa, tavily, google")
|
||||
priority: int = Field(1, ge=1, le=5, description="Priority 1-5, higher = more important")
|
||||
expected_results: str = Field(..., description="What we expect to find with this query")
|
||||
|
||||
# Intent field links - which intent aspects this query addresses
|
||||
addresses_primary_question: bool = Field(
|
||||
False,
|
||||
description="Does this query address the primary question?"
|
||||
)
|
||||
addresses_secondary_questions: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Which secondary questions does this query answer?"
|
||||
)
|
||||
targets_focus_areas: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Which focus areas does this query target?"
|
||||
)
|
||||
covers_also_answering: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Which 'also answering' topics does this query cover?"
|
||||
)
|
||||
justification: Optional[str] = Field(
|
||||
None,
|
||||
description="Why this query was generated"
|
||||
)
|
||||
|
||||
|
||||
class IntentInferenceRequest(BaseModel):
|
||||
@@ -309,7 +335,15 @@ class IntentDrivenResearchResult(BaseModel):
|
||||
primary_answer: str = Field(..., description="Direct answer to primary question")
|
||||
secondary_answers: Dict[str, str] = Field(
|
||||
default_factory=dict,
|
||||
description="Answers to secondary questions (question → answer)"
|
||||
description="Answers to secondary questions (question → answer, null if not found)"
|
||||
)
|
||||
focus_areas_coverage: Dict[str, Optional[str]] = Field(
|
||||
default_factory=dict,
|
||||
description="Summary of what was found for each focus area (area → summary, null if not covered)"
|
||||
)
|
||||
also_answering_coverage: Dict[str, Optional[str]] = Field(
|
||||
default_factory=dict,
|
||||
description="Information found about each 'also answering' topic (topic → info, null if not found)"
|
||||
)
|
||||
|
||||
# Deliverables (populated based on user's expected_deliverables)
|
||||
|
||||
58
backend/models/research_models.py
Normal file
58
backend/models/research_models.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
Research Project Models
|
||||
|
||||
Database models for research project persistence and state management.
|
||||
Similar to PodcastProject, but for research projects.
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Boolean, JSON, Index
|
||||
from datetime import datetime
|
||||
|
||||
# Use the same Base as subscription models for consistency
|
||||
from models.subscription_models import Base
|
||||
|
||||
|
||||
class ResearchProject(Base):
|
||||
"""
|
||||
Database model for research project state.
|
||||
Stores complete research project state to enable cross-device resume.
|
||||
"""
|
||||
|
||||
__tablename__ = "research_projects"
|
||||
|
||||
# Primary fields
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
project_id = Column(String(255), unique=True, nullable=False, index=True) # User-facing project ID
|
||||
user_id = Column(String(255), nullable=False, index=True) # Clerk user ID
|
||||
|
||||
# Project metadata
|
||||
title = Column(String(500), nullable=True) # Project title
|
||||
keywords = Column(JSON, nullable=False) # List of keywords
|
||||
industry = Column(String(255), nullable=True)
|
||||
target_audience = Column(String(255), nullable=True)
|
||||
research_mode = Column(String(50), nullable=True, default="comprehensive") # basic, comprehensive, expert
|
||||
|
||||
# Project state (stored as JSON)
|
||||
config = Column(JSON, nullable=True) # ResearchConfig
|
||||
intent_analysis = Column(JSON, nullable=True) # AnalyzeIntentResponse
|
||||
confirmed_intent = Column(JSON, nullable=True) # ResearchIntent
|
||||
intent_result = Column(JSON, nullable=True) # IntentDrivenResearchResponse
|
||||
legacy_result = Column(JSON, nullable=True) # BlogResearchResponse (for backward compatibility)
|
||||
trends_config = Column(JSON, nullable=True) # Google Trends configuration
|
||||
|
||||
# UI state
|
||||
current_step = Column(Integer, default=1, nullable=False) # 1=Input, 2=Progress, 3=Results
|
||||
|
||||
# Status
|
||||
status = Column(String(50), default="draft", nullable=False, index=True) # draft, in_progress, completed, archived
|
||||
is_favorite = Column(Boolean, default=False, index=True)
|
||||
|
||||
# Timestamps
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False, index=True)
|
||||
|
||||
# Composite indexes for common query patterns
|
||||
__table_args__ = (
|
||||
Index('idx_user_status_created', 'user_id', 'status', 'created_at'),
|
||||
Index('idx_user_favorite_updated', 'user_id', 'is_favorite', 'updated_at'),
|
||||
)
|
||||
@@ -137,6 +137,7 @@ class APIUsageLog(Base):
|
||||
endpoint = Column(String(200), nullable=False)
|
||||
method = Column(String(10), nullable=False)
|
||||
model_used = Column(String(100), nullable=True) # e.g., "gemini-2.5-flash"
|
||||
actual_provider_name = Column(String(50), nullable=True) # e.g., "wavespeed", "google", "huggingface" - tracks real provider behind generic enum
|
||||
|
||||
# Usage Metrics
|
||||
tokens_input = Column(Integer, default=0)
|
||||
|
||||
Reference in New Issue
Block a user