muzakkirhussain011 commited on
Commit
83136bf
Β·
1 Parent(s): d1220fd

Add application files

Browse files
Files changed (1) hide show
  1. app.py +248 -68
app.py CHANGED
@@ -380,14 +380,29 @@ footer { display: none !important; }
380
 
381
  /* ============== MAIN CONTENT AREA ============== */
382
  .main-wrapper {
383
- margin-left: var(--sidebar-width);
 
 
384
  min-height: 100vh;
385
  padding: 20px;
386
- transition: margin-left 0.3s ease;
387
  background: var(--bg-secondary);
 
 
 
 
 
 
 
 
388
  }
389
 
390
- .main-wrapper.expanded { margin-left: var(--sidebar-collapsed); }
 
 
 
 
 
391
 
392
  .content-area {
393
  max-width: 1200px;
@@ -458,13 +473,19 @@ footer { display: none !important; }
458
 
459
  .main-wrapper {
460
  margin-left: 0 !important;
 
 
461
  padding: 16px;
462
  padding-top: calc(var(--header-height) + 16px);
463
  }
464
  }
465
 
466
  @media (max-width: 480px) {
467
- .main-wrapper { padding: 12px; padding-top: calc(var(--header-height) + 12px); }
 
 
 
 
468
  .page-header { padding: 16px; }
469
  .page-title { font-size: 20px; }
470
  }
@@ -566,6 +587,94 @@ footer { display: none !important; }
566
  .action-card h3 { margin: 0 0 12px 0; color: var(--text-primary); font-size: 18px; font-weight: 600; }
567
  .action-card p { margin: 0 0 16px 0; color: var(--text-secondary); font-size: 14px; line-height: 1.6; }
568
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  button.primary {
570
  background: linear-gradient(135deg, var(--primary-blue) 0%, var(--primary-dark) 100%) !important;
571
  color: white !important;
@@ -2679,6 +2788,21 @@ def create_app():
2679
  <p class="page-subtitle">Configure your company and API credentials</p>
2680
  </div>
2681
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2682
  """)
2683
 
2684
  with gr.Row():
@@ -2724,7 +2848,18 @@ def create_app():
2724
  gr.HTML("""<div class="page-header"><div>
2725
  <h1 class="page-title">πŸ“Š Dashboard</h1>
2726
  <p class="page-subtitle">Overview of your sales pipeline</p>
2727
- </div></div>""")
 
 
 
 
 
 
 
 
 
 
 
2728
 
2729
  client_status = gr.HTML(get_client_status_html())
2730
 
@@ -2742,7 +2877,23 @@ def create_app():
2742
  gr.HTML("""<div class="page-header"><div>
2743
  <h1 class="page-title">πŸ” Discovery</h1>
2744
  <p class="page-subtitle">AI-powered prospect discovery</p>
2745
- </div></div>""")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2746
 
2747
  client_status_2 = gr.HTML(get_client_status_html())
2748
 
@@ -2763,7 +2914,18 @@ def create_app():
2763
  gr.HTML("""<div class="page-header"><div>
2764
  <h1 class="page-title">🎯 Prospects</h1>
2765
  <p class="page-subtitle">Companies discovered by AI</p>
2766
- </div></div>""")
 
 
 
 
 
 
 
 
 
 
 
2767
  refresh_prospects_btn = gr.Button("πŸ”„ Refresh", variant="secondary", size="sm")
2768
  prospects_list = gr.HTML(get_prospects_html())
2769
 
@@ -2772,7 +2934,18 @@ def create_app():
2772
  gr.HTML("""<div class="page-header"><div>
2773
  <h1 class="page-title">πŸ‘₯ Contacts</h1>
2774
  <p class="page-subtitle">Decision makers found by AI</p>
2775
- </div></div>""")
 
 
 
 
 
 
 
 
 
 
 
2776
  refresh_contacts_btn = gr.Button("πŸ”„ Refresh", variant="secondary", size="sm")
2777
  contacts_list = gr.HTML(get_contacts_html())
2778
 
@@ -2781,7 +2954,18 @@ def create_app():
2781
  gr.HTML("""<div class="page-header"><div>
2782
  <h1 class="page-title">βœ‰οΈ Emails</h1>
2783
  <p class="page-subtitle">AI-drafted outreach emails</p>
2784
- </div></div>""")
 
 
 
 
 
 
 
 
 
 
 
2785
  refresh_emails_btn = gr.Button("πŸ”„ Refresh", variant="secondary", size="sm")
2786
  emails_list = gr.HTML(get_emails_html())
2787
 
@@ -2790,7 +2974,18 @@ def create_app():
2790
  gr.HTML("""<div class="page-header"><div>
2791
  <h1 class="page-title">πŸ’¬ AI Chat</h1>
2792
  <p class="page-subtitle">Your AI sales assistant</p>
2793
- </div></div>""")
 
 
 
 
 
 
 
 
 
 
 
2794
 
2795
  chatbot = gr.Chatbot(value=[], height=400, label="Chat")
2796
 
@@ -2804,7 +2999,7 @@ def create_app():
2804
  send_btn = gr.Button("Send", variant="primary", scale=1)
2805
 
2806
  gr.HTML("""<div class="action-card" style="margin-top: 16px;">
2807
- <h4>πŸ’‘ Example Prompts</h4>
2808
  <ul style="font-size: 13px; line-height: 1.8; margin: 8px 0 0 0; padding-left: 20px;">
2809
  <li>"Search for DTC fashion brands that raised Series A"</li>
2810
  <li>"Draft an email to the CEO of Warby Parker"</li>
@@ -2851,77 +3046,62 @@ def create_app():
2851
  btn_emails.click(fn=lambda: show_page("emails"), outputs=all_pages)
2852
  btn_chat.click(fn=lambda: show_page("chat"), outputs=all_pages)
2853
 
2854
- # JavaScript to connect sidebar nav items to Gradio buttons
2855
  gr.HTML("""
2856
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2857
  window.selectPage = function(pageName) {
2858
- // Close mobile sidebar
2859
  if (window.closeMobileSidebar) {
2860
  window.closeMobileSidebar();
2861
  }
2862
 
2863
- // Update active nav item
2864
  document.querySelectorAll('.nav-item').forEach(item => {
2865
- item.classList.remove('active');
2866
- if (item.dataset.page === pageName) {
2867
- item.classList.add('active');
2868
- }
2869
  });
2870
 
2871
- // Map page names to button IDs and click the corresponding button
2872
- const buttonMap = {
2873
- 'setup': 'btn-setup',
2874
- 'dashboard': 'btn-dashboard',
2875
- 'discovery': 'btn-discovery',
2876
- 'prospects': 'btn-prospects',
2877
- 'contacts': 'btn-contacts',
2878
- 'emails': 'btn-emails',
2879
- 'chat': 'btn-chat'
2880
- };
2881
-
2882
- // Find button by elem_id in Gradio's structure
2883
- const btnId = buttonMap[pageName];
2884
- if (btnId) {
2885
- // Gradio wraps buttons in a div with id containing the elem_id
2886
- const btn = document.querySelector(`[id*="${btnId}"] button`) ||
2887
- document.querySelector(`button[id*="${btnId}"]`) ||
2888
- document.getElementById(btnId);
2889
- if (btn) {
2890
- btn.click();
2891
- return;
2892
- }
2893
 
2894
- // Fallback: find by button text content
2895
- const buttons = document.querySelectorAll('.nav-buttons-row button');
2896
- const labels = {
2897
- 'setup': 'Setup',
2898
- 'dashboard': 'Dashboard',
2899
- 'discovery': 'Discovery',
2900
- 'prospects': 'Prospects',
2901
- 'contacts': 'Contacts',
2902
- 'emails': 'Emails',
2903
- 'chat': 'Chat'
2904
- };
2905
- buttons.forEach(b => {
2906
- if (b.textContent.includes(labels[pageName])) {
2907
- b.click();
2908
- }
2909
- });
2910
  }
2911
  };
2912
 
2913
- // Highlight active button when clicked
2914
- document.addEventListener('DOMContentLoaded', function() {
2915
- setTimeout(function() {
2916
- const navButtons = document.querySelectorAll('.nav-buttons-row button');
2917
- navButtons.forEach(btn => {
2918
- btn.addEventListener('click', function() {
2919
- navButtons.forEach(b => b.classList.remove('active-nav-btn'));
2920
- this.classList.add('active-nav-btn');
2921
- });
2922
- });
2923
- }, 500);
2924
- });
2925
  </script>
2926
  """)
2927
 
 
380
 
381
  /* ============== MAIN CONTENT AREA ============== */
382
  .main-wrapper {
383
+ margin-left: var(--sidebar-width) !important;
384
+ width: calc(100% - var(--sidebar-width)) !important;
385
+ max-width: calc(100vw - var(--sidebar-width)) !important;
386
  min-height: 100vh;
387
  padding: 20px;
388
+ transition: margin-left 0.3s ease, width 0.3s ease;
389
  background: var(--bg-secondary);
390
+ overflow-x: hidden;
391
+ box-sizing: border-box !important;
392
+ }
393
+
394
+ .main-wrapper.expanded {
395
+ margin-left: var(--sidebar-collapsed) !important;
396
+ width: calc(100% - var(--sidebar-collapsed)) !important;
397
+ max-width: calc(100vw - var(--sidebar-collapsed)) !important;
398
  }
399
 
400
+ /* Ensure Gradio's inner containers don't overflow */
401
+ .main-wrapper > div,
402
+ .main-wrapper > div > div {
403
+ max-width: 100% !important;
404
+ overflow-x: hidden;
405
+ }
406
 
407
  .content-area {
408
  max-width: 1200px;
 
473
 
474
  .main-wrapper {
475
  margin-left: 0 !important;
476
+ width: 100% !important;
477
+ max-width: 100vw !important;
478
  padding: 16px;
479
  padding-top: calc(var(--header-height) + 16px);
480
  }
481
  }
482
 
483
  @media (max-width: 480px) {
484
+ .main-wrapper {
485
+ padding: 12px;
486
+ padding-top: calc(var(--header-height) + 12px);
487
+ width: 100% !important;
488
+ }
489
  .page-header { padding: 16px; }
490
  .page-title { font-size: 20px; }
491
  }
 
587
  .action-card h3 { margin: 0 0 12px 0; color: var(--text-primary); font-size: 18px; font-weight: 600; }
588
  .action-card p { margin: 0 0 16px 0; color: var(--text-secondary); font-size: 14px; line-height: 1.6; }
589
 
590
+ /* ============== INFO BOX / HELP TIPS ============== */
591
+ .info-box {
592
+ background: linear-gradient(135deg, var(--primary-light) 0%, #E8F4FD 100%);
593
+ border: 1px solid var(--primary-blue);
594
+ border-left: 4px solid var(--primary-blue);
595
+ border-radius: 8px;
596
+ padding: 16px 20px;
597
+ margin-bottom: 20px;
598
+ display: flex;
599
+ gap: 12px;
600
+ align-items: flex-start;
601
+ }
602
+
603
+ .info-box.tip {
604
+ background: linear-gradient(135deg, #FEF3C7 0%, #FEF9E7 100%);
605
+ border-color: var(--warning-orange);
606
+ border-left-color: var(--warning-orange);
607
+ }
608
+
609
+ .info-box.success {
610
+ background: linear-gradient(135deg, var(--success-light) 0%, #E8F8ED 100%);
611
+ border-color: var(--success-green);
612
+ border-left-color: var(--success-green);
613
+ }
614
+
615
+ .info-box-icon {
616
+ font-size: 20px;
617
+ flex-shrink: 0;
618
+ margin-top: 2px;
619
+ }
620
+
621
+ .info-box-content {
622
+ flex: 1;
623
+ }
624
+
625
+ .info-box-title {
626
+ font-weight: 600;
627
+ color: var(--text-primary);
628
+ margin-bottom: 4px;
629
+ font-size: 14px;
630
+ }
631
+
632
+ .info-box-text {
633
+ color: var(--text-secondary);
634
+ font-size: 13px;
635
+ line-height: 1.5;
636
+ margin: 0;
637
+ }
638
+
639
+ .info-box-text ul {
640
+ margin: 8px 0 0 0;
641
+ padding-left: 18px;
642
+ }
643
+
644
+ .info-box-text li {
645
+ margin-bottom: 4px;
646
+ }
647
+
648
+ .dark .info-box {
649
+ background: linear-gradient(135deg, rgba(1, 118, 211, 0.15) 0%, rgba(1, 118, 211, 0.08) 100%);
650
+ }
651
+
652
+ .dark .info-box.tip {
653
+ background: linear-gradient(135deg, rgba(251, 191, 36, 0.15) 0%, rgba(251, 191, 36, 0.08) 100%);
654
+ }
655
+
656
+ .dark .info-box.success {
657
+ background: linear-gradient(135deg, rgba(46, 132, 74, 0.15) 0%, rgba(46, 132, 74, 0.08) 100%);
658
+ }
659
+
660
+ /* Collapsible help section */
661
+ .help-toggle {
662
+ background: none;
663
+ border: none;
664
+ color: var(--primary-blue);
665
+ cursor: pointer;
666
+ font-size: 13px;
667
+ padding: 4px 8px;
668
+ display: inline-flex;
669
+ align-items: center;
670
+ gap: 4px;
671
+ margin-bottom: 8px;
672
+ }
673
+
674
+ .help-toggle:hover {
675
+ text-decoration: underline;
676
+ }
677
+
678
  button.primary {
679
  background: linear-gradient(135deg, var(--primary-blue) 0%, var(--primary-dark) 100%) !important;
680
  color: white !important;
 
2788
  <p class="page-subtitle">Configure your company and API credentials</p>
2789
  </div>
2790
  </div>
2791
+
2792
+ <div class="info-box">
2793
+ <span class="info-box-icon">πŸš€</span>
2794
+ <div class="info-box-content">
2795
+ <div class="info-box-title">Getting Started</div>
2796
+ <div class="info-box-text">
2797
+ Complete these steps to start finding prospects:
2798
+ <ul>
2799
+ <li><strong>HuggingFace Token</strong> - Required for AI-powered research and email drafting</li>
2800
+ <li><strong>Serper API Key</strong> - Optional, enables real-time web search for company info</li>
2801
+ <li><strong>Company Name</strong> - Your company name helps AI find relevant prospects</li>
2802
+ </ul>
2803
+ </div>
2804
+ </div>
2805
+ </div>
2806
  """)
2807
 
2808
  with gr.Row():
 
2848
  gr.HTML("""<div class="page-header"><div>
2849
  <h1 class="page-title">πŸ“Š Dashboard</h1>
2850
  <p class="page-subtitle">Overview of your sales pipeline</p>
2851
+ </div></div>
2852
+
2853
+ <div class="info-box success">
2854
+ <span class="info-box-icon">πŸ“ˆ</span>
2855
+ <div class="info-box-content">
2856
+ <div class="info-box-title">Pipeline Overview</div>
2857
+ <div class="info-box-text">
2858
+ Track your progress at a glance. The dashboard shows real-time counts of prospects discovered, contacts found, and emails drafted. Click "Refresh" to update the stats after running Discovery.
2859
+ </div>
2860
+ </div>
2861
+ </div>
2862
+ """)
2863
 
2864
  client_status = gr.HTML(get_client_status_html())
2865
 
 
2877
  gr.HTML("""<div class="page-header"><div>
2878
  <h1 class="page-title">πŸ” Discovery</h1>
2879
  <p class="page-subtitle">AI-powered prospect discovery</p>
2880
+ </div></div>
2881
+
2882
+ <div class="info-box tip">
2883
+ <span class="info-box-icon">πŸ’‘</span>
2884
+ <div class="info-box-content">
2885
+ <div class="info-box-title">How Discovery Works</div>
2886
+ <div class="info-box-text">
2887
+ <ul>
2888
+ <li><strong>Step 1:</strong> AI searches the web for companies matching your profile</li>
2889
+ <li><strong>Step 2:</strong> Finds decision-makers (CEOs, VPs, Founders) with verified emails</li>
2890
+ <li><strong>Step 3:</strong> Drafts personalized outreach emails for each contact</li>
2891
+ </ul>
2892
+ <em>Tip: Start with 2-3 prospects to test, then increase the number.</em>
2893
+ </div>
2894
+ </div>
2895
+ </div>
2896
+ """)
2897
 
2898
  client_status_2 = gr.HTML(get_client_status_html())
2899
 
 
2914
  gr.HTML("""<div class="page-header"><div>
2915
  <h1 class="page-title">🎯 Prospects</h1>
2916
  <p class="page-subtitle">Companies discovered by AI</p>
2917
+ </div></div>
2918
+
2919
+ <div class="info-box">
2920
+ <span class="info-box-icon">🏒</span>
2921
+ <div class="info-box-content">
2922
+ <div class="info-box-title">Your Prospect Companies</div>
2923
+ <div class="info-box-text">
2924
+ This list shows all companies found by the AI. Each prospect includes company details, industry, and a fit score (0-100) indicating how well they match your ideal customer profile. Higher scores = better fit!
2925
+ </div>
2926
+ </div>
2927
+ </div>
2928
+ """)
2929
  refresh_prospects_btn = gr.Button("πŸ”„ Refresh", variant="secondary", size="sm")
2930
  prospects_list = gr.HTML(get_prospects_html())
2931
 
 
2934
  gr.HTML("""<div class="page-header"><div>
2935
  <h1 class="page-title">πŸ‘₯ Contacts</h1>
2936
  <p class="page-subtitle">Decision makers found by AI</p>
2937
+ </div></div>
2938
+
2939
+ <div class="info-box">
2940
+ <span class="info-box-icon">πŸ‘€</span>
2941
+ <div class="info-box-content">
2942
+ <div class="info-box-title">Decision Maker Contacts</div>
2943
+ <div class="info-box-text">
2944
+ AI finds key decision-makers (CEOs, VPs, Founders, Directors) at each prospect company. Contact info includes name, title, email, and company. Only verified contacts with real email addresses are shown.
2945
+ </div>
2946
+ </div>
2947
+ </div>
2948
+ """)
2949
  refresh_contacts_btn = gr.Button("πŸ”„ Refresh", variant="secondary", size="sm")
2950
  contacts_list = gr.HTML(get_contacts_html())
2951
 
 
2954
  gr.HTML("""<div class="page-header"><div>
2955
  <h1 class="page-title">βœ‰οΈ Emails</h1>
2956
  <p class="page-subtitle">AI-drafted outreach emails</p>
2957
+ </div></div>
2958
+
2959
+ <div class="info-box tip">
2960
+ <span class="info-box-icon">✍️</span>
2961
+ <div class="info-box-content">
2962
+ <div class="info-box-title">AI-Written Outreach Emails</div>
2963
+ <div class="info-box-text">
2964
+ Each email is personalized based on the prospect's company, industry, and any pain points discovered during research. Review and customize before sending. Emails are designed to start conversations, not close deals.
2965
+ </div>
2966
+ </div>
2967
+ </div>
2968
+ """)
2969
  refresh_emails_btn = gr.Button("πŸ”„ Refresh", variant="secondary", size="sm")
2970
  emails_list = gr.HTML(get_emails_html())
2971
 
 
2974
  gr.HTML("""<div class="page-header"><div>
2975
  <h1 class="page-title">πŸ’¬ AI Chat</h1>
2976
  <p class="page-subtitle">Your AI sales assistant</p>
2977
+ </div></div>
2978
+
2979
+ <div class="info-box success">
2980
+ <span class="info-box-icon">πŸ€–</span>
2981
+ <div class="info-box-content">
2982
+ <div class="info-box-title">Your AI Sales Assistant</div>
2983
+ <div class="info-box-text">
2984
+ Chat with AI to research companies, draft emails, get talking points, or manage your pipeline. The AI has access to all your prospect data and can perform web searches for real-time info.
2985
+ </div>
2986
+ </div>
2987
+ </div>
2988
+ """)
2989
 
2990
  chatbot = gr.Chatbot(value=[], height=400, label="Chat")
2991
 
 
2999
  send_btn = gr.Button("Send", variant="primary", scale=1)
3000
 
3001
  gr.HTML("""<div class="action-card" style="margin-top: 16px;">
3002
+ <h4>πŸ’‘ Try These Prompts</h4>
3003
  <ul style="font-size: 13px; line-height: 1.8; margin: 8px 0 0 0; padding-left: 20px;">
3004
  <li>"Search for DTC fashion brands that raised Series A"</li>
3005
  <li>"Draft an email to the CEO of Warby Parker"</li>
 
3046
  btn_emails.click(fn=lambda: show_page("emails"), outputs=all_pages)
3047
  btn_chat.click(fn=lambda: show_page("chat"), outputs=all_pages)
3048
 
3049
+ # JavaScript to connect sidebar nav items to Gradio buttons (optimized)
3050
  gr.HTML("""
3051
  <script>
3052
+ // Cache for navigation buttons - populated once on load
3053
+ window._navButtonCache = null;
3054
+ window._pageOrder = ['setup', 'dashboard', 'discovery', 'prospects', 'contacts', 'emails', 'chat'];
3055
+
3056
+ // Initialize button cache
3057
+ function initNavCache() {
3058
+ if (window._navButtonCache) return window._navButtonCache;
3059
+ const buttons = document.querySelectorAll('.nav-buttons-row button');
3060
+ if (buttons.length >= 7) {
3061
+ window._navButtonCache = {};
3062
+ window._pageOrder.forEach((page, idx) => {
3063
+ window._navButtonCache[page] = buttons[idx];
3064
+ });
3065
+ }
3066
+ return window._navButtonCache;
3067
+ }
3068
+
3069
  window.selectPage = function(pageName) {
3070
+ // Close mobile sidebar immediately
3071
  if (window.closeMobileSidebar) {
3072
  window.closeMobileSidebar();
3073
  }
3074
 
3075
+ // Update active nav item in sidebar (instant visual feedback)
3076
  document.querySelectorAll('.nav-item').forEach(item => {
3077
+ item.classList.toggle('active', item.dataset.page === pageName);
 
 
 
3078
  });
3079
 
3080
+ // Use cached button reference for instant navigation
3081
+ const cache = initNavCache();
3082
+ if (cache && cache[pageName]) {
3083
+ cache[pageName].click();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3084
 
3085
+ // Update button row active state
3086
+ Object.values(cache).forEach(b => b.classList.remove('active-nav-btn'));
3087
+ cache[pageName].classList.add('active-nav-btn');
3088
+ return;
3089
+ }
3090
+
3091
+ // Fallback: direct index access (no searching)
3092
+ const buttons = document.querySelectorAll('.nav-buttons-row button');
3093
+ const idx = window._pageOrder.indexOf(pageName);
3094
+ if (idx >= 0 && buttons[idx]) {
3095
+ buttons[idx].click();
 
 
 
 
 
3096
  }
3097
  };
3098
 
3099
+ // Initialize cache after Gradio loads
3100
+ if (document.readyState === 'loading') {
3101
+ document.addEventListener('DOMContentLoaded', () => setTimeout(initNavCache, 100));
3102
+ } else {
3103
+ setTimeout(initNavCache, 100);
3104
+ }
 
 
 
 
 
 
3105
  </script>
3106
  """)
3107