
    ,iI                         d Z ddlmZ ddddddZdedeeef   fdZdedeeef   fdZdedeeef   fd	Zdedeeef   fd
Z	dededeeef   fdZ
dedefdZdedefdZdededefdZdedeeef   fdZy)u   
analyzer.py — Rule-based scoring engine and recommendation generator.

No LLM API calls. Pure deterministic scoring from scraped data.
    )Tupleg?website_speedmobile_experienceonline_presence
seo_basicsai_readinessdatareturnc           	      ,   | j                  di       }| j                  di       }|s|j                  dd      sdddifS |sddd	ifS |j                  d
d      }|j                  dd      }|j                  dd      }|j                  dd      }|dz  |dz  z   }|dkD  r|dz  }n|dkD  r|dz  }n
|dkD  r|dz  }|dkD  r|dz  }n|dkD  r|dz  }n
|dkD  r|dz  }t        dt        dt        |                  }|||||rt        |dz  d      ndd}	||	fS ) zp
    Score website speed based on PageSpeed performance metrics.
    Returns (score 0-100, breakdown dict).
    	pagespeedwebsiteis_reachableFr   reasonWebsite unreachable   z*PageSpeed data unavailable, site reachablemobile_performance_scoredesktop_performance_scoremobile_fcp_msi'  mobile_lcp_msi:  gffffff?g333333?i     i     i     iX  i  i	  d        N)mobile_performancedesktop_performancer   r   load_time_seconds)getmaxminround)
r
   pswsmobile_perfdesktop_perf
mobile_fcp
mobile_lcp
perf_scorescore	breakdowns
             7/mnt/e/genesis-system/scripts/heatmap_audit/analyzer.py_score_website_speedr.      sh   
 
+r	"B	)R	 Bbff^U382333HJKKK&&3Q7K665q9L/J/J #s(:;J Db
	d	a
	d	a
Db
	d	a
	d	a
3sE*-./E *+##<FU:#4a8DI )    c                    | j                  di       }| j                  di       }|j                  dd      sdddifS d}i }|j                  d|j                  dd            }|r|d	z  }||d
<   |j                  dd      }|t        |dz        z  }||d<   |j                  dd      }|t        |dz        z  }||d<   |j                  dd      }|dk  r|dz  }n|dk  r|dz  }n
|dk  r|dz  }||d<   t        dt        d|            |fS )zG
    Score mobile-friendliness from PageSpeed and direct scraping.
    r   r   r   Fr   r   r   has_mobile_viewportr   has_viewportr   g?r   mobile_accessibility_score333333?accessibility
mobile_cls      ?g?r   g      ?
   g      ?   clsr   )r    r#   r!   r"   )	r
   r$   r%   r+   r,   r2   r&   a11ycls_vals	            r-   _score_mobile_experiencer=   N   sH    
+r	"B	)R	 B66.%(82333EI 66/8Mu1UVL ,In &&3Q7K	U;$%%E&1I"# 66.2D	U4$;E!%Io ff\3'G#~	D	C
Ieq#c5/"I--r/   c                    | j                  di       }| j                  di       }d}i }|j                  dd      }|dk\  r|dz  }n+|dk\  r|dz  }n |d	k\  r|d
z  }n|dk\  r|dz  }n
|dkD  r|dz  }||d<   |j                  dd      }|j                  dg       }|t        |      z   }t        d|dz        }	||	z  }||d<   |j                  dd      }
|
r|dz  }|
|d<   |j                  dd      }|r|d
z  }||d<   |j                  dd      }|dk\  r|d
z  }n
|dk\  r|dz  }||d<   t        dt        d	|            |fS )zM
    Score online visibility from Brave Search and website social links.
    braver   r   search_result_countr           r   r   r8   r9   search_resultssocial_profile_countpage_social_linkssocial_profileshas_google_businessFgoogle_businesshas_directory_listingsdirectory_listingsreview_mentionsr   r   )r    lenr"   r!   )r
   r?   r%   r+   r,   result_countsocial_countpage_socialcombined_socialsocial_scorehas_gbphas_dirsrL   s                r-   _score_online_presencerU   x   s    HHWb!E	)R	 BEI 992A6Lt								
".I 993Q7L&&,b1K"S%55Or?Q./L	\E#2I  ii-u5G#*I  yy159H&.I"# ii 115O!	A	#2I q#c5/"I--r/   c                    | j                  di       }| j                  di       }|j                  dd      sdddifS d}i }|j                  dd      }|r|d	z  }||d<   |j                  d
d      }|j                  dd      }|r!|dz  }dt        |      cxk  rdk  rn n|dz  }||d
<   t        |      |d<   |j                  dd      }|j                  dd      }	|r!|dz  }dt        |	      cxk  rdk  rn n|dz  }||d<   |j                  dd      }
|
dk(  r|dz  }n
|
dkD  r|dz  }|
|d<   |j                  dd      r|dz  }|j                  dd      |d<   |j                  dd      r|dz  }|j                  dd      |d<   |j                  dd      }|j                  dd      }|dkD  rd||z  z
  }|t        |dz        z  }n|dz  }||d<   ||d<   |j                  dd      }|t        |dz        z  }||d <   |j                  d!d      }|d"k\  r|dz  }n|d#k\  r|d$z  }n
|d%k\  r|dz  }||d!<   t        dt	        d&|            |fS )'zD
    Score basic SEO setup from website scraping and PageSpeed.
    r   r   r   Fr   r   r   has_sslr   	has_title	title_tag r8   r   <   r9   title_lengthhas_meta_descriptionmeta_descriptionx      h1_countr   has_schema_markup
has_schemahas_og_tagstotal_imagesimages_without_altr7   mobile_seo_scorer4   pagespeed_seo
word_countrB      r   2   r   )r    rM   r#   r!   r"   )r
   r%   r$   r+   r,   rW   rX   titlehas_metametara   re   missing_alt	alt_ratiops_seori   s                   r-   _score_seo_basicsrr      s    
)R	 B	+r	"B66.%(82333EI ffY&G"Ii {E*IFF;#EU!r!QJE&Ik #E
In vv,e4H66$b)D#d)"s"QJE(0I$% vvj!$H1}	A
$Ij 
vv!5) ff%8%@Il 
vvmU#
!vvmU;Im 66.!,L&&-q1Ka;56	y2~&&
&1I"# ,In VV&*F	U6D=!!E!'Io a(JS
	s	
	r	
(Ilq#c5/"I--r/   other_scoresc                    | j                  di       }i }t        |j                               t        t	        |      d      z  }t        dt        dt        d|dz  z
                    }||d<   |}|j                  dd      s
|d	z  }d
|d<   |j                  dd      s
|dz  }d
|d<   |j                  dd      s
|dz  }d
|d<   |j                  dd      sd}d
|d<   t        dt        d|            |fS )u  
    Score AI readiness — how much the business would benefit from AI.
    INVERSE logic: lower scores in other areas = HIGHER AI opportunity.
    A perfect website scores LOW on AI readiness (less need for AI).
    A terrible website scores HIGH (massive AI opportunity).
    r   r   rC   P   g333333?base_opportunityhas_chat_widgetFr   Tno_chat_widgethas_booking_system   no_booking_systemhas_phone_visibler9   phone_not_visibler   _   site_unreachabler   r   )r    sumvaluesr!   rM   r"   r#   )r
   rs   r%   r,   	other_avg
base_scorer+   s          r-   _score_ai_readinessr     s    
)R	 BI L'')*S\1BA-FFIRRrY_'=!>?@J$.I !E 66#U+
&*	"#66&.
)-	%&66%u-
)-	%& 66.%((,	$%q#c5/"I--r/   scraped_datac                     t        |       \  }}t        |       \  }}t        |       \  }}t        |       \  }}||||d}	t	        | |	      \  }
}||d||d||d||d|
|dd}|S )zp
    Calculate all category scores from scraped data.
    Returns dict with category -> {score, breakdown}.
    )r   r   r   r   )r+   r,   r   )r.   r=   rU   rr   r   )r   speed_scorespeed_bdmobile_score	mobile_bdpresence_scorepresence_bd	seo_scoreseo_bdpreliminaryai_scoreai_bdscoress                r-   calculate_scoresr   0  s    
 1>K6|DL)"8"FNK),7Iv %))	K *,DOHe $/XF'3)L%3+N )?"*?F Mr/   r   c           	         d}t         j                         D ]H  \  }}| j                  |i       }t        |t              r||j                  dd      |z  z  }A|||z  z  }J t        dt        dt        |                  S )z2
    Weighted average of all category scores.
    g        r+   r   r   )CATEGORY_WEIGHTSitemsr    
isinstancedictr!   r"   r#   )r   totalcategoryweight	cat_scores        r-   calculate_overall_scorer   N  s     E,224 (&JJx,	i&Y]]7A.77EY''E( q#c5<())r/   c                    |j                  di       }|j                  di       }g }| j                  di       }t        |t              r|j                  dd      n|}t        |t              r|j                  di       ni }|dk  r;|j                  d      }|r|d	k7  rd
| d}	nd}	|j                  dd|	dd|z
  d       | j                  di       }
t        |
t              r|
j                  dd      n|
}t        |
t              r|
j                  di       ni }|dk  r3|j                  dd      }|sd}nd}|j                  dd|dd|z
  d       | j                  di       }t        |t              r|j                  dd      n|}t        |t              r|j                  di       ni }|dk  rT|j                  dd      }|j                  dd      }|sd}n
|dk  rd}nd }|j                  d!d"||d#k  rdnd$d|z
  d       | j                  d%i       }t        |t              r|j                  dd      n|}t        |t              r|j                  di       ni }|dk  rg }|j                  d&d'      s|j                  d(       |j                  d)d'      s|j                  d*       |j                  d+d'      s|j                  d,       |j                  d-d.      dk(  r|j                  d/       |rd0j	                  |d1d       }d2| d3}nd4}|j                  d5d6|d$d|z
  d       | j                  d7i       }t        |t              r|j                  dd      n|}t        |t              r|j                  di       ni }|dk\  rg }|j                  d8      r|j                  d9       |j                  d:      r|j                  d;       |j                  d<      r|j                  d=       |rd>j	                  |d1d       }d?| d@}ndA}|j                  dBdC|d|d       |j                  dD d'E       |d1dF S )Gz
    Generate top 3-5 actionable recommendations based on weakest areas.
    Each recommendation is a dict with: category, title, detail, impact.
    r   r   r   r+   r   r,   rk   r   unknownzYour site takes z seconds to load on mobile. 53% of mobile visitors leave after just 3 seconds. An AI-powered website loads instantly and never loses a customer to slow speeds.zYour website is underperforming on speed. 53% of mobile visitors leave after just 3 seconds of loading. An AI-powered website loads instantly and never loses a customer to slow speeds.zWebsite SpeedzYour website is too slowhighr   )r   rl   detailimpactpriorityr   r[   r2   FzYour website isn't mobile-optimised. 68% of Australian tradies' customers search on their phone. Without a mobile-friendly site, you're invisible to most potential customers.zYour mobile experience needs improvement. Customers on phones see a slow, unstable layout. An AI receptionist captures leads 24/7 even when your website can't.zMobile ExperiencezLosing mobile customersr   rG   rI   zWe couldn't find a Google Business Profile for your company. This is the #1 way local customers find tradies. Businesses with a Google profile get 7x more clicks than those without.   u   Your online presence is limited. Your competitors are showing up on social media, directories, and review sites — capturing leads that should be yours. AI can manage your online presence 24/7.zWe found limited online visibility for your business. Your competitors are getting the leads you're missing. An AI-powered presence manager keeps you visible everywhere, always.zOnline Presencez#Competitors are more visible onliner   mediumr   rW   Tzlacks HTTPS securityr]   zis missing its meta descriptionrX   zhas no proper title tagra   r   zis missing its main headingz, NzYour website z. This means Google can't properly show your business in search results. You're invisible to customers actively searching for your services.zYour SEO setup needs work. Google can't properly understand and rank your website. Customers searching for your services are finding your competitors instead.z
SEO BasicszGoogle can't find your businessr	   rx   z)no live chat to capture after-hours leadsr{   zno online booking systemr}   zphone number hard to findz; zYour business has u   . An AI receptionist answers every call, books jobs, and follows up with customers — even at 2am. Your competitors who adopt AI first will capture the leads you're currently losing.zYour business has significant opportunity to benefit from AI. An AI receptionist can answer every call, book jobs, and follow up automatically. Businesses using AI report 40% more booked jobs.zAI Readinessz"High opportunity for AI automationc                     | d   S )Nr    )rs    r-   <lambda>z*generate_recommendations.<locals>.<lambda>	  s
    q} r/   )keyreverser9   )r    r   r   appendjoinsort)r   r   r%   r$   recommendationsspeedr   r   	load_timespeed_detailmobiler   r   viewportr   presencer   r   rO   rS   seor   r   issues
issue_textaiai_score_valr   missingmissing_texts                                 r-   generate_recommendationsr   \  s   
 
		)R	(B			+r	*BO JJ+E+5eT+B%))GQ'K-7t-Duyyb)"HRLL!45	i/"9+ .c c c 
 	'/"k) 
 	 ZZ+R0F-7-E6::gq)6L/9&$/G

;+RIb==7` W 
 	+.l* 
 	 zz+R0H1;Hd1KX\\'1-QYN3=h3M(,,{B/SUK"'8!<//"3U;Z 
 AQ W 
 	): . 3fn, 
 	 **\2
&C'1#t'<##I)3C)>SWW["%BF2~zz)T*MM01zz0$7MM;<zz+t,MM34::j!$)MM786"1:.J
| ,V V 8 
 	$6i 
 	 
NB	'B)3B)=266'1%2L'1"d';BFF;#Er99%&NNFG99()NN5699()NN6799WRa[1L$\N 3B B R 
 	&9$ 
 	 4dC2Ar/   c                     t        |       }t        |      }t        ||       }d|i|d<   | j                  d      xs i }|j                  d      |j                  d      d|d<   ||fS )zU
    Main analysis entry point.
    Returns (scores_dict, recommendations_list).
    r+   overallr   detected_providerest_monthly_cost)r   r   _provider_intel)r   r   r   r    )r   r   r   r   r   s        r-   analyzer     s    
 l+F%f-G.v|DO !'*F9 y)/RG$[[)<=#KK(:;!F
 ?""r/   N)__doc__typingr   r   r   intr.   r=   rU   rr   r   r   r   listr   r   r   r/   r-   <module>r      s$     1t 1c4i(8 1h'.4 '.E#t),< '.T4. 4.%T	*: 4.nR.D R.U39%5 R.j%.d %.$ %.5d;K %.X4 D <*D *S *nT n n$ nb#$ #5t#4 #r/   