ismdrobiul489 commited on
Commit
c00f68c
·
1 Parent(s): b4761cd

Add Gemini chatbot test widget with floating button and /api/chat endpoint

Browse files
Files changed (2) hide show
  1. app.py +54 -0
  2. static/index.html +188 -0
app.py CHANGED
@@ -97,6 +97,60 @@ async def list_modules():
97
  }
98
 
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  @app.get("/")
101
  async def read_root():
102
  """Serve the web UI"""
 
97
  }
98
 
99
 
100
+ # ==========================================
101
+ # GEMINI CHATBOT TEST ENDPOINT
102
+ # ==========================================
103
+ from pydantic import BaseModel
104
+ import os
105
+
106
+ class ChatRequest(BaseModel):
107
+ message: str
108
+
109
+ @app.post("/api/chat", tags=["Chat"])
110
+ async def chat_with_gemini(request: ChatRequest):
111
+ """
112
+ Test Gemini API connectivity.
113
+ Uses GEMINI_API_KEY from environment.
114
+ """
115
+ import requests
116
+
117
+ api_key = config.gemini_api_key or os.getenv("GEMINI_API_KEY")
118
+ if not api_key:
119
+ return {"error": "GEMINI_API_KEY not configured"}
120
+
121
+ try:
122
+ # Use Gemini REST API directly
123
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={api_key}"
124
+
125
+ payload = {
126
+ "contents": [{
127
+ "parts": [{"text": request.message}]
128
+ }]
129
+ }
130
+
131
+ response = requests.post(url, json=payload, timeout=30)
132
+
133
+ if response.status_code != 200:
134
+ return {"error": f"Gemini API error: {response.status_code} - {response.text[:200]}"}
135
+
136
+ data = response.json()
137
+
138
+ # Extract reply
139
+ candidates = data.get("candidates", [])
140
+ if candidates:
141
+ content = candidates[0].get("content", {})
142
+ parts = content.get("parts", [])
143
+ if parts:
144
+ reply = parts[0].get("text", "No response")
145
+ return {"reply": reply}
146
+
147
+ return {"error": "No response from Gemini"}
148
+
149
+ except Exception as e:
150
+ logger.error(f"Gemini chat error: {e}")
151
+ return {"error": str(e)}
152
+
153
+
154
  @app.get("/")
155
  async def read_root():
156
  """Serve the web UI"""
static/index.html CHANGED
@@ -673,7 +673,195 @@
673
  status.innerHTML = '❌ Error: ' + err.message;
674
  }
675
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
676
  </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
677
  </body>
678
 
679
  </html>
 
673
  status.innerHTML = '❌ Error: ' + err.message;
674
  }
675
  });
676
+
677
+ // ==========================================
678
+ // GEMINI CHATBOT TEST
679
+ // ==========================================
680
+ const chatBtn = document.getElementById('chatBtn');
681
+ const chatModal = document.getElementById('chatModal');
682
+ const chatClose = document.getElementById('chatClose');
683
+ const chatForm = document.getElementById('chatForm');
684
+ const chatInput = document.getElementById('chatInput');
685
+ const chatMessages = document.getElementById('chatMessages');
686
+
687
+ chatBtn.addEventListener('click', () => {
688
+ chatModal.classList.toggle('hidden');
689
+ });
690
+
691
+ chatClose.addEventListener('click', () => {
692
+ chatModal.classList.add('hidden');
693
+ });
694
+
695
+ chatForm.addEventListener('submit', async (e) => {
696
+ e.preventDefault();
697
+ const message = chatInput.value.trim();
698
+ if (!message) return;
699
+
700
+ // Add user message
701
+ addMessage(message, 'user');
702
+ chatInput.value = '';
703
+
704
+ // Add loading
705
+ const loadingId = addMessage('⏳ Thinking...', 'bot');
706
+
707
+ try {
708
+ const res = await fetch('/api/chat', {
709
+ method: 'POST',
710
+ headers: { 'Content-Type': 'application/json' },
711
+ body: JSON.stringify({ message })
712
+ });
713
+ const data = await res.json();
714
+
715
+ // Remove loading
716
+ document.getElementById(loadingId).remove();
717
+
718
+ if (data.reply) {
719
+ addMessage(data.reply, 'bot');
720
+ } else if (data.error) {
721
+ addMessage('❌ ' + data.error, 'bot');
722
+ }
723
+ } catch (err) {
724
+ document.getElementById(loadingId).remove();
725
+ addMessage('❌ Error: ' + err.message, 'bot');
726
+ }
727
+ });
728
+
729
+ function addMessage(text, type) {
730
+ const id = 'msg-' + Date.now();
731
+ const div = document.createElement('div');
732
+ div.id = id;
733
+ div.className = 'chat-message ' + type;
734
+ div.textContent = text;
735
+ chatMessages.appendChild(div);
736
+ chatMessages.scrollTop = chatMessages.scrollHeight;
737
+ return id;
738
+ }
739
  </script>
740
+
741
+ <!-- Chat Widget Button -->
742
+ <button id="chatBtn" class="chat-float-btn">💬</button>
743
+
744
+ <!-- Chat Modal -->
745
+ <div id="chatModal" class="chat-modal hidden">
746
+ <div class="chat-header">
747
+ <span>🤖 Gemini Chat Test</span>
748
+ <button id="chatClose">✕</button>
749
+ </div>
750
+ <div id="chatMessages" class="chat-body"></div>
751
+ <form id="chatForm" class="chat-input-area">
752
+ <input type="text" id="chatInput" placeholder="Type a message..." autocomplete="off">
753
+ <button type="submit">Send</button>
754
+ </form>
755
+ </div>
756
+
757
+ <style>
758
+ .chat-float-btn {
759
+ position: fixed;
760
+ bottom: 30px;
761
+ right: 30px;
762
+ width: 60px;
763
+ height: 60px;
764
+ border-radius: 50%;
765
+ background: linear-gradient(135deg, #6366f1, #a855f7);
766
+ border: none;
767
+ font-size: 28px;
768
+ cursor: pointer;
769
+ box-shadow: 0 4px 20px rgba(99, 102, 241, 0.5);
770
+ z-index: 9999;
771
+ transition: transform 0.2s;
772
+ }
773
+
774
+ .chat-float-btn:hover {
775
+ transform: scale(1.1);
776
+ }
777
+
778
+ .chat-modal {
779
+ position: fixed;
780
+ bottom: 100px;
781
+ right: 30px;
782
+ width: 380px;
783
+ height: 500px;
784
+ background: var(--bg-card);
785
+ border-radius: 16px;
786
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
787
+ display: flex;
788
+ flex-direction: column;
789
+ z-index: 9998;
790
+ overflow: hidden;
791
+ }
792
+
793
+ .chat-modal.hidden {
794
+ display: none;
795
+ }
796
+
797
+ .chat-header {
798
+ padding: 15px 20px;
799
+ background: linear-gradient(135deg, #6366f1, #a855f7);
800
+ display: flex;
801
+ justify-content: space-between;
802
+ align-items: center;
803
+ font-weight: 600;
804
+ }
805
+
806
+ .chat-header button {
807
+ background: none;
808
+ border: none;
809
+ color: white;
810
+ font-size: 18px;
811
+ cursor: pointer;
812
+ }
813
+
814
+ .chat-body {
815
+ flex: 1;
816
+ padding: 15px;
817
+ overflow-y: auto;
818
+ display: flex;
819
+ flex-direction: column;
820
+ gap: 10px;
821
+ }
822
+
823
+ .chat-message {
824
+ padding: 10px 14px;
825
+ border-radius: 12px;
826
+ max-width: 85%;
827
+ word-wrap: break-word;
828
+ }
829
+
830
+ .chat-message.user {
831
+ background: var(--accent);
832
+ align-self: flex-end;
833
+ }
834
+
835
+ .chat-message.bot {
836
+ background: var(--bg-secondary);
837
+ align-self: flex-start;
838
+ }
839
+
840
+ .chat-input-area {
841
+ display: flex;
842
+ padding: 10px;
843
+ gap: 10px;
844
+ border-top: 1px solid var(--border);
845
+ }
846
+
847
+ .chat-input-area input {
848
+ flex: 1;
849
+ padding: 12px;
850
+ border-radius: 8px;
851
+ border: none;
852
+ background: var(--bg-secondary);
853
+ color: var(--text-primary);
854
+ }
855
+
856
+ .chat-input-area button {
857
+ padding: 12px 20px;
858
+ border-radius: 8px;
859
+ border: none;
860
+ background: var(--accent);
861
+ color: white;
862
+ cursor: pointer;
863
+ }
864
+ </style>
865
  </body>
866
 
867
  </html>