import { apiClient, aiApiClient, pollingApiClient } from "../api/client"; // Import research types for use in this file import type { ResearchMode, ResearchSource, ResearchConfig, ResearchResponse } from './researchApi'; // Re-export research types for backward compatibility // TODO: Update all blog writer code to import from researchApi.ts directly export type { ResearchMode, ResearchProvider, SourceType, DateRange, ResearchSource, ResearchConfig, ResearchResponse } from './researchApi'; export interface PersonaInfo { persona_id?: string; tone?: string; audience?: string; industry?: string; } export interface BlogResearchRequest { keywords: string[]; topic?: string; industry?: string; target_audience?: string; tone?: string; word_count_target?: number; persona?: PersonaInfo; research_mode?: ResearchMode; config?: ResearchConfig; } export interface GroundingChunk { title: string; url: string; confidence_score?: number; } export interface GroundingSupport { confidence_scores: number[]; grounding_chunk_indices: number[]; segment_text: string; start_index?: number; end_index?: number; } export interface Citation { citation_type: string; start_index: number; end_index: number; text: string; source_indices: number[]; reference: string; } export interface GroundingMetadata { grounding_chunks: GroundingChunk[]; grounding_supports: GroundingSupport[]; citations: Citation[]; search_entry_point?: string; web_search_queries: string[]; } export interface BlogResearchResponse extends ResearchResponse { // Blog Writer specific extensions search_widget?: string; grounding_metadata?: GroundingMetadata; } export interface BlogOutlineSection { id: string; heading: string; subheadings: string[]; key_points: string[]; references: ResearchSource[]; target_words?: number; keywords: string[]; } export interface SourceMappingStats { total_sources_mapped: number; coverage_percentage: number; average_relevance_score: number; high_confidence_mappings: number; } export interface GroundingInsights { confidence_analysis?: { average_confidence: number; confidence_distribution: { high: number; medium: number; low: number }; high_confidence_sources_count: number; high_confidence_insights: string[]; }; authority_analysis?: { average_authority_score: number; authority_distribution: { high: number; medium: number; low: number }; high_authority_sources: Array<{ title: string; url: string; score: number }>; }; temporal_analysis?: { recency_score: number; trending_topics: string[]; temporal_balance: string; }; content_relationships?: { related_concepts: string[]; content_gaps: string[]; concept_coverage_score: number; gap_count: number; }; citation_insights?: { total_citations: number; citation_types: Record; citation_density: number; citation_quality_score: number; }; search_intent_insights?: { primary_intent: string; user_questions: string[]; intent_signals_count: number; }; quality_indicators?: { overall_quality_score: number; quality_grade: string; key_quality_factors: { confidence: number; authority: number; citations: number; coverage: number; }; }; } export interface OptimizationResults { overall_quality_score: number; improvements_made: string[]; optimization_focus: string; } export interface ResearchCoverage { sources_utilized: number; content_gaps_identified: number; competitive_advantages: string[]; } export interface BlogOutlineResponse { success: boolean; title_options: string[]; outline: BlogOutlineSection[]; // Additional metadata for enhanced UI source_mapping_stats?: SourceMappingStats; grounding_insights?: GroundingInsights; optimization_results?: OptimizationResults; research_coverage?: ResearchCoverage; } export interface BlogSectionResponse { success: boolean; markdown: string; citations: ResearchSource[]; continuity_metrics?: { flow?: number; consistency?: number; progression?: number }; } export interface BlogSEOActionableRecommendation { category: string; priority: 'High' | 'Medium' | 'Low' | string; recommendation: string; impact: string; } export interface BlogSEOAnalysisSummary { overall_grade: string; status: string; strongest_category: string; weakest_category: string; key_strengths: string[]; key_weaknesses: string[]; ai_summary: string; } export interface BlogSEOAnalyzeResponse { success: boolean; analysis_id?: string; overall_score: number; category_scores: Record; analysis_summary: BlogSEOAnalysisSummary; actionable_recommendations: BlogSEOActionableRecommendation[]; detailed_analysis?: any; visualization_data?: any; generated_at?: string; error?: string; } export interface BlogSEOApplyRecommendationsRequest { title: string; sections: Array<{ id: string; heading: string; content: string }>; outline: BlogOutlineSection[]; research: Record; recommendations: BlogSEOActionableRecommendation[]; persona?: Record; tone?: string; audience?: string; } export interface BlogSEOApplyRecommendationsResponse { success: boolean; title?: string; sections: Array<{ id: string; heading: string; content: string; notes?: string[] }>; applied?: Array<{ category: string; summary: string }>; error?: string; } export interface BlogSEOMetadataResponse { success: boolean; title_options: string[]; meta_descriptions: string[]; seo_title?: string; meta_description?: string; url_slug?: string; blog_tags: string[]; blog_categories: string[]; social_hashtags: string[]; open_graph: Record; twitter_card: Record; json_ld_schema?: Record; schema?: Record; // Legacy field name canonical_url?: string; reading_time?: number; focus_keyword?: string; generated_at?: string; optimization_score?: number; error?: string; } export interface BlogPublishResponse { success: boolean; platform: string; url?: string; post_id?: string; } export interface TaskStatusResponse { task_id: string; status: 'pending' | 'running' | 'completed' | 'failed'; created_at: string; progress_messages: Array<{ timestamp: string; message: string; }>; result?: T; error?: string; // Subscription error details (set by backend when subscription limit is exceeded) error_status?: number; // HTTP status code (429 for usage limit, 402 for subscription expired) error_data?: { error?: string; message?: string; provider?: string; usage_info?: { provider?: string; current_calls?: number; limit?: number; type?: string; breakdown?: { gemini?: number; openai?: number; anthropic?: number; mistral?: number; }; }; [key: string]: any; // Allow additional fields }; } export const blogWriterApi = { // Async polling endpoints async startResearch(payload: BlogResearchRequest): Promise<{task_id: string; status: string}> { const { data } = await apiClient.post("/api/blog/research/start", payload); return data; }, async pollResearchStatus(taskId: string): Promise { const { data } = await pollingApiClient.get(`/api/blog/research/status/${taskId}`); return data; }, async startOutlineGeneration(payload: { research: BlogResearchResponse; persona?: PersonaInfo; word_count?: number; custom_instructions?: string }): Promise<{task_id: string; status: string}> { const { data } = await aiApiClient.post("/api/blog/outline/start", payload); return data; }, async pollOutlineStatus(taskId: string): Promise { const { data } = await pollingApiClient.get(`/api/blog/outline/status/${taskId}`); return data; }, async getContinuity(sectionId: string): Promise<{ section_id: string; continuity_metrics?: Record }> { const { data } = await apiClient.get(`/api/blog/section/${encodeURIComponent(sectionId)}/continuity`); return data; }, async sectionOriginalityTools(payload: { section_id: string; title?: string; content: string; }): Promise<{ success: boolean; section_id: string; cannibalization?: any; matches?: Array<{ id?: string; score?: number; excerpt?: string }>; error?: string; }> { const { data } = await apiClient.post('/api/blog/section/tools/originality', payload); return data; }, async sectionInternalLinkTools(payload: { section_id: string; title?: string; content: string; }): Promise<{ success: boolean; section_id: string; suggestions?: Array<{ url: string; relevance?: number; final_score?: number; confidence?: number; reason?: string; }>; }> { const { data } = await apiClient.post('/api/blog/section/tools/internal-links', payload); return data; }, async sectionFactCheckTools(payload: { section_id: string; title?: string; content: string; }): Promise<{ success: boolean; section_id: string; verification?: any; citations?: Array<{ source?: string; title?: string; relevance?: number; citation_text?: string; }>; }> { const { data } = await apiClient.post('/api/blog/section/tools/fact-check', payload); return data; }, async sectionOptimizeTools(payload: { section_id: string; title?: string; content: string; keywords?: string[]; goal?: string; }): Promise<{ success: boolean; section_id: string; optimized_content?: string; changes_made?: string[]; diff_summary?: string; error?: string; }> { const { data } = await apiClient.post('/api/blog/section/tools/optimize', payload); return data; }, // Blog Rewrite API async rewriteBlog(payload: { title: string; sections: Array<{ id: string; heading: string; content: string; }>; research: BlogResearchResponse; outline: BlogOutlineSection[]; feedback: string; tone?: string; audience?: string; focus?: string; }): Promise<{ success: boolean; taskId?: string; error?: string; }> { const { data } = await aiApiClient.post('/api/blog/rewrite/start', payload); return data; }, async pollRewriteStatus(taskId: string): Promise { const { data } = await pollingApiClient.get(`/api/blog/rewrite/status/${taskId}`); return data; }, async applySeoRecommendations(payload: BlogSEOApplyRecommendationsRequest): Promise { const { data } = await apiClient.post('/api/blog/seo/apply-recommendations', payload); return data; }, // Flow Analysis APIs async analyzeFlowBasic(payload: { title: string; sections: Array<{ id: string; heading: string; content: string; }>; }): Promise<{ success: boolean; analysis?: { overall_flow_score: number; overall_consistency_score: number; overall_progression_score: number; sections: Array<{ section_id: string; heading: string; flow_score: number; consistency_score: number; progression_score: number; suggestions: string[]; }>; overall_suggestions: string[]; }; mode: string; error?: string; }> { const { data } = await aiApiClient.post('/api/blog/flow-analysis/basic', payload); return data; }, async analyzeFlowAdvanced(payload: { title: string; sections: Array<{ id: string; heading: string; content: string; }>; }): Promise<{ success: boolean; analysis?: { overall_flow_score: number; overall_consistency_score: number; overall_progression_score: number; sections: Array<{ section_id: string; heading: string; flow_score: number; consistency_score: number; progression_score: number; detailed_analysis: string; suggestions: string[]; }>; }; mode: string; error?: string; }> { const { data } = await aiApiClient.post('/api/blog/flow-analysis/advanced', payload); return data; }, async refineOutline(payload: { outline: BlogOutlineSection[]; operation: string; section_id?: string; payload?: any }): Promise { const { data } = await apiClient.post("/api/blog/outline/refine", payload); return data; }, async generateSection(payload: { section: BlogOutlineSection; keywords?: string[]; tone?: string; persona?: PersonaInfo; mode?: 'draft' | 'polished' }): Promise { const { data } = await apiClient.post("/api/blog/section/generate", payload); return data; }, // Removed old seoAnalyze - now using comprehensive SEO analysis through modal async seoMetadata(payload: { content: string; title?: string; keywords?: string[] }): Promise { const { data } = await apiClient.post("/api/blog/seo/metadata", payload); return data; }, async publish(payload: { platform: 'wix' | 'wordpress'; html: string; metadata: BlogSEOMetadataResponse; schedule_time?: string }): Promise { const { data } = await apiClient.post("/api/blog/publish", payload); return data; }, async generateSEOTitles(payload: { research: BlogResearchResponse; outline: BlogOutlineSection[]; primary_keywords: string[]; secondary_keywords: string[]; content_angles: string[]; search_intent?: string; word_count?: number; }): Promise<{ success: boolean; titles: string[] }> { const { data } = await aiApiClient.post('/api/blog/titles/generate-seo', payload); return data; }, async generateIntroductions(payload: { blog_title: string; research: BlogResearchResponse; outline: BlogOutlineSection[]; sections_content: Record; primary_keywords: string[]; search_intent?: string; }): Promise<{ success: boolean; introductions: string[] }> { const { data } = await aiApiClient.post('/api/blog/introductions/generate', payload); return data; }, // Enhanced Outline Methods async enhanceSection(section: BlogOutlineSection, focus: string = 'general improvement'): Promise { const { data } = await apiClient.post("/api/blog/outline/enhance-section", section, { params: { focus } }); return data; }, async optimizeOutline(payload: { outline: BlogOutlineSection[] }, focus: string = 'general optimization'): Promise<{ outline: BlogOutlineSection[] }> { const { data } = await apiClient.post("/api/blog/outline/optimize", payload, { params: { focus } }); return data; }, async rebalanceOutline(payload: { outline: BlogOutlineSection[] }, targetWords: number = 1500): Promise<{ outline: BlogOutlineSection[] }> { const { data } = await apiClient.post("/api/blog/outline/rebalance", payload, { params: { target_words: targetWords } }); return data; } }; // Medium blog generation (≤1000 words) export interface MediumSectionOutlinePayload { id: string; heading: string; keyPoints?: string[]; subheadings?: string[]; keywords?: string[]; targetWords?: number; references?: ResearchSource[]; } export interface MediumGenerationRequestPayload { title: string; sections: MediumSectionOutlinePayload[]; persona?: PersonaInfo; tone?: string; audience?: string; globalTargetWords?: number; researchKeywords?: string[]; // Original research keywords for better caching } export interface MediumGenerationResultPayload { success: boolean; title: string; sections: Array<{ id: string; heading: string; content: string; wordCount: number; sources?: ResearchSource[] }>; model?: string; generation_time_ms?: number; } export const mediumBlogApi = { async startMediumGeneration(payload: MediumGenerationRequestPayload): Promise<{ task_id: string; status: string }> { const { data } = await aiApiClient.post('/api/blog/generate/medium/start', payload); return data; }, async pollMediumGeneration(taskId: string): Promise { const { data } = await pollingApiClient.get(`/api/blog/generate/medium/status/${taskId}`); return data; } }; // Assistive Writing API export interface AssistiveSuggestion { text: string; confidence: number; sources: Array<{ title: string; url: string; text?: string; author?: string; published_date?: string; score: number; }>; } export interface AssistiveSuggestionResponse { success: boolean; suggestions: AssistiveSuggestion[]; } export const assistiveWritingApi = { async getSuggestion(text: string): Promise { const { data } = await aiApiClient.post('/api/writing-assistant/suggest', { text }); return data; } };