+
    *
j                        R t ^ RIHt ^ RIt^ RIt^ RIt^ RIHt ]P                  P                  RR4      t
RsR tR tR R	 ltRR
 R lltR R ltRR R lltR R ltR R ltR# )u  
insights_module.py — Leitura de métricas Meta + Vista Social do Postgres VPS.

Schema: six_hype.* no command_center_postgres (127.0.0.1:55433).
Workflows n8n alimentam o banco diariamente (meta_insights_pull, vs_snapshots, vs_inbox_sync).

Env:
  INSIGHTS_DB_DSN  → ex: postgresql://command_center_app:senha@127.0.0.1:55433/command_center
                     (em prod: leia do .env de produção; em dev: leia do túnel SSH)
)annotationsN)OptionalINSIGHTS_DB_DSN c                     \         '       g   R#  ^ RIp ^ RIp \        f   ^ RIHp TP                  ^^\         4      s\        P                  4       #   \         d     \	        R\
        P                  R7        R# i ; i)u?   Conexão lazy. Usa psycopg2 se disponível; senão, log + None.NuX   ⚠ psycopg2 não instalado · insights desabilitados. Rode: pip install psycopg2-binary)file)pool)DSNpsycopg2psycopg2.extrasModuleNotFoundErrorprintsysstderr_poolr   SimpleConnectionPoolgetconn)r
   r   s     '/opt/apps/studio-api/insights_module.py	_get_connr      sg     3
 }!))!Q4==?  horoyoyzs   A &A;:A;c                `    \         '       d"   V '       d   \         P                  V 4       R # R # R # N)r   putconn)conns   &r   _releaser   )   s    ud u    c                   V ^8  d   QhRR/# )   returnbool )formats   "r   __annotate__r!   .   s      D r   c                      \        \        4      # r   )r   r	   r   r   r   
is_enabledr#   .   s    9r   c               $    V ^8  d   QhRRRRRR/# r   
persona_idstrlimitintr   
list[dict]r   )r    s   "r   r!   r!   2   s!      # c : r   c           	        \        4       pV'       g   . #  VP                  4       ;_uu_ 4       pVP                  RW34       VP                  4       pVP                   Uu. uF  qU^ ,          NK  	  ppV Uu. uF  p\        Wg4      NK  	  upuuRRR4       \        V4       # u upi u upi   + '       g   i     M; i \        T4       R#   \        T4       i ; i)uB   Top posts de uma persona nos últimos 30 dias, ordenado por score.a=  
                SELECT id, format, posted_at, caption, permalink, thumbnail_url,
                       impressions, reach, engagement, saves, shares, score
                FROM six_hype.top_posts_30d
                WHERE persona_id = %s
                ORDER BY score DESC
                LIMIT %s
                Nr   cursorexecutefetchalldescription_row_to_dictr   r&   r(   r   currowsdcolsrs   &&      r   	top_postsr8   2   s    ;D	[[]]cKK #
 <<>D"%//2/QaDD/D23784aL)48 ]  	 38 ]]  	@   C 2B- B#1B-7B(B-
C #
B--B=	8C Cc                    V ^8  d   QhRRRR/# )r   r&   r'   r   r*   r   )r    s   "r   r!   r!   K   s      # * r   c           	        \        4       pV'       g   . #  VP                  4       ;_uu_ 4       pVP                  RV 34       VP                  4       pVP                   Uu. uF  qD^ ,          NK  	  ppV Uu. uF  p\        WV4      NK  	  upuuRRR4       \        V4       # u upi u upi   + '       g   i     M; i \        T4       R#   \        T4       i ; i)uO   Performance comparativa por formato (reel vs carrossel vs static) últimos 30d.a)  
                SELECT format, n_posts, avg_impressions, avg_reach,
                       avg_engagement, avg_density, last_snapshot
                FROM six_hype.performance_by_format
                WHERE persona_id = %s
                ORDER BY avg_engagement DESC NULLS LAST
                Nr,   )r&   r   r3   r4   r5   r6   r7   s   &      r   	by_formatr<   K   s    ;D	[[]]cKK 	 <<>D"%//2/QaDD/D23784aL)48 ] 	 38 ]] 	r9   c               $    V ^8  d   QhRRRRRR/# r%   r   )r    s   "r   r!   r!   c   s!       C  r   c           	        \        4       pV'       g   . #  VP                  4       ;_uu_ 4       pVP                  RW34       VP                  4       pVP                   Uu. uF  qU^ ,          NK  	  ppV Uu. uF  p\        Wg4      NK  	  upuuRRR4       \        V4       # u upi u upi   + '       g   i     M; i \        T4       R#   \        T4       i ; i)uN   Palavras-chave/tópicos mais perguntados pelos pacientes nos últimos 30 dias.a  
                SELECT keyword, topic_category, mentions, n_sources, last_mention, channels
                FROM six_hype.topics_demanded_30d
                WHERE persona_id = %s
                ORDER BY mentions DESC
                LIMIT %s
                Nr,   r2   s   &&      r   topics_demandedr?   c   s    ;D	[[]]cKK #	 <<>D"%//2/QaDD/D23784aL)48 ] 	 38 ]] 	r9   c                    V ^8  d   QhRRRR/# )r   r&   r'   r   dictr   )r    s   "r   r!   r!   {   s        r   c                   \        4       pV'       g   / #  VP                  4       ;_uu_ 4       pVP                  RV 34       VP                  4        Uu. uF3  pRV^ ,          RV^,          RV^,          RV^,          ;'       g    ^ /NK5  	  ppRRR4       RX/\	        V4       # u upi   + '       g   i     L$; i  \	        T4       i ; i)uJ   Heatmap dia-da-semana × hora-do-dia de melhor performance (últimos 30d).a  
                SELECT EXTRACT(DOW  FROM mp.posted_at)::INT AS dow,
                       EXTRACT(HOUR FROM mp.posted_at)::INT AS hour,
                       COUNT(*)                              AS n,
                       AVG(mi.engagement)::INT               AS avg_engagement
                FROM six_hype.media_posts mp
                LEFT JOIN LATERAL (
                  SELECT engagement FROM six_hype.media_insights
                  WHERE post_id = mp.id ORDER BY snapshot_date DESC LIMIT 1
                ) mi ON TRUE
                WHERE mp.persona_id = %s
                  AND mp.posted_at >= NOW() - INTERVAL '30 days'
                GROUP BY dow, hour
                dowhournavg_engagementNcells)r   r-   r.   r/   r   )r&   r   r3   r7   rG   s   &    r   heatmaprH   {   s    ;D	[[]]cKK & 'A !fadC17G1QRS'  % , % ]0 	s:   B> &B+0B&B&B+B> &B++B;	6B> >Cc               $    V ^8  d   QhRRRRRR/# )r   r6   z	list[str]rowtupler   rA   r   )r    s   "r   r!   r!      s!     	 	y 	u 	 	r   c                    / p\        W4       FT  w  r4\        VR 4      '       d   VP                  4       W#&   K+  \        V\        4      '       d   \	        V4      W#&   KP  WBV&   KV  	  V# )	isoformat)ziphasattrrM   
isinstancelist)r6   rJ   outkvs   &&   r   r1   r1      sW    
CD1k""[[]CF4  !WCFF  Jr   )
   )__doc__
__future__r   jsonosr   typingr   environgetr	   r   r   r   r#   r8   r<   r?   rH   r1   r   r   r   <module>r]      s^   	 #  	 
 jjnn&+$
200B	r   