| import streamlit as st |
| from datetime import datetime |
| import google.generativeai as genai |
| import json |
| import urllib.parse |
|
|
| from auth import get_current_user |
| from modules.venegard_brain import get_gemini_model, build_prompt |
|
|
| VENEGARD_TEAM = { |
| "Jan": {"role": "Partner", "email": "jan@venegard.com", "phone": "+420 605 875 808"}, |
| "Filip": {"role": "Partner", "email": "filip@venegard.com", "phone": "+420 775 610 350"}, |
| "Matěj": {"role": "Partner", "email": "matej@venegard.com", "phone": "+420 725 188 832"}, |
| "Mikuláš": {"role": "Partner", "email": "mikulas@venegard.com", "phone": "+420 000 000 000"}, |
| } |
|
|
| VENEGARD_DEFAULT_PROFILE = { |
| "role": "Partner", |
| "email": "contact@venegard.com", |
| "phone": "+420 000 000 000", |
| } |
|
|
| def render_sniper_tab(db, scrape_website, extract_pdf_text, uploaded_file, company_size, language, tone, focus, focus_arg, cta_type, creativity): |
| ui_lang = st.session_state.get("ui_lang", "CZ") |
| |
| t = { |
| "CZ": { |
| "title": "Direct Outreach Engine", |
| "subtitle": "Generování sekvencí na míru pro konkrétní cíl na základě živé analýzy webu a nastavených parametrů.", |
| "target_url": "Cílová URL adresa", |
| "target_email": "Kontaktní e-mail klienta", |
| "btn_an": "Analyzovat web", |
| "btn_gen": "Vygenerovat e-maily", |
| "btn_send": "✉️ Otevřít v e-mailu a odeslat", |
| "stat_an": "Analyzuji DNA webu a hledám kontakty...", |
| "succ_an": "✅ Analýza dokončena. Parametry a kontakt byly nastaveny.", |
| "err_an": "Chyba analýzy:", |
| "stat_gen": "Inicializuji Venegard Sniper Engine…", |
| "subj_lbl": "VARIANTY PŘEDMĚTŮ:", |
| "mail_lbl": "HLAVNÍ EMAIL:", |
| "foll_lbl": "FOLLOW-UP:", |
| "succ_gen": "Sekvence vygenerována.", |
| "toast": "Uloženo do CRM pod jménem", |
| "err_gen": "Chyba při generování:", |
| "status": "Vygenerováno" |
| }, |
| "EN": { |
| "title": "Direct Outreach Engine", |
| "subtitle": "Generate sequence-grade outreach assets for a single target based on live web intelligence and configured parameters.", |
| "target_url": "Target URL", |
| "target_email": "Target Contact Email", |
| "btn_an": "Analyze Website", |
| "btn_gen": "Generate Emails", |
| "btn_send": "✉️ Open in Email Client", |
| "stat_an": "Performing Autopilot Analysis & scraping contacts...", |
| "succ_an": "✅ Target profile synchronized. Parameters and contact updated.", |
| "err_an": "Analysis error:", |
| "stat_gen": "Initializing Venegard Sniper Engine...", |
| "subj_lbl": "SUBJECT VARIANTS:", |
| "mail_lbl": "MAIN EMAIL:", |
| "foll_lbl": "FOLLOW-UP:", |
| "succ_gen": "Sequence generated successfully.", |
| "toast": "Saved to CRM under", |
| "err_gen": "Generation error:", |
| "status": "Generated" |
| } |
| }[ui_lang] |
|
|
| st.markdown("<br>", unsafe_allow_html=True) |
| st.markdown(f""" |
| <h2 style="margin-bottom: 0.5rem;">{t['title']}</h2> |
| <p style="color:#9CA3AF; font-size:0.9rem; max-width:640px;">{t['subtitle']}</p> |
| """, unsafe_allow_html=True) |
| st.markdown("<br>", unsafe_allow_html=True) |
| |
| col_url, col_mail = st.columns(2) |
| with col_url: |
| target_url = st.text_input(t['target_url'], placeholder="https://domain.com", key="sniper_url") |
| with col_mail: |
| |
| target_email = st.text_input(t['target_email'], value=st.session_state.get("target_email_auto", ""), placeholder="info@domain.com") |
| |
| is_analyzed = st.session_state.get("last_analyzed_url") == target_url |
| if is_analyzed and target_url != "": |
| st.success(t['succ_an']) |
|
|
| col_an, col_ge = st.columns(2) |
| submit_analysis = col_an.button(t['btn_an'], use_container_width=True) |
| submit_sniper = col_ge.button(t['btn_gen'], key="btn_sniper", disabled=not is_analyzed, use_container_width=True) |
|
|
| if submit_analysis and target_url: |
| with st.status(t['stat_an'], expanded=True): |
| client_data = scrape_website(target_url) |
| model = get_gemini_model() |
| |
| analysis_prompt = f""" |
| Analyzuj tento web: {client_data[:3000]} |
| Navrhni nejlepší obchodní strategii pro agenturu Venegard na základě našeho know-how a POKUS SE NAJÍT KONTAKTNÍ E-MAIL. |
| |
| Vrať POUZE čistý JSON, kde hodnoty jsou CELÁ ČÍSLA a nalezený e-mail: |
| {{ |
| "segment_idx": (0: Startup, 1: SME, 2: Mid-Market, 3: Corporate, 4: E-commerce, 5: Agency), |
| "focus_idx": (0: High-Conversion Web, 1: AI Infrastructure, 2: Cinematic Visuals, 3: Long-Term Growth), |
| "argument_idx": (0: Digital Authority, 1: Sales & Conversions, 2: 24/7 AI Automation, 3: Tech Dominance), |
| "tone_idx": (0: Modern B2B, 1: Direct & Punchy, 2: Visionary, 3: Premium), |
| "cta_idx": (0: Discovery Call, 1: Open Question, 2: Tech Demo, 3: Direct Pitch), |
| "contact_email": "nalezeny_email@firma.cz (nebo prázdný řetězec, pokud na webu není)" |
| }} |
| """ |
| try: |
| analysis_res = model.generate_content(analysis_prompt) |
| prefs = json.loads(analysis_res.text.strip().replace("```json", "").replace("```", "")) |
| |
| st.session_state.segment_auto_idx = int(prefs.get("segment_idx", 0)) |
| st.session_state.focus_auto_idx = int(prefs.get("focus_idx", 0)) |
| st.session_state.argument_auto_idx = int(prefs.get("argument_idx", 0)) |
| st.session_state.tone_auto_idx = int(prefs.get("tone_idx", 0)) |
| st.session_state.cta_auto_idx = int(prefs.get("cta_idx", 0)) |
| |
| |
| st.session_state.target_email_auto = prefs.get("contact_email", "") |
| st.session_state.last_analyzed_url = target_url |
| |
| st.rerun() |
| except Exception as e: |
| st.error(f"{t['err_an']} {e}\n\nOdpověď AI: {analysis_res.text}") |
|
|
| if submit_sniper and target_url: |
| with st.status(t['stat_gen'], expanded=True) as status: |
| client_data = scrape_website(target_url) |
| pdf_context = extract_pdf_text(uploaded_file) if uploaded_file else "" |
| model = get_gemini_model() |
|
|
| raw_name = str(st.session_state.get("name", "")).strip() or "Venegard" |
| first_name = raw_name.split()[0].capitalize() |
| profile = VENEGARD_TEAM.get(raw_name, VENEGARD_TEAM.get(first_name, VENEGARD_DEFAULT_PROFILE)) |
| |
| user_phone = profile.get("phone", "+420 605 875 808") |
| user_email = profile.get("email", "jan@venegard.com") |
| user_full_name = "Jan Sedlář" if first_name == "Jan" else (raw_name if raw_name != "Venegard" else "Jan Sedlář") |
|
|
| task = f""" |
| Vytvoř outbound sekvenci v jazyce: {language}. |
| |
| ABSOLUTNÍ ZÁKAZ FORMÁTOVÁNÍ: |
| ZAKAZUJI POUŽÍVAT HVĚZDIČKY (*), MŘÍŽKY (#) A TUČNÉ PÍSMO. |
| Nepiš nadpisy jako "Předmět:" nebo "Část 2". Napiš pouze čistý text oddělený řetězcem "===DELIC===". |
| |
| Tón: {tone}, Segment: {company_size}. |
| |
| ČÁST 1 (Předměty): |
| Napiš 4 krátké, přirozené předměty (max 6 slov). Každý na nový řádek. Bez odrážek a bez čísel. |
| |
| ===DELIC=== |
| |
| ČÁST 2 (Hlavní Email - STRICTNĚ PODLE TÉTO STRUKTURY): |
| 1. Oslovení: Dobrý den, |
| 2. Úvod a pochvala: "Už nějakou dobu sleduji..." nebo "Narazil jsem na...". Zmiň jednu konkrétní detailní věc z jejich webu, která tě zaujala (bez frází "je to super"). |
| 3. Přemostění: "Právě proto si myslím, že by si projekt zasloužil..." |
| 4. Představení: "Jmenuji se {user_full_name} a jsem součástí digitální agentury Venegard. Pomáháme značkám růst v online světě." |
| 5. Nabídka: Plynule a lidsky zmiň: {focus} a náš argument: {focus_arg}. |
| 6. CTA: {cta_type}. (např. "Pokud budete mít chvíli, navrhuji krátký call, kde vám ukážu...") |
| |
| Podpis (Zkopíruj PŘESNĚ toto): |
| S úctou |
| |
| {user_full_name} | Venegard |
| venegard.com |
| {user_phone} |
| {user_email} |
| |
| ===DELIC=== |
| |
| ČÁST 3 (Follow-up): |
| Napiš ultra-krátký, přirozený a lidský follow-up po 3 dnech (max 2-3 věty). |
| Nesmí to znít suše nebo "korporátně". Přátelsky se připomeň, jestli minulý email nezapadl, a ukaž sebevědomí, že jim {focus} pomůže s {focus_arg}. |
| |
| NA KONEC PŘIDEJ STEJNÝ PODPIS: |
| S úctou |
| {user_full_name} | Venegard |
| venegard.com |
| {user_phone} |
| {user_email} |
| """ |
| |
| prompt = build_prompt( |
| task_specific_prompt=task, |
| target_client_data=f"URL: {target_url}\nObsah Webu: {client_data}", |
| extra_context=pdf_context |
| ) |
| |
| try: |
| response = model.generate_content(prompt, generation_config=genai.GenerationConfig(temperature=creativity)) |
| |
| clean_text = response.text.replace("*", "").replace("#", "") |
| parts = clean_text.split("===DELIC===") |
| |
| subjects_text = parts[0].strip() if len(parts) > 0 else "" |
| email_body = parts[1].strip() if len(parts) > 1 else "" |
| followup_body = parts[2].strip() if len(parts) > 2 else "" |
| |
| subjects_text = subjects_text.replace("ČÁST 1 (Předměty):", "").replace("Předměty:", "").strip() |
| email_body = email_body.replace("ČÁST 2 (Hlavní Email):", "").replace("Hlavní Email:", "").strip() |
| followup_body = followup_body.replace("ČÁST 3 (Follow-up):", "").replace("Follow-up:", "").strip() |
| |
| status.update(label=t['succ_gen'], state="complete", expanded=False) |
| |
| st.markdown("""<style>code { white-space: pre-wrap !important; word-break: break-word !important; }</style>""", unsafe_allow_html=True) |
|
|
| st.markdown(f'<div class="result-box"><div style="color:#1E60F2; font-weight:600; margin-bottom:10px;">{t["subj_lbl"]}</div></div>', unsafe_allow_html=True) |
| st.code(subjects_text, language=None) |
|
|
| st.markdown(f'<div class="result-box"><hr style="margin:25px 0; border-color:#1F2937;"><div style="color:#1E60F2; font-weight:600; margin-bottom:10px;">{t["mail_lbl"]}</div></div>', unsafe_allow_html=True) |
| st.code(email_body, language=None) |
| |
| if target_email: |
| first_subj = subjects_text.split('\n')[0].strip() if subjects_text else "Návrh spolupráce" |
| subject_enc = urllib.parse.quote(first_subj) |
| body_enc = urllib.parse.quote(email_body) |
| mailto_link = f"mailto:{target_email}?subject={subject_enc}&body={body_enc}" |
| |
| st.markdown(f''' |
| <a href="{mailto_link}" target="_blank" style="text-decoration: none;"> |
| <div style="background-color: #1E60F2; color: white; padding: 12px 20px; border-radius: 8px; text-align: center; font-weight: 600; margin-top: 15px; margin-bottom: 5px; transition: all 0.2s ease;"> |
| {t['btn_send']} |
| </div> |
| </a> |
| ''', unsafe_allow_html=True) |
| else: |
| st.info("💡 E-mail nebyl na webu nalezen. Doplňte ho nahoře do pole, aby se objevilo tlačítko pro rychlé odeslání.") |
|
|
| st.markdown(f'<div class="result-box"><hr style="margin:25px 0; border-color:#1F2937;"><div style="color:#1E60F2; font-weight:600; margin-bottom:10px;">{t["foll_lbl"]}</div></div>', unsafe_allow_html=True) |
| st.code(followup_body, language=None) |
| |
| record = { |
| "Autor": user_full_name, |
| "Datum": datetime.now().strftime("%d.%m.%Y"), |
| "Nástroj": "Sniper", |
| "Firma": target_url.replace("https://", "").replace("http://", "").split('/')[0], |
| "Email": target_email, |
| "URL": target_url, |
| "Skóre": "N/A", |
| "Analýza": "Individuální outreach" |
| } |
| st.session_state.crm_data.append(record) |
| db.save(st.session_state.crm_data) |
| st.toast(f"{t['toast']} {user_full_name}") |
|
|
| except Exception as e: |
| status.update(label=t['err_gen'], state="error") |
| st.error(f"{t['err_gen']} {e}") |