o
    O%j3                     @  sH  d Z ddlmZ ddlZddlZddlZddlmZ ddlmZ ddl	m
Z
 edZed d	 Zed
 ZdZdZdZdZdZdZdaddZdbdcddZefddddZ		dedfd&d'Zdgd+d,Zdhd-d.Z			didjd8d9Zdkd;d<Zdldmd=d>Zdnd?d@ZdodpdEdFZdqdHdIZ	J	KdrdsdPdQZ 		RdtdudXdYZ!dvd]d^Z"dwd_d`Z#dS )xu  Shared helpers for the Plappi Social-Marketing engine.

Single source of truth for: paths, DB access, WA dispatch, Claude drafting
(with OpenAI-Codex fallback, mirrored from the LinkedIn pipeline), e-mail send
(via lena-mail.py), disclosure labels and the WhatsApp approval format.

Two channels, three posting modes (set per target — see init_db.py):
  channel 'press'  → posting_mode 'email'             (Lena drafts → approve → SENDS mail)
  channel 'social' → posting_mode 'auto_own'          (eigene Plappi-Kanäle: draft → approve → post)
                   → posting_mode 'manual_community'   (Reddit/FB-Gruppen/Foren: draft → approve → DU postest)
                   → posting_mode 'paid'               (Ad-Creative-Draft → approve → schalten)

Design rule (see PLATTFORM-RICHTLINIEN.md): NEVER auto-post into third-party
communities — that gets accounts banned. Communities are always human-posted.
    )annotationsN)datetime)Path)Optionalz/home/agent/plappi-marketingdatazmarketing.sqlitelogs4367761591536z/home/agent/bin/send-wa.shz/home/agent/bin/lena-mail.pyz/home/nk/.local/bin/claudez /home/agent/tracking/log_call.pyu   🔔 Plappireturnsqlite3.Connectionc                  C  s   t t} t j| _| S )N)sqlite3connectDB_PATHRowrow_factory)conn r   L/home/nk/hobo-godmode/otto/projekte/plappi/marketing/engine/marketing_lib.pydb*   s   
r   enginemsgstrstreamNonec                 C  sJ   t jddd dt jdd d|  d}t | d d	| d S )
NT)parentsexist_ok[seconds)timespec] 
z.loga)LOG_DIRmkdirr   now	isoformatopenwrite)r   r   liner   r   r   log0   s   r(   bodytoc                 C  s   t jt|| gdd dS )z:Queue a WhatsApp message to Nemanja via Lena's send-wa.sh.F)checkN)
subprocessrunSEND_WA)r)   r*   r   r   r   wa_send6   s   r/   channelOptional[str]platformwavestatuslist[sqlite3.Row]c           
      C  sv   d}g }d| fd|fd|fd|ffD ]\}}|r%|d| d7 }| | q|d7 }t }||| }	|  |	S )	NzSELECT * FROM targets WHERE 1=1r0   r2   r3   r4   z AND =?z ORDER BY priority DESC, id ASCappendr   executefetchallclose)
r0   r2   r3   r4   qpcolvalr   rowsr   r   r   list_targets<   s   rA   tidintOptional[sqlite3.Row]c                 C  $   t  }|d| f }|  |S )Nz SELECT * FROM targets WHERE id=?r   r9   fetchoner;   )rB   r   rr   r   r   
get_targetI       rI   c                 C  s*   t  }|d|| f |  |  d S )NzBUPDATE targets SET status=?, updated_at=datetime('now') WHERE id=?r   r9   commitr;   )rB   r4   r   r   r   r   set_target_statusN   s   rM   	target_idOptional[int]type_subject
disclosurescheduled_for
thread_refprompt_used
model_usedc                 C  sB   t  }|d| |||||||||	|
f}|  |j}|  |S )NzINSERT INTO items (target_id, channel, type, platform, subject, body,
                              disclosure, scheduled_for, thread_ref, prompt_used,
                              model_used, status)
           VALUES (?,?,?,?,?,?,?,?,?,?,?, 'pending'))r   r9   rL   	lastrowidr;   )rN   r0   rP   r2   r)   rQ   rR   rS   rT   rU   rV   r   curiidr   r   r   insert_itemU   s   rZ   rY   c                 C  rE   )NzSELECT * FROM items WHERE id=?rF   )rY   r   rH   r   r   r   get_iteme   rJ   r[   c                 C  s^   d}g }| r|d7 }| |  |r|d7 }| | |d7 }t }||| }|  |S )NzSELECT * FROM items WHERE 1=1z AND status=?z AND channel=?z ORDER BY id DESC LIMIT 40r7   )r4   r0   r<   r=   r   r@   r   r   r   
list_itemsj   s   r\   c                 K  sx   ddg}|g}|  D ]\}}|| d || q||  t }|dd| d| |  |  d S )Nzstatus=?zupdated_at=datetime('now')r6   zUPDATE items SET , z WHERE id=?)itemsr8   r   r9   joinrL   r;   )rY   r4   extrafieldsparamskvr   r   r   r   
set_statusu   s   
 re    item_ideventdetailc                 C  s,   t  }|d| ||f |  |  d S )Nz:INSERT INTO events (item_id, event, detail) VALUES (?,?,?)rK   )rg   rh   ri   r   r   r   r   	log_event~   s
   rj   posting_modec                 C  s   | dv rdS d S )N)auto_ownpaidmanual_communityWerbungr   )rk   r   r   r   disclosure_for   s   rp   haikuplappi_marketinguser_promptsystem_promptmodellabelc                 C  s  ddddt d| d|d|dd	g}tj|d
d
dd}ztjt|dd|g|jd
dd
d W n	 ty3   Y nw zt|j}t|t	rL|
drL|d  W S W n	 tyV   Y nw |jp[d|jp_d }dd l}|d||j}	|jdkst|	rzPdd l}
dd l}d}|d |  }|
jdd}tj|dddddd||g	tjd
d
dd d}zt|  }|| W n	 ty   Y nw |rtd  |W S W n ty } ztd!|  W Y d }~nd }~ww td"|jd d  td#|jd d$  )%Nsudoz-nz-unkz-pz--append-system-promptz--modelz--output-formatjsonT   capture_outputtexttimeoutplappi
   )inputr}   r~   r|   resultrf   r   zsusage limit|rate.?limit|5-hour limit|reached your.*limit|quota|exceeded your|limit reached|Overloaded|Not logged inz1/home/agent/.nvm/versions/node/v24.15.0/bin/codexz

## AUFGABE:
z.txt)suffixexecz--skip-git-repo-checkz--cdz/home/agentz*--dangerously-bypass-approvals-and-sandboxz--output-last-messagei,  )stdinr|   r}   r~   u.   Claude-Limit → OpenAI-Codex-Fallback genutztzcodex-fallback err: z'claude failed + codex fallback failed: zclaude returned no result:    )CLAUDEr,   r-   TRACKstdout	Exceptionry   loads
isinstancedictgetstripstderrresearchI
returncodetempfileosmktempDEVNULLr%   readunlinkr(   RuntimeError)rs   rt   ru   rv   cmdresdblobr   limitedr   r   codexcombinedoutfouter   r   r   
run_claude   sj   


r   FattachmentsOptional[list[str]]dryboolno_bccc           	      C  s   t d| d|d|g}|pg D ]}|d|g7 }q|r|d |r$|d tj|dddd	}td
|  d| d|j d|j d d   |jdkS )Nz--toz	--subjectz--bodyz--attachz--no-bccz--dryTZ   r{   zsend_email to=z dry=z rc=z :: x   r   )	LENA_MAILr8   r,   r-   r(   r   r   r   )	r*   rQ   r)   r   r   r   r   r    rH   r   r   r   
send_email   s   

0
r   itemsqlite3.Rowtargetc                 C  s  | d }|r
|d nd}| d pd}|r|d nd}d}| d	 d
krYt  d| d| d| d  d| d|r9|d nd d| d pAd d| d| d  d| d| d| d| dS |dkrt  d| d| d| d  d|rq|d nd d| d pyd d| d| d  d| d| d | d| d!| S | d rd"| d  d#nd$}t  d%| d| d| d  d&| | d| d| d  d| d| d'| d| dS )(Nidname   —rS   sofortrk   email<   ━━━━━━━━━━━━━━━━━━━━r0   pressz	-Presse #u    → z (r2   r]   z)
An: contactz

Betreff: rQ   r   r)   z

ok #u    → Mail senden  ·  nein #u     ·  fix #u   : <änderung>rn   z-Community #u1   )
⚠️ MANUELL posten (Account-Schutz).
Regel: rulesz
Kennzeichnung: rR   u:    → freigeben (ich geb dir den fertigen Text)  ·  nein #u%   : <änderung>
Wenn gepostet: posted #r   r   rf   z-Post #z, eigener Kanal)
u    → posten  ·  nein #)APPROVAL_PREFIX)r   r   rY   r   schedmodebartagr   r   r   format_for_wa   sz   "

r   c                 C  s   d}| d rd| d  dnd}d| d  d|d	  d
|d p$|d p$d d|d p+d d| d| d  | d| d| d  S )zFReady-to-paste block Lena returns after a community draft is approved.r   rR   u   

— u    —rf   u   ✅ Freigegeben #r   u    — bitte HIER posten:
Ziel: r   z
Link/Handle: r   urlr   z
Regel beachten: r   r   r)   z
Danach: posted #r   )r   r   r   discr   r   r   manual_post_card   s&   
r   )r	   r
   )r   )r   r   r   r   r	   r   )r)   r   r*   r   r	   r   )NNNN)
r0   r1   r2   r1   r3   r1   r4   r1   r	   r5   )rB   rC   r	   rD   )rB   rC   r4   r   r	   r   )NNNNNN)rN   rO   r0   r   rP   r   r2   r   r)   r   rQ   r1   rR   r1   rS   r1   rT   r1   rU   r1   rV   r1   r	   rC   )rY   rC   r	   rD   )NN)r4   r1   r0   r1   r	   r5   )rY   rC   r4   r   r	   r   )rf   )rg   rO   rh   r   ri   r   r	   r   )rk   r   r	   r1   )rq   rr   )
rs   r   rt   r   ru   r   rv   r   r	   r   )NFF)r*   r   rQ   r   r)   r   r   r   r   r   r   r   r	   r   )r   r   r   rD   r	   r   )r   r   r   r   r	   r   )$__doc__
__future__r   ry   r   r,   r   pathlibr   typingr   ROOTr   r!   MASTER_PHONEr.   r   r   r   r   r   r(   r/   rA   rI   rM   rZ   r[   r\   re   rj   rp   r   r   r   r   r   r   r   r   <module>   sT    




	

	3
