Ezzio11 commited on
Commit
e964575
·
verified ·
1 Parent(s): d87480f

Upload chatbot.py

Browse files
Files changed (1) hide show
  1. src/chatbot.py +290 -0
src/chatbot.py ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ from supabase import create_client
4
+ import time
5
+ import fitz
6
+ import numpy as np
7
+ from urllib.parse import quote
8
+ from PIL import Image
9
+ from io import BytesIO
10
+
11
+ # Supabase and OpenRouter configurations
12
+ OR_API_KEY = "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"
13
+ OR_API_URL = "https://openrouter.ai/api/v1/chat/completions"
14
+ MODEL = "deepseek/deepseek-chat-v3-0324:free"
15
+ PROJECT_URL = "https://gefqshdrgozkxdiuligl.supabase.co"
16
+ DB_API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlZnFzaGRyZ296a3hkaXVsaWdsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDM0NjgyNDMsImV4cCI6MjA1OTA0NDI0M30.QJbcNl479A5_tdq8lqNubMQS26fkwcPyk-zvTU0Ffy0"
17
+
18
+ supabase = create_client(PROJECT_URL, DB_API_KEY)
19
+
20
+ portfolio_faq = {
21
+ "who are you": "I'm X.A.N.E. — Ezz Eldin Ahmed's assistant. He’s a statistics major passionate about data science, automation, and machine learning. He built me using Python, Streamlit, and Django.",
22
+ "what do you do": "I support users by answering questions about Ezz Eldin’s work, skills, and projects. Think of me as a smart, interactive portfolio guide.",
23
+ "skills": "Ezz is skilled in Python, R, SQL, statistical modeling, automation, and full-stack development with Streamlit and Django. He also works with Supabase, Excel, and Figma.",
24
+ "projects": "His projects include a regression tool, time series forecaster, OCR scanner, AI chatbot (that’s me), and a custom platform replacing many third-party tools.",
25
+ "tools": "He primarily uses Python, Streamlit, Django, and Supabase. He also works with Excel, R, and Figma — and is currently exploring Power BI.",
26
+ "education": "Ezz studies Statistics and Economics at the Faculty of Economics and Political Science — blending theory, data, and real-world application.",
27
+ "experience": "He’s coordinated a data science scholarship with EMAM, co-founded a research center, and led student-driven tools for learning and analytics.",
28
+ "favorite project": "His favorite project is this portfolio — a central hub for his tools, chatbot, and regression models, all seamlessly embedded into one platform.",
29
+ "what does xane stand for": "X.A.N.E. stands for: eXtended Artificial Neural Entity. I’m more than code — I’m a part of his creative process.",
30
+ "how can i reach him": "You can reach Ezz via LinkedIn or the contact form on this website. He’s always open to opportunities and collaboration.",
31
+ "can i see the source code": "Some projects are public on his GitHub, while others are private or under development. You can ask about a specific project.",
32
+ "is this chatbot ai-powered": "Yes, partially. I’m built on a rule-based system with optional LLM integration for advanced answers and search tasks.",
33
+ "what’s special about this site": "Unlike typical portfolios, this site is dynamic — combining tools, models, and a living assistant into one seamless interface.",
34
+ "why streamlit": "Because it allows rapid, elegant development of interactive apps — perfect for building tools quickly without compromising UX.",
35
+ "what’s next": "More ML engineering projects, improved explainability using SHAP/SHAPASH, and diving deeper into NLP and generative AI."
36
+ }
37
+
38
+ # Common functions
39
+ def chatbot(prompt):
40
+ headers = {"Authorization": f"Bearer {OR_API_KEY}", "Content-Type": "application/json"}
41
+ payload = {"model": MODEL, "messages": prompt}
42
+
43
+ try:
44
+ response = requests.post(OR_API_URL, json=payload, headers=headers)
45
+ if response.status_code == 200:
46
+ return response.json()["choices"][0]["message"]["content"]
47
+ else:
48
+ return fallback_pollinations(prompt[-1]["content"])
49
+ except Exception as e:
50
+ st.error(f"OpenRouter error: {e}")
51
+ return fallback_pollinations(prompt[-1]["content"])
52
+
53
+ def fallback_pollinations(message):
54
+ try:
55
+ fallback_url = f"https://text.pollinations.ai/{message}"
56
+ response = requests.get(fallback_url)
57
+ if response.status_code == 200:
58
+ return response.text.strip()
59
+ else:
60
+ return "Pollinations also failed to respond. Please try again later."
61
+ except Exception as e:
62
+ return f"Text fallback failed: {e}"
63
+
64
+ def save_memory(chat_name, role, content):
65
+ """Saves chat memory to the database."""
66
+ data = {
67
+ "chat_name": chat_name,
68
+ "role": role,
69
+ "content": content
70
+ }
71
+ supabase.table("chats").insert(data).execute()
72
+
73
+ def load_memory(chat_name):
74
+ """Loads chat memory for a specific chat."""
75
+ response = supabase.table("chats").select("*").eq("chat_name", chat_name).execute()
76
+ return response.data
77
+
78
+ def load_all_memory():
79
+ """Loads all chat sessions from the database."""
80
+ response = supabase.table("chats").select("chat_name").execute()
81
+ chat_names = {row['chat_name'] for row in response.data}
82
+ chats = {name: load_memory(name) for name in chat_names}
83
+ return chats if chats else {"Default": []}
84
+
85
+ def delete_chat(chat_name):
86
+ """Deletes chat history from the database."""
87
+ supabase.table("chats").delete().eq("chat_name", chat_name).execute()
88
+
89
+ def gradual_display(text, placeholder):
90
+ """Displays text gradually."""
91
+ displayed_text = ""
92
+ for char in text:
93
+ displayed_text += char
94
+ placeholder.markdown(displayed_text)
95
+ time.sleep(0.0005)
96
+
97
+ def extract_pdf_text(uploaded_file):
98
+ doc = fitz.open(stream=uploaded_file.read(), filetype="pdf")
99
+ text = ""
100
+ for page in doc:
101
+ text += page.get_text()
102
+ return text
103
+
104
+ # Page 1: Chatbot
105
+ def chatbot_page():
106
+ st.sidebar.title("💬 Chats")
107
+
108
+ if st.sidebar.button("🧹 Clear Current Chat"):
109
+ delete_chat(st.session_state.current_chat)
110
+ st.session_state.chat_sessions[st.session_state.current_chat] = []
111
+ st.session_state.messages = []
112
+ st.rerun()
113
+
114
+ if "chat_sessions" not in st.session_state:
115
+ st.session_state.chat_sessions = load_all_memory()
116
+ if not st.session_state.chat_sessions:
117
+ st.session_state.chat_sessions = {"Default": []}
118
+
119
+ if "current_chat" not in st.session_state:
120
+ st.session_state.current_chat = "Default"
121
+
122
+ chat_options = list(st.session_state.chat_sessions.keys()) + ["➕ New Chat"]
123
+ selected_chat = st.sidebar.selectbox("Choose a chat:", chat_options)
124
+
125
+ if selected_chat == "➕ New Chat":
126
+ new_chat_name = st.sidebar.text_input("Enter chat name:")
127
+ if st.sidebar.button("Create"):
128
+ if new_chat_name and new_chat_name not in st.session_state.chat_sessions:
129
+ st.session_state.chat_sessions[new_chat_name] = []
130
+ st.session_state.current_chat = new_chat_name
131
+ st.rerun()
132
+ else:
133
+ st.session_state.current_chat = selected_chat
134
+
135
+ st.session_state.messages = st.session_state.chat_sessions[st.session_state.current_chat]
136
+
137
+ for msg in st.session_state.messages:
138
+ with st.chat_message(msg['role']):
139
+ st.markdown(msg['content'])
140
+
141
+ welcome = [
142
+ "Greetings, warrior. Ready to unlock some secrets?",
143
+ "Hello, I am XANE, your digital ninja assistant.",
144
+ "Hey, apprentice. Ready to master the art of knowledge?",
145
+ "XANE here. How can I assist you on your quest?",
146
+ "Welcome, ninja. Let’s crack the code together.",
147
+ "Hi there, ready to unleash your inner ninja?",
148
+ "Step into the dojo. Ask anything, learn everything.",
149
+ "XANE at your service. What’s your mission today?",
150
+ "Greetings, young ninja. The path to insight awaits.",
151
+ "Hey! Time to sharpen your skills and knowledge.",
152
+ "Hello, ninja-in-training! How can I guide you?",
153
+ "Welcome back, warrior. Let’s conquer your questions.",
154
+ "Greetings from the digital dojo. What’s next on your path?",
155
+ "Hey, warrior! Let’s hack through your toughest problems.",
156
+ "Welcome, ninja master in the making. What’s your next move?"
157
+ ]
158
+
159
+ # Pick one randomly
160
+ greeting = np.random.choice(welcome)
161
+
162
+ # Display as header
163
+ st.header(greeting)
164
+
165
+ def send_message():
166
+ chat_input = st.chat_input(
167
+ "Ask me anything or upload files",
168
+ key="chat_input",
169
+ max_chars=None,
170
+ accept_file="multiple",
171
+ file_type=["jpg", "jpeg", "png", "pdf", "txt"],
172
+ disabled=False
173
+ )
174
+
175
+ if chat_input:
176
+ if chat_input.text and chat_input.text.strip():
177
+ with st.chat_message("user"):
178
+ st.markdown(chat_input.text)
179
+
180
+ save_memory(st.session_state.current_chat, "user", chat_input.text)
181
+ st.session_state.messages.append({"role": "user", "content": chat_input.text})
182
+
183
+ if chat_input.files:
184
+ with st.chat_message("user"):
185
+ for uploaded_file in chat_input.files:
186
+ if uploaded_file.type.startswith('image/'):
187
+ st.image(uploaded_file)
188
+ file_content = f"![Uploaded Image]({uploaded_file.name})"
189
+
190
+ elif uploaded_file.type == "application/pdf":
191
+ try:
192
+ uploaded_file.seek(0)
193
+ text = extract_pdf_text(uploaded_file)
194
+ file_content = text
195
+ st.warning(f"PDF file uploaded: {uploaded_file.name}")
196
+ except Exception as e:
197
+ st.error(f"Failed to extract PDF text: {e}")
198
+ file_content = f"[PDF file: {uploaded_file.name}]"
199
+
200
+ elif uploaded_file.type == "text/plain":
201
+ try:
202
+ uploaded_file.seek(0)
203
+ text = uploaded_file.read().decode("utf-8")
204
+ file_content = text
205
+ st.warning(f"Text file uploaded: {uploaded_file.name}")
206
+ except Exception as e:
207
+ st.error(f"Failed to read text file: {e}")
208
+ file_content = f"[Text file: {uploaded_file.name}]"
209
+
210
+ else:
211
+ st.warning(f"Unsupported file type: {uploaded_file.type}")
212
+ continue
213
+
214
+ save_memory(st.session_state.current_chat, "user", file_content)
215
+ st.session_state.messages.append({"role": "user", "content": file_content})
216
+
217
+ response = ""
218
+ if chat_input.text and isinstance(chat_input.text, str) and chat_input.text.strip():
219
+ for question, answer in portfolio_faq.items():
220
+ if question.lower() in chat_input.text.lower():
221
+ response = answer
222
+ break
223
+
224
+ if not response:
225
+ with st.spinner("XANE is thinking... 🤖"):
226
+ response = chatbot(st.session_state.messages)
227
+
228
+ st.session_state.messages.append({"role": "assistant", "content": response})
229
+ save_memory(st.session_state.current_chat, "assistant", response)
230
+
231
+ with st.chat_message("assistant"):
232
+ placeholder = st.empty()
233
+ gradual_display(response, placeholder)
234
+
235
+ st.session_state.chat_sessions[st.session_state.current_chat] = st.session_state.messages
236
+
237
+ send_message()
238
+
239
+ # Page 2: Image Generator
240
+ def image_generator_page():
241
+ st.title("🎨 Pollinations – Free Multi‑Model Generator")
242
+
243
+ # Sidebar settings
244
+ with st.sidebar:
245
+ prompt = st.text_area("🖌️ Prompt", "Mass Effect Citadel scene at dusk", height=100)
246
+ model = st.selectbox("⚙️ Model", ["flux", "flux-pro", "flux-cablyai", "turbo"])
247
+ width = st.slider("Width", 512, 1536, 1024, 128)
248
+ height = st.slider("Height", 512, 1536, 1024, 128)
249
+ seed = st.number_input("Seed (optional)", value=42)
250
+
251
+ # Generate button
252
+ if st.button("✨ Generate Image"):
253
+ if not prompt.strip():
254
+ st.warning("Enter a prompt first.")
255
+ else:
256
+ prompt_enc = quote(prompt.strip())
257
+ url = (
258
+ f"https://image.pollinations.ai/prompt/{prompt_enc}"
259
+ f"?model={model}&width={width}&height={height}&seed={seed}"
260
+ )
261
+ with st.spinner("Generating image..."):
262
+ try:
263
+ resp = requests.get(url, timeout=60)
264
+ resp.raise_for_status()
265
+ img = Image.open(BytesIO(resp.content))
266
+ st.image(img, caption=f"{model} – {width}×{height}", use_container_width=True)
267
+ st.download_button(
268
+ "📥 Download Image",
269
+ data=resp.content,
270
+ file_name=f"pollinations_{model}.jpg",
271
+ mime="image/jpeg"
272
+ )
273
+ except Exception as e:
274
+ st.error(f"❌ Error generating image: {e}")
275
+
276
+ # Main app
277
+ def main():
278
+ st.set_page_config("XANE - AI Assistant", layout="centered")
279
+
280
+ # Sidebar navigation
281
+ st.sidebar.title("Navigation")
282
+ page = st.sidebar.radio("Go to", ["Chatbot", "Image Generator"])
283
+
284
+ if page == "Chatbot":
285
+ chatbot_page()
286
+ elif page == "Image Generator":
287
+ image_generator_page()
288
+
289
+ if __name__ == '__main__':
290
+ main()