
    &i                         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mZ ddlmZmZmZmZ de
de
fd	Zde
de
fd
Zde
de
fdZde
ded   fdZde
de
fdZddedz  fdZy)z]
Link Approval Subgraph
Dedicated workflow for link opportunity discovery and human approval
    )Literal)
StateGraphSTARTEND)BaseCheckpointSaver)SEOCampaignStateCampaignPhaseLinkOpportunityLinkOpportunityStatustransition_phase)link_discovery_phaseis_quality_opportunitygenerate_pitchLINK_QUALITY_THRESHOLDSstatereturnc           	        K   t        dt        | j                  dg              d       | j                  dg       }g }g }|D ]  }t        |j                  dd      dz  d      }t        |j                  dd      d	z  d      }|j                  d
d      }|dz  |dz  z   |dz  z   }t	        |      r!t        |d      |d<   |j                  |       t        j                  j                  |d<   d|d<   |j                  |        |j                  d d       t        dt        |       dt        |              ||z   | d<   || d<   | S w)z
    Score and filter link opportunities

    Applies strict quality filters:
    - Domain Authority >= 40
    - Monthly Traffic >= 5,000
    - Relevance Score >= 0.8
    - No blacklisted patterns
    z[ScoreOpportunities] Scoring link_opportunities opportunitiesdomain_authorityr   d   g      ?monthly_trafficiP  relevance_scoreg333333?g?   composite_scorestatuszDid not meet quality thresholdsrejection_reasonc                 &    | j                  dd      S )Nr   r   )get)xs    I/var/www/html/eventheodds/langgraph-service/graphs/link_approval_graph.py<lambda>z%score_opportunities.<locals>.<lambda>;   s    aee$5q9     T)keyreversez [ScoreOpportunities] Qualified: z, Rejected: pending_approvals)printlenr   minr   roundappendr   REJECTEDvaluesort)	r   opportunitiesscoredrejectedoppda_scoretraffic_score	relevancer   s	            r!   score_opportunitiesr6      sd     
)#eii8Lb.Q*R)SSa
bcII2B7MFH !sww115;SACGG$5q9EA3GGG-q1	#c>mc.ABiRUoV "#&%*?A%>C!"MM#1::@@CM&GC"#OOC !$ KK94KH	,S[Mc(m_
UV"(8"3E
!'E
Ls   EEc           	        K   t        dt        | j                  dg              d       dddd}| j                  dg       D ]-  }|j                  d      rt        ||       d	{   }||d<   / t        d
       | S 7 w)zC
    Generate personalized pitches for qualified opportunities
    z)[GeneratePitches] Generating pitches for r&   r   zeventheodds.aizsports betting analyticszAFree sports analytics tools with data from 50,000+ games analyzed)domaintopic
value_proppitch_draftNz#[GeneratePitches] Pitches generated)r'   r(   r   r   )r   	site_infor2   pitchs       r!   generate_pitchesr>   E   s      
5c%))DWY[:\6]5^^l
mn #+YI yy,b1 'ww}%(i88E!&C'
 
/1L 9s   ABB'B (Bc           	      <  K   t        dt        | j                  dg              d       | j                  dg       }|D cg c]1  }|j                  d      t        j                  j
                  k(  s0|3 }}|D cg c]1  }|j                  d      t        j                  j
                  k(  s0|3 }}|D cg c]1  }|j                  d      t        j                  j
                  k(  s0|3 }}t        |      | d<   || d<   |sd| d<   | S c c}w c c}w c c}w w)z
    Human approval interrupt point

    Waits for human to:
    - Approve opportunities (optionally edit pitch)
    - Reject opportunities (provide reason)
    z([AwaitApproval] Waiting for approval of r&   r   r   links_approvedFrequires_human_review)r'   r(   r   r   APPROVEDr-   r,   PENDING)r   pendingoapprovedr1   still_pendings         r!   await_approvalrH   [   s     
4SCVXZ9[5\4]]k
lm ii+R0G"^aaeeHo9N9W9W9]9]&]^H^"^aaeeHo9N9W9W9]9]&]^H^ 'b1155?>S>[>[>a>a+aQbMb!(mE
!.E
).%&L _^bs;   ?D1D3D7D=1D/D3D91D+D/-DexecuterD   donec                     | j                  dg       }| j                  dg       D cg c]0  }|j                  d      t        j                  j                  k(  r|2 }}|ry|ryyc c}w )z+Check if we should execute, wait, or finishr&   r   r   rD   rJ   rK   )r   r   rB   r-   )r   rD   rE   rF   s       r!   check_approval_statusrM   t   sr    ii+R0G 99%92> La55?&;&D&D&J&JJ  LH L 	Ls   5A%c                 8  K   t        d       ddlm} |j                         j                         }| j	                  dg       D ]Q  }|j	                  d      t
        j                  j                  k(  s0t
        j                  j                  |d<   ||d<   S | S w)z
    Execute outreach for approved opportunities

    In a full implementation, this would:
    - Send emails via the email service
    - Track delivery status
    - Log to compliance system
    z-[ExecuteApproved] Executing approved outreachr   )datetimer   r   executed_at)	r'   rO   utcnow	isoformatr   r   rB   r-   EXECUTED)r   rO   nowr2   s       r!   execute_approvedrU      s      
9;!
//

%
%
'Cyy-r2 %778 5 > > D DD1::@@CM!$C	% Ls   A1B4&BNcheckpointerc                 2   t        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t        t        d       |j                  dt               |j                  | dg      }|S )ab  
    Create the link approval subgraph

    Flow:
    1. Discover - Find link opportunities
    2. Score - Apply quality filters
    3. Pitch - Generate personalized pitches
    4. Approval (INTERRUPT) - Wait for human approval
    5. Execute - Send approved outreach

    This graph can be used standalone or as a subgraph within the main campaign.
    discoverscorer>   rH   rJ   rI   )rV   interrupt_before)r   r   add_noder   r6   r>   rH   rU   add_edger   add_conditional_edgesrM   r   compile)rV   graphcompileds      r!   create_link_approval_graphra      s     '(E 
NN:34	NN7/0	NN%'78	NN#^4	NN9./ 
NN5*%	NN:w'	NN7./	NN%'78 
 	
 
NN9c" }}!*+  H
 Or#   )N)__doc__typingr   langgraph.graphr   r   r   langgraph.checkpoint.baser   state.campaign_stater   r	   r
   r   r   nodes.link_discovery_noder   r   r   r   r6   r>   rH   rM   rU   ra    r#   r!   <module>ri      s   
  2 2 9  )%5 ):J )X"2 7G , 0 5E 2!1 g>Z6[ "2 7G 4/-@4-G /r#   