
    &i'!                     0   d Z ddlmZ ddlmZmZmZ ddlmZ ddl	m
Z
mZmZmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ de
ded   fdZde
ded   fdZde
de
fdZde
de
fdZddedz  fdZ	 	 	 ddedededz  dedz  de
f
dZdede
dede
fdZ y)zg
Main SEO Campaign Graph
Orchestrates the full SEO campaign workflow with human-in-the-loop interrupts
    )Literal)
StateGraphSTARTEND)BaseCheckpointSaver)SEOCampaignStateCampaignPhasecreate_initial_statetransition_phase)research_phase)content_phase)serp_optimization_phase)link_discovery_phase)generate_report_phasestatereturnawait_approvalskip_to_reportc                 J    | j                  d      r| j                  d      ryy)z
    Conditional edge: Check if human review is required

    Returns "await_approval" if there are pending approvals,
    otherwise "skip_to_report" to proceed directly to reporting.
    requires_human_reviewpending_approvalsr   r   )get)r   s    H/var/www/html/eventheodds/langgraph-service/graphs/seo_campaign_graph.pycheck_human_review_requiredr      s#     yy()eii8K.L    executestill_pendingall_rejectedc                 0   | j                  dg       }| j                  dg       }t        |D cg c]  }|j                  d      dk(  s| c}      }|dkD  ryt        |D cg c]  }|j                  d      dk(  s| c}      }|dkD  ryy	c c}w c c}w )
z
    Conditional edge: Check approval status after human review

    Returns:
    - "execute" if any opportunities were approved
    - "still_pending" if still awaiting approvals
    - "all_rejected" if all were rejected
    r   link_opportunitiesstatuspendingr   r   approvedr   r    )r   len)r   r   	link_oppsopending_countapproved_counts         r   check_approval_statusr+   #   s     		"5r:		.3I $5VqxI9UVWMq YP!%%/Z2O!PQN W
 Qs   BB"B<Bc           
      
  K   t        dt        | j                  dg              d       | j                  dg       }|D cg c]  }|j                  d      dk(  s| }}|D cg c]  }|j                  d      dk(  s| }}|D cg c]  }|j                  d      dk(  s| }}t        |      | d	<   || d<   |sd
| d<   t        dt        |       dt        |       dt        |              | S c c}w c c}w c c}w w)a  
    Human approval interrupt node

    This node is configured as an interrupt point. When the graph reaches this node,
    execution pauses and waits for human input via the resume API.

    The human can:
    - Approve opportunities (set status to "approved", optionally edit pitch)
    - Reject opportunities (set status to "rejected", provide reason)

    After human input, the graph resumes and this node processes the updated state.
    z&[HumanApproval] Awaiting approval for r   z opportunitiesr"   r#   r%   rejectedr$   links_approvedFr   z[HumanApproval] Approved: z, Rejected: z, Still pending: )printr&   r   )r   r'   r(   r%   r-   r   s         r   await_human_approvalr0   <   s     
23uyyATVX7Y3Z2[[i
jk 		.3I$Fah:(EFHF$Fah:(EFHF )J1QUU8_	-IQJMJ!(mE
!.E
 ).%&	&s8}o\#h-Pabefsbtau
vwL GFJs<   ?DC4C4D%C9?C9D	C>#C>'ADc                 ~  K   t        d       | j                  dg       }|D cg c]  }|j                  d      dk(  s| }}|D ];  }d|d<   t        d      j                  j	                         j                         |d<   = t        dt        |       d	       t        | t        j                        } | S c c}w w)
z
    Execute approved link outreach

    Only runs after human approval. Sends outreach emails for approved opportunities.
    z?[ExecuteOutreach] Executing outreach for approved opportunitiesr"   r#   r%   executeddatetimeexecuted_atz[ExecuteOutreach] Executed z outreach campaigns)
r/   r   
__import__r3   utcnow	isoformatr&   r   r	   REPORT)r   r'   r(   r%   opps        r   execute_approved_outreachr:   _   s      
KM		.3I$Fah:(EFHF  R"H'
3<<CCEOOQMR 
'H6I
JK UM$8$89EL Gs   "B=B8B8A;B=Ncheckpointerc                    t        t              }|j                  dt               |j                  dt               |j                  dt
               |j                  dt               |j                  dt               |j                  dt               |j                  dt               |j                  t        d       |j                  dd       |j                  dd       |j                  dd       |j                  dt        ddd       |j                  dt        dt        dd	       |j                  dd       |j                  dt               |j!                  | dg
      }|S )af  
    Create the main SEO campaign workflow graph

    Phases:
    1. Research - Gather GSC data, competitors, SERP features
    2. Content - Prioritize and queue content generation
    3. SERP Features - Queue optimizations for snippets, PAA, AI Overviews
    4. Link Discovery - Find white-hat link opportunities
    5. Human Review (INTERRUPT) - Pause for human approval of link opportunities
    6. Execute - Send approved outreach
    7. Report - Generate final campaign report

    The graph uses interrupt_before on the human_review node, allowing
    campaigns to pause and resume after human approval.
    researchcontentserp_featureslink_discoveryhuman_reviewexecute_outreachreportr   r   )r;   interrupt_before)r   r   add_noder   r   r   r   r0   r:   r   add_edger   add_conditional_edgesr   r+   r   compile)r;   graphcompileds      r   create_seo_campaign_graphrK   x   s@   " '(E 
NN:~.	NN9m,	NN?$;<	NN#%9:	NN>#78	NN%'@A	NN823 
NN5*%	NN:y)	NN9o.	NN?$45 
#,&	
 
) $	
 
NN%x0 
NN8S! }}!()  H
 Or   site_idcampaign_typeconfigc                    K   ddl }t        |j                               }t        | |||xs i       }t	        |      }dd|ii}|j                  ||       d{   }	|	S 7 w)a  
    Create and run a new SEO campaign

    Args:
        site_id: The site ID to run the campaign for
        campaign_type: Type of campaign (zero_click_authority, link_building, etc.)
        config: Optional campaign configuration
        checkpointer: Optional checkpointer for state persistence

    Returns:
        Final campaign state (or paused state if awaiting human review)
    r   N)rL   campaign_idrM   rN   configurable	thread_id)uuidstruuid4r
   rK   ainvoke)
rL   rM   rN   r;   rS   rP   initial_staterI   thread_configfinal_states
             r   run_campaignrZ      ss     $  djjl#K(#|	M &l3E $k;%?@Mm]CCK Ds   AA"A A"rP   updated_statec                 h   K   t        |      }dd| ii}|j                  ||       d{   }|S 7 w)a6  
    Resume a paused campaign after human approval

    Args:
        campaign_id: The campaign ID to resume
        updated_state: State with updated approvals
        checkpointer: Checkpointer with persisted state

    Returns:
        Final campaign state (or paused state if still awaiting approvals)
    rQ   rR   N)rK   rV   )rP   r[   r;   rI   rX   rY   s         r   resume_campaignr]      sB       &l3E#k;%?@M m]CCK Ds   '202)N)zero_click_authorityNN)!__doc__typingr   langgraph.graphr   r   r   langgraph.checkpoint.baser   state.campaign_stater   r	   r
   r   nodes.research_noder   nodes.content_noder   nodes.serp_features_noder   nodes.link_discovery_noder   nodes.performance_noder   r   r+   r0   r:   rK   rT   dictrZ   r]    r   r   <module>rk      s  
  2 2 9  / , < : 8	'7 	GDf<g 	!1 g>h6i 2 &6  ;K  F+; @P 2C,?$,F CR 0/3	%%% 4K% &,	%
 %P# & 	r   