Yoonc commited on
Commit
f7c6da6
·
verified ·
1 Parent(s): a740509

Upload 2 files

Browse files
Files changed (2) hide show
  1. example.py +348 -0
  2. templates/index.html +837 -0
example.py ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Concept: Flask + HTML Integration - Spiritual Path Assessment Tool
3
+
4
+ This app helps users discover which religious or spiritual path aligns with their
5
+ beliefs, values, lifestyle, and background through an interactive questionnaire.
6
+ """
7
+ # cSpell:ignore jsonify
8
+
9
+ from flask import Flask, render_template, request, jsonify, session, redirect, url_for
10
+ import json
11
+ import os
12
+ import warnings
13
+ from dotenv import load_dotenv
14
+ from together import Together
15
+
16
+ warnings.filterwarnings("ignore")
17
+ load_dotenv()
18
+
19
+ app = Flask(__name__)
20
+ app.secret_key = 'spiritual-journey-finder-2024'
21
+
22
+ # File to store user data
23
+ USERS_FILE = 'users_data.json'
24
+
25
+ # Together API for chatbot
26
+ TOGETHER_API_KEY = os.getenv("TOGETHER_API_KEY")
27
+ client = Together(api_key=TOGETHER_API_KEY) if TOGETHER_API_KEY else None
28
+
29
+ # Assessment Questions
30
+ QUESTIONS = [
31
+ {
32
+ "id": 1,
33
+ "question": "What is your view on the nature of the divine?",
34
+ "options": {
35
+ "One supreme God who created everything": {"christianity": 3, "islam": 3, "judaism": 3},
36
+ "Multiple gods and goddesses": {"hinduism": 3, "paganism": 3},
37
+ "A universal energy or force": {"buddhism": 2, "taoism": 3, "new_age": 3},
38
+ "No divine being, focus on human potential": {"humanism": 3, "atheism": 3},
39
+ "Uncertain or unknowable": {"agnosticism": 3}
40
+ }
41
+ },
42
+ {
43
+ "id": 2,
44
+ "question": "How do you prefer to connect with spirituality?",
45
+ "options": {
46
+ "Through organized worship and community": {"christianity": 2, "islam": 2, "judaism": 2},
47
+ "Through personal meditation and reflection": {"buddhism": 3, "hinduism": 2, "taoism": 2},
48
+ "Through nature and natural cycles": {"paganism": 3, "indigenous": 3},
49
+ "Through reason and philosophy": {"humanism": 2, "stoicism": 3},
50
+ "I don't feel the need for spiritual connection": {"atheism": 3}
51
+ }
52
+ },
53
+ {
54
+ "id": 3,
55
+ "question": "What is your belief about the afterlife?",
56
+ "options": {
57
+ "Heaven or Hell based on faith/deeds": {"christianity": 3, "islam": 3},
58
+ "Reincarnation until enlightenment": {"hinduism": 3, "buddhism": 3},
59
+ "Ancestral realm or spiritual world": {"indigenous": 2, "paganism": 2},
60
+ "No afterlife, this life is all there is": {"atheism": 3, "humanism": 2},
61
+ "Unsure or open to possibilities": {"agnosticism": 2, "new_age": 2}
62
+ }
63
+ },
64
+ {
65
+ "id": 4,
66
+ "question": "What guides your moral and ethical decisions?",
67
+ "options": {
68
+ "Sacred texts and religious teachings": {"christianity": 3, "islam": 3, "judaism": 3},
69
+ "Universal principles of compassion and mindfulness": {"buddhism": 3, "jainism": 3},
70
+ "Harmony with nature and balance": {"taoism": 3, "indigenous": 2},
71
+ "Reason, empathy, and human rights": {"humanism": 3, "secularism": 3},
72
+ "Personal intuition and inner wisdom": {"new_age": 2, "spiritualism": 3}
73
+ }
74
+ },
75
+ {
76
+ "id": 5,
77
+ "question": "What role does ritual or practice play in your life?",
78
+ "options": {
79
+ "Regular prayer and worship are essential": {"islam": 3, "christianity": 2, "judaism": 2},
80
+ "Daily meditation or mindfulness practice": {"buddhism": 3, "hinduism": 2, "zen": 3},
81
+ "Seasonal celebrations and ceremonies": {"paganism": 3, "wicca": 3},
82
+ "Minimal to no ritual, prefer intellectual engagement": {"humanism": 2, "deism": 2},
83
+ "Flexible, whatever feels meaningful to me": {"new_age": 2, "spiritual_not_religious": 3}
84
+ }
85
+ },
86
+ {
87
+ "id": 6,
88
+ "question": "How do you view the relationship between humans and nature?",
89
+ "options": {
90
+ "Humans are stewards of God's creation": {"christianity": 2, "islam": 2, "judaism": 2},
91
+ "All life is interconnected and sacred": {"buddhism": 2, "hinduism": 2, "jainism": 3},
92
+ "Nature itself is divine": {"paganism": 3, "pantheism": 3, "indigenous": 3},
93
+ "Nature follows natural laws we can understand": {"atheism": 2, "humanism": 2},
94
+ "We should live in harmony with natural flow": {"taoism": 3, "shintoism": 2}
95
+ }
96
+ },
97
+ {
98
+ "id": 7,
99
+ "question": "What is your view on suffering and its purpose?",
100
+ "options": {
101
+ "A test of faith or part of God's plan": {"christianity": 2, "islam": 2},
102
+ "Result of attachment and desire": {"buddhism": 3, "stoicism": 2},
103
+ "Karma from past actions": {"hinduism": 3, "sikhism": 2},
104
+ "Random or result of natural causes": {"atheism": 3, "secular": 2},
105
+ "An opportunity for growth and learning": {"new_age": 2, "spiritualism": 2}
106
+ }
107
+ },
108
+ {
109
+ "id": 8,
110
+ "question": "How important is community in your spiritual life?",
111
+ "options": {
112
+ "Very important, prefer group worship": {"christianity": 2, "islam": 2, "sikhism": 3},
113
+ "Somewhat important, but personal practice matters more": {"buddhism": 2, "hinduism": 2},
114
+ "Community of like-minded seekers": {"paganism": 2, "unitarian": 3},
115
+ "Not important, spirituality is personal": {"spiritual_not_religious": 3, "deism": 2},
116
+ "Prefer secular community over religious": {"humanism": 2, "atheism": 2}
117
+ }
118
+ }
119
+ ]
120
+
121
+ # Religion Descriptions
122
+ RELIGIONS = {
123
+ "christianity": {"name": "Christianity", "description": "Faith in Jesus Christ emphasizing love, forgiveness, and salvation through grace.", "practices": "Prayer, Bible study, church, communion", "core_beliefs": "Trinity, salvation through Christ, eternal life"},
124
+ "islam": {"name": "Islam", "description": "Submission to Allah through Prophet Muhammad's teachings and the Quran.", "practices": "Five daily prayers, Ramadan fasting, charity, Mecca pilgrimage", "core_beliefs": "One God (Allah), Muhammad as prophet, Day of Judgment"},
125
+ "buddhism": {"name": "Buddhism", "description": "Path to enlightenment through mindfulness and compassion.", "practices": "Meditation, mindfulness, Eightfold Path", "core_beliefs": "Four Noble Truths, impermanence, ending suffering"},
126
+ "hinduism": {"name": "Hinduism", "description": "Ancient tradition embracing diverse paths to spiritual realization.", "practices": "Yoga, meditation, puja, festivals", "core_beliefs": "Dharma, karma, reincarnation, moksha, multiple paths"},
127
+ "judaism": {"name": "Judaism", "description": "Covenant with God through Torah and Jewish community.", "practices": "Shabbat, Torah study, prayer, kosher", "core_beliefs": "One God, Torah as divine law, ethical monotheism"},
128
+ "taoism": {"name": "Taoism", "description": "Living in harmony with the Tao - the natural order.", "practices": "Meditation, tai chi, wu wei, simplicity", "core_beliefs": "Yin-yang balance, harmony with nature"},
129
+ "paganism": {"name": "Modern Paganism", "description": "Nature-based spirituality honoring seasonal cycles.", "practices": "Seasonal celebrations, rituals, nature work", "core_beliefs": "Nature as sacred, multiple deities"},
130
+ "humanism": {"name": "Secular Humanism", "description": "Ethics emphasizing human values and reason without supernatural beliefs.", "practices": "Critical thinking, ethical living, community service", "core_beliefs": "Human dignity, reason, science, secular ethics"},
131
+ "atheism": {"name": "Atheism", "description": "Lack of belief in deities with naturalistic worldview.", "practices": "Evidence-based thinking, secular community", "core_beliefs": "No gods, natural explanations, this-life focus"},
132
+ "agnosticism": {"name": "Agnosticism", "description": "Divine existence is unknown or unknowable.", "practices": "Philosophical inquiry, ethical living", "core_beliefs": "Uncertainty about divine, questions over answers"},
133
+ "new_age": {"name": "New Age Spirituality", "description": "Eclectic approach emphasizing personal growth.", "practices": "Meditation, energy work, crystals, yoga", "core_beliefs": "Personal transformation, universal consciousness"},
134
+ "spiritual_not_religious": {"name": "Spiritual But Not Religious", "description": "Personal spirituality without organized religion.", "practices": "Personal practices, meditation, self-reflection", "core_beliefs": "Individual journey, authenticity, diverse wisdom"},
135
+ "sikhism": {"name": "Sikhism", "description": "One God emphasizing service, equality, and meditation.", "practices": "Prayer, meditation, community service, 5 Ks", "core_beliefs": "One God, equality, honest living, sharing"},
136
+ "indigenous": {"name": "Indigenous Spirituality", "description": "Traditional practices honoring ancestors and land.", "practices": "Ceremonies, storytelling, seasonal rituals", "core_beliefs": "Land connection, ancestor veneration, reciprocity"}
137
+ }
138
+
139
+ def load_users():
140
+ """Load users from JSON file"""
141
+ if os.path.exists(USERS_FILE):
142
+ with open(USERS_FILE, 'r') as f:
143
+ return json.load(f)
144
+ return {}
145
+
146
+ def save_users(users):
147
+ """Save users to JSON file"""
148
+ with open(USERS_FILE, 'w') as f:
149
+ json.dump(users, f, indent=2)
150
+
151
+ def calculate_results(answers):
152
+ """Calculate which spiritual paths align with user's answers"""
153
+ scores = {}
154
+
155
+ for answer in answers:
156
+ question = next((q for q in QUESTIONS if q["id"] == answer["question_id"]), None)
157
+ if question and answer["answer"] in question["options"]:
158
+ points = question["options"][answer["answer"]]
159
+ for religion, score in points.items():
160
+ scores[religion] = scores.get(religion, 0) + score
161
+
162
+ # Sort by score
163
+ sorted_scores = sorted(scores.items(), key=lambda x: x[1], reverse=True)
164
+
165
+ # Get top 3 recommendations
166
+ recommendations = []
167
+ for religion_key, score in sorted_scores[:3]:
168
+ if religion_key in RELIGIONS:
169
+ religion_info = RELIGIONS[religion_key].copy()
170
+ religion_info["score"] = score
171
+ religion_info["percentage"] = round((score / (len(answers) * 3)) * 100)
172
+ recommendations.append(religion_info)
173
+
174
+ return recommendations
175
+
176
+ @app.route("/")
177
+ def home():
178
+ if 'username' not in session:
179
+ return redirect(url_for('login'))
180
+
181
+ users = load_users()
182
+ user_data = users.get(session['username'], {})
183
+ has_results = 'results' in user_data and user_data['results']
184
+
185
+ return render_template(
186
+ "index.html",
187
+ title="Spiritual Path Finder",
188
+ message=f"Welcome, {session['username']}! 🌟",
189
+ username=session['username'],
190
+ logged_in=True,
191
+ questions=QUESTIONS,
192
+ has_results=has_results,
193
+ results=user_data.get('results', []) if has_results else []
194
+ )
195
+
196
+ @app.route("/login", methods=["GET", "POST"])
197
+ def login():
198
+ if request.method == "POST":
199
+ data = request.json
200
+ username = data.get('username', '').strip()
201
+ password = data.get('password', '')
202
+
203
+ users = load_users()
204
+
205
+ if username in users and users[username]['password'] == password:
206
+ session['username'] = username
207
+ return jsonify({"success": True})
208
+ else:
209
+ return jsonify({"success": False, "message": "Invalid credentials!"})
210
+
211
+ return render_template("index.html", logged_in=False, is_signup=False)
212
+
213
+ @app.route("/signup", methods=["GET", "POST"])
214
+ def signup():
215
+ if request.method == "POST":
216
+ data = request.json
217
+ username = data.get('username', '').strip()
218
+ password = data.get('password', '')
219
+
220
+ users = load_users()
221
+
222
+ if username in users:
223
+ return jsonify({"success": False, "message": "Username already exists!"})
224
+
225
+ if not username or not password:
226
+ return jsonify({"success": False, "message": "Username and password required!"})
227
+
228
+ # Create new user
229
+ users[username] = {
230
+ 'password': password,
231
+ 'answers': [],
232
+ 'results': []
233
+ }
234
+ save_users(users)
235
+ session['username'] = username
236
+ return jsonify({"success": True})
237
+
238
+ return render_template("index.html", logged_in=False, is_signup=True)
239
+
240
+ @app.route("/logout")
241
+ def logout():
242
+ session.pop('username', None)
243
+ return redirect(url_for('login'))
244
+
245
+ @app.route("/submit_assessment", methods=["POST"])
246
+ def submit_assessment():
247
+ if 'username' not in session:
248
+ return jsonify({"success": False, "message": "Not logged in"})
249
+
250
+ data = request.json
251
+ answers = data.get('answers', [])
252
+
253
+ if len(answers) != len(QUESTIONS):
254
+ return jsonify({"success": False, "message": "Please answer all questions!"})
255
+
256
+ # Calculate results
257
+ results = calculate_results(answers)
258
+
259
+ # Save to user data
260
+ users = load_users()
261
+ if session['username'] in users:
262
+ users[session['username']]['answers'] = answers
263
+ users[session['username']]['results'] = results
264
+ save_users(users)
265
+
266
+ return jsonify({"success": True, "results": results})
267
+
268
+ return jsonify({"success": False, "message": "User not found"})
269
+
270
+ @app.route("/reset_assessment", methods=["POST"])
271
+ def reset_assessment():
272
+ if 'username' not in session:
273
+ return jsonify({"success": False, "message": "Not logged in"})
274
+
275
+ users = load_users()
276
+ if session['username'] in users:
277
+ users[session['username']]['answers'] = []
278
+ users[session['username']]['results'] = []
279
+ save_users(users)
280
+ return jsonify({"success": True})
281
+
282
+ return jsonify({"success": False, "message": "User not found"})
283
+
284
+ @app.route("/chat", methods=["POST"])
285
+ def chat():
286
+ if 'username' not in session:
287
+ return jsonify({"success": False, "message": "Not logged in"})
288
+
289
+ if not client:
290
+ return jsonify({"success": False, "message": "Chat service not configured. Please set TOGETHER_API_KEY."})
291
+
292
+ data = request.json
293
+ user_message = data.get('message', '').strip()
294
+ religion_name = data.get('religion', '')
295
+ chat_history = data.get('history', [])
296
+
297
+ if not user_message or not religion_name:
298
+ return jsonify({"success": False, "message": "Message and religion required"})
299
+
300
+ # Find religion details
301
+ religion_data = None
302
+ for key, value in RELIGIONS.items():
303
+ if value['name'] == religion_name:
304
+ religion_data = value
305
+ break
306
+
307
+ if not religion_data:
308
+ return jsonify({"success": False, "message": "Religion not found"})
309
+
310
+ # Create context-aware system prompt
311
+ system_prompt = f"""You're a spiritual guide for {religion_data['name']}.
312
+ Info: {religion_data['description']} | Practices: {religion_data['practices']} | Beliefs: {religion_data['core_beliefs']}
313
+ Rules: Keep 30-50 words, be respectful, use * for bullet points (format: "Text: * item * item"), answer directly."""
314
+
315
+ # Build conversation history
316
+ messages = [{"role": "system", "content": system_prompt}]
317
+
318
+ # Add chat history (last 5 messages for context)
319
+ for msg in chat_history[-5:]:
320
+ messages.append({"role": msg["role"], "content": msg["content"]})
321
+
322
+ # Add current user message
323
+ messages.append({"role": "user", "content": user_message})
324
+
325
+ try:
326
+ # Call Together API with limited tokens for concise responses
327
+ response = client.chat.completions.create(
328
+ model="meta-llama/Meta-Llama-3-8B-Instruct-Lite",
329
+ messages=messages,
330
+ max_tokens=80, # Roughly 50-60 words maximum
331
+ temperature=0.7,
332
+ )
333
+
334
+ bot_response = response.choices[0].message.content
335
+
336
+ return jsonify({
337
+ "success": True,
338
+ "response": bot_response
339
+ })
340
+
341
+ except Exception as e:
342
+ return jsonify({
343
+ "success": False,
344
+ "message": f"Chat error: {str(e)}"
345
+ })
346
+
347
+ if __name__ == "__main__":
348
+ app.run(debug=True, port=5001)
templates/index.html ADDED
@@ -0,0 +1,837 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>{{ title if logged_in else 'Spiritual Path Finder - Login' }}</title>
5
+ <style>
6
+ * {
7
+ margin: 0;
8
+ padding: 0;
9
+ box-sizing: border-box;
10
+ }
11
+
12
+ body {
13
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
14
+ background: #F5F5F5;
15
+ min-height: 100vh;
16
+ display: flex;
17
+ justify-content: center;
18
+ align-items: center;
19
+ padding: 20px;
20
+ }
21
+
22
+ .container {
23
+ background: white;
24
+ border-radius: 16px;
25
+ padding: 40px;
26
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
27
+ max-width: 700px;
28
+ width: 100%;
29
+ animation: slideIn 0.4s ease;
30
+ max-height: 90vh;
31
+ overflow-y: auto;
32
+ }
33
+
34
+ @keyframes slideIn {
35
+ from { opacity: 0; transform: translateY(20px); }
36
+ to { opacity: 1; transform: translateY(0); }
37
+ }
38
+
39
+ h1 {
40
+ color: #3D3D3D;
41
+ font-size: 32px;
42
+ margin-bottom: 8px;
43
+ text-align: center;
44
+ font-weight: 800;
45
+ }
46
+
47
+ p {
48
+ color: #6B7280;
49
+ text-align: center;
50
+ margin-bottom: 30px;
51
+ font-size: 15px;
52
+ }
53
+
54
+ .subtitle {
55
+ color: #9CA3AF;
56
+ font-size: 14px;
57
+ text-align: center;
58
+ margin-bottom: 25px;
59
+ line-height: 1.6;
60
+ }
61
+
62
+ input[type="text"], input[type="password"] {
63
+ width: 100%;
64
+ padding: 12px 16px;
65
+ font-size: 15px;
66
+ border: none;
67
+ background: #F5F5F5;
68
+ border-radius: 10px;
69
+ transition: all 0.2s;
70
+ outline: none;
71
+ }
72
+
73
+ input:focus {
74
+ background: #EBEBEB;
75
+ box-shadow: 0 0 0 2px #E5E5E5;
76
+ }
77
+
78
+ button, .btn {
79
+ padding: 12px 24px;
80
+ font-size: 15px;
81
+ background: #3D3D3D;
82
+ color: white;
83
+ border: none;
84
+ border-radius: 10px;
85
+ cursor: pointer;
86
+ transition: all 0.2s;
87
+ font-weight: 600;
88
+ text-decoration: none;
89
+ display: inline-block;
90
+ }
91
+
92
+ button:hover, .btn:hover {
93
+ background: #1A1A1A;
94
+ transform: translateY(-1px);
95
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
96
+ }
97
+
98
+ button:active, .btn:active { transform: translateY(0); }
99
+ button:disabled { background: #E5E5E5; color: #999; cursor: not-allowed; transform: none; }
100
+
101
+ .logout-btn, .reset-btn {
102
+ background: #6B7280;
103
+ padding: 8px 16px;
104
+ font-size: 13px;
105
+ margin-top: 15px;
106
+ }
107
+
108
+ .logout-btn:hover, .reset-btn:hover {
109
+ background: #4B5563;
110
+ box-shadow: 0 4px 12px rgba(107, 114, 128, 0.3);
111
+ }
112
+
113
+ .auth-form input {
114
+ width: 100%;
115
+ margin-bottom: 15px;
116
+ }
117
+
118
+ .auth-form button {
119
+ width: 100%;
120
+ }
121
+
122
+ .switch-link {
123
+ color: #3D3D3D;
124
+ text-decoration: none;
125
+ cursor: pointer;
126
+ font-weight: 600;
127
+ margin-top: 15px;
128
+ display: inline-block;
129
+ transition: color 0.2s;
130
+ }
131
+
132
+ .switch-link:hover {
133
+ color: #1A1A1A;
134
+ text-decoration: underline;
135
+ }
136
+
137
+ .question-block {
138
+ background: #FAFAFA;
139
+ padding: 30px;
140
+ border-radius: 12px;
141
+ margin-bottom: 20px;
142
+ border: none;
143
+ display: none;
144
+ min-height: 400px;
145
+ }
146
+
147
+ .question-block.active {
148
+ display: block;
149
+ animation: fadeIn 0.3s ease;
150
+ }
151
+
152
+ @keyframes fadeIn {
153
+ from { opacity: 0; transform: translateX(20px); }
154
+ to { opacity: 1; transform: translateX(0); }
155
+ }
156
+
157
+ .question-block h4 {
158
+ color: #3D3D3D;
159
+ margin-bottom: 25px;
160
+ font-weight: 700;
161
+ font-size: 18px;
162
+ line-height: 1.6;
163
+ }
164
+
165
+ .question-number {
166
+ display: inline-block;
167
+ background: #3D3D3D;
168
+ color: #fff;
169
+ width: 32px;
170
+ height: 32px;
171
+ border-radius: 50%;
172
+ text-align: center;
173
+ line-height: 32px;
174
+ margin-right: 12px;
175
+ font-size: 16px;
176
+ }
177
+
178
+ .option {
179
+ display: block;
180
+ padding: 16px 20px;
181
+ margin-bottom: 12px;
182
+ background: white;
183
+ border: none;
184
+ border-radius: 10px;
185
+ cursor: pointer;
186
+ transition: all 0.2s;
187
+ font-size: 15px;
188
+ color: #3D3D3D;
189
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
190
+ }
191
+
192
+ .option:hover {
193
+ background: #F5F5F5;
194
+ transform: translateX(5px);
195
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
196
+ }
197
+
198
+ .option input[type="radio"] {
199
+ margin-right: 12px;
200
+ cursor: pointer;
201
+ width: 18px;
202
+ height: 18px;
203
+ }
204
+
205
+ .option input[type="radio"]:disabled {
206
+ cursor: not-allowed;
207
+ opacity: 0.5;
208
+ }
209
+
210
+ .option:has(input[type="radio"]:disabled) {
211
+ opacity: 0.4;
212
+ cursor: not-allowed;
213
+ }
214
+
215
+ .option:has(input[type="radio"]:disabled):hover {
216
+ background: white;
217
+ transform: none;
218
+ }
219
+
220
+ .question-counter {
221
+ text-align: center;
222
+ color: #999;
223
+ font-size: 14px;
224
+ margin-bottom: 15px;
225
+ font-weight: 600;
226
+ }
227
+
228
+ .submit-btn {
229
+ width: 100%;
230
+ padding: 16px;
231
+ font-size: 16px;
232
+ margin-top: 10px;
233
+ background: #3D3D3D;
234
+ color: #fff;
235
+ border: none;
236
+ border-radius: 10px;
237
+ font-weight: 600;
238
+ transition: background 0.2s;
239
+ }
240
+ .submit-btn:hover {
241
+ background: #1A1A1A;
242
+ color: #fff;
243
+ }
244
+
245
+ .result-card {
246
+ padding: 25px;
247
+ border-radius: 12px;
248
+ margin-bottom: 20px;
249
+ border: none;
250
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
251
+ }
252
+
253
+ .result-card.rank-1 {
254
+ background: #FFFACD;
255
+ }
256
+
257
+ .result-card.rank-2 {
258
+ background: #B4C7E7;
259
+ }
260
+
261
+ .result-card.rank-3 {
262
+ background: #90EE90;
263
+ }
264
+
265
+ .result-header {
266
+ display: flex;
267
+ align-items: center;
268
+ justify-content: space-between;
269
+ margin-bottom: 15px;
270
+ }
271
+
272
+ .result-rank {
273
+ color: #fff;
274
+ width: 40px;
275
+ height: 40px;
276
+ border-radius: 50%;
277
+ display: flex;
278
+ align-items: center;
279
+ justify-content: center;
280
+ font-size: 20px;
281
+ font-weight: 800;
282
+ background: #3D3D3D;
283
+ }
284
+
285
+ .result-title { flex: 1; margin-left: 15px; }
286
+ .result-title h3 {
287
+ font-size: 22px; margin-bottom: 5px; color: #3D3D3D;
288
+ }
289
+ .result-percentage {
290
+ font-size: 24px; font-weight: 800; color: #3D3D3D;
291
+ }
292
+ .result-description { color: #666; line-height: 1.6; margin-bottom: 12px; font-size: 14px; }
293
+ .result-details { background: rgba(255, 255, 255, 0.6); border: none; padding: 15px; border-radius: 8px; margin-top: 15px; }
294
+ .result-details h5 { color: #3D3D3D; font-size: 13px; margin-bottom: 8px; font-weight: 700; }
295
+ .result-details p { color: #666; font-size: 13px; margin-bottom: 10px; text-align: left; }
296
+ .icon { font-size: 24px; margin-right: 8px; }
297
+ .success-msg { color: #3D3D3D; font-weight: 600; }
298
+ .error-msg { color: #666; font-weight: 600; text-align: center; padding: 10px; }
299
+ .progress-bar { background: #F5F5F5; height: 8px; border-radius: 4px; overflow: hidden; margin-bottom: 20px; }
300
+ .progress-fill { background: #3D3D3D; height: 100%; transition: width 0.3s; }
301
+ .buttons-row { display: flex; gap: 10px; justify-content: center; margin-top: 20px; }
302
+ .nav-buttons { display: flex; gap: 12px; justify-content: space-between; margin-top: 20px; }
303
+ .nav-btn, .nav-btn.next {
304
+ padding: 12px 24px;
305
+ font-size: 15px;
306
+ background: #3D3D3D;
307
+ color: #fff;
308
+ border: none;
309
+ border-radius: 10px;
310
+ cursor: pointer;
311
+ transition: background 0.2s;
312
+ font-weight: 600;
313
+ }
314
+ .nav-btn:hover, .nav-btn.next:hover { background: #1A1A1A; color: #fff; transform: translateY(-1px); }
315
+ .nav-btn:disabled { opacity: 0.3; cursor: not-allowed; transform: none; }
316
+ h3 { text-align: center; color: #3D3D3D; }
317
+ .chat-toggle-btn {
318
+ background: rgba(255, 255, 255, 0.8);
319
+ color: #3D3D3D;
320
+ border: none;
321
+ padding: 10px 20px;
322
+ border-radius: 8px;
323
+ cursor: pointer;
324
+ font-size: 14px;
325
+ font-weight: 600;
326
+ margin-top: 15px;
327
+ width: 100%;
328
+ transition: background 0.2s, color 0.2s;
329
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
330
+ }
331
+ .chat-toggle-btn:hover { background: #3D3D3D; color: #fff; }
332
+ .chat-window {
333
+ display: none;
334
+ background: rgba(255, 255, 255, 0.9);
335
+ border: none;
336
+ border-radius: 10px;
337
+ margin-top: 15px;
338
+ overflow: hidden;
339
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
340
+ }
341
+ .chat-window.open { display: block; animation: slideDown 0.3s ease; }
342
+ @keyframes slideDown { from { opacity: 0; max-height: 0; } to { opacity: 1; max-height: 500px; } }
343
+ .chat-messages { height: 250px; overflow-y: auto; padding: 15px; background: transparent; }
344
+ .chat-message { margin-bottom: 12px; padding: 10px 14px; border-radius: 8px; max-width: 85%; line-height: 1.5; font-size: 14px; }
345
+ .chat-message.user {
346
+ background: #3D3D3D;
347
+ color: #fff;
348
+ margin-left: auto;
349
+ text-align: right;
350
+ }
351
+ .chat-message.bot {
352
+ background: white;
353
+ color: #3D3D3D;
354
+ border: none;
355
+ text-align: left;
356
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
357
+ }
358
+ .chat-message.bot ul { margin: 8px 0 0 0; padding-left: 20px; }
359
+ .chat-message.bot li { margin-bottom: 6px; line-height: 1.6; }
360
+ .chat-input-area { display: flex; gap: 8px; padding: 12px; background: transparent; border-top: none; }
361
+ .chat-input {
362
+ flex: 1;
363
+ padding: 10px 14px;
364
+ border: none;
365
+ background: white;
366
+ border-radius: 8px;
367
+ font-size: 14px;
368
+ outline: none;
369
+ color: #3D3D3D;
370
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
371
+ }
372
+ .chat-input:focus { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }
373
+ .chat-send-btn {
374
+ padding: 10px 20px;
375
+ background: #3D3D3D;
376
+ color: #fff;
377
+ border: none;
378
+ border-radius: 8px;
379
+ cursor: pointer;
380
+ font-weight: 600;
381
+ font-size: 14px;
382
+ transition: background 0.2s;
383
+ }
384
+ .chat-send-btn:hover { background: #1A1A1A; color: #fff; }
385
+ .chat-send-btn:disabled { background: #F5F5F5; color: #999; cursor: not-allowed; }
386
+ .chat-typing { color: #999; font-style: italic; font-size: 13px; padding: 10px 14px; }
387
+ </style>
388
+ </head>
389
+ <body>
390
+ <div class="container">
391
+ {% if not logged_in %}
392
+ <!-- Login/Signup Form -->
393
+ <h1><span class="icon">🌟</span>Spiritual Path Finder</h1>
394
+ <p>{{ 'Begin your journey of self-discovery' if is_signup else 'Welcome back, seeker!' }}</p>
395
+
396
+ <div class="auth-form">
397
+ <input type="text" id="authUsername" placeholder="Username">
398
+ <input type="password" id="authPassword" placeholder="Password">
399
+ <button onclick="authenticate()">{{ 'Sign Up' if is_signup else 'Sign In' }}</button>
400
+ <div id="result"></div>
401
+ <p class="switch-link" onclick="switchAuth()">
402
+ {{ 'Already have an account? Sign In' if is_signup else 'New here? Sign Up' }}
403
+ </p>
404
+ </div>
405
+
406
+ <script>
407
+ function authenticate() {
408
+ const username = document.getElementById('authUsername').value.trim();
409
+ const password = document.getElementById('authPassword').value;
410
+
411
+ if (!username || !password) {
412
+ document.getElementById('result').innerHTML =
413
+ '<p class="error-msg">⚠️ Please fill in all fields</p>';
414
+ return;
415
+ }
416
+
417
+ const endpoint = window.location.pathname === '/signup' ? '/signup' : '/login';
418
+
419
+ fetch(endpoint, {
420
+ method: 'POST',
421
+ headers: {'Content-Type': 'application/json'},
422
+ body: JSON.stringify({username, password})
423
+ })
424
+ .then(response => response.json())
425
+ .then(data => {
426
+ if (data.success) {
427
+ window.location.href = '/';
428
+ } else {
429
+ document.getElementById('result').innerHTML =
430
+ `<p class="error-msg">${data.message}</p>`;
431
+ }
432
+ });
433
+ }
434
+
435
+ function switchAuth() {
436
+ const newPath = window.location.pathname === '/signup' ? '/login' : '/signup';
437
+ window.location.href = newPath;
438
+ }
439
+
440
+ document.getElementById('authPassword').addEventListener('keypress', function(e) {
441
+ if (e.key === 'Enter') authenticate();
442
+ });
443
+ </script>
444
+ {% else %}
445
+ <!-- Assessment Interface -->
446
+ <h1>{{ title }}</h1>
447
+ <p>{{ message }}</p>
448
+
449
+ {% if not has_results %}
450
+ <p class="subtitle">
451
+ Discover which spiritual or religious path aligns with your beliefs, values, and lifestyle.
452
+ Answer 8 thoughtful questions about your worldview.
453
+ </p>
454
+
455
+ <div class="question-counter" id="questionCounter">Question 1 of {{ questions|length }}</div>
456
+
457
+ <div class="progress-bar">
458
+ <div class="progress-fill" id="progressBar" style="width: 0%"></div>
459
+ </div>
460
+
461
+ <div style="display:none;" id="assessmentData"
462
+ data-total="{{ questions|length }}"
463
+ data-ids="{{ questions|map(attribute='id')|list|tojson|safe }}">
464
+ </div>
465
+
466
+ <form id="assessmentForm">
467
+ {% for question in questions %}
468
+ {% set q_index = loop.index %}
469
+ <div class="question-block" data-question-index="{{ q_index }}" {% if loop.first %}data-active="true"{% endif %}>
470
+ <h4>
471
+ <span class="question-number">{{ q_index }}</span>
472
+ {{ question.question }}
473
+ </h4>
474
+ {% for option in question.options.keys() %}
475
+ <label class="option">
476
+ <input type="radio"
477
+ name="q{{ question.id }}"
478
+ value="{{ option }}"
479
+ data-question-index="{{ q_index }}"
480
+ onchange="handleAnswer(this)">
481
+ {{ option }}
482
+ </label>
483
+ {% endfor %}
484
+
485
+ <div class="nav-buttons" style="justify-content: flex-end;">
486
+ <button type="button" class="nav-btn next" id="nextBtn{{ q_index }}" onclick="goToNext()" disabled>
487
+ Next →
488
+ </button>
489
+ </div>
490
+ </div>
491
+ {% endfor %}
492
+
493
+ <button type="button" class="submit-btn" onclick="submitAssessment()" id="submitBtn" style="display: none;">
494
+ ✨ Discover Your Path
495
+ </button>
496
+ </form>
497
+
498
+ <div id="errorMsg"></div>
499
+ {% else %}
500
+ <!-- Results Display -->
501
+ <p class="subtitle">
502
+ Based on your responses, here are the spiritual paths that align most closely with your values and beliefs:
503
+ </p>
504
+
505
+ <div id="resultsContainer">
506
+ {% for result in results %}
507
+ <div class="result-card rank-{{ loop.index }}">
508
+ <div class="result-header">
509
+ <div class="result-rank">{{ loop.index }}</div>
510
+ <div class="result-title">
511
+ <h3>{{ result.name }}</h3>
512
+ </div>
513
+ <div class="result-percentage">{{ result.percentage }}%</div>
514
+ </div>
515
+ <p class="result-description">{{ result.description }}</p>
516
+ <div class="result-details">
517
+ <h5>📿 Common Practices:</h5>
518
+ <p>{{ result.practices }}</p>
519
+ <h5>💭 Core Beliefs:</h5>
520
+ <p>{{ result.core_beliefs }}</p>
521
+ </div>
522
+
523
+ <button class="chat-toggle-btn" onclick="toggleChat('{{ result.name }}')">
524
+ 💬 Ask Questions About {{ result.name }}
525
+ </button>
526
+
527
+ <div class="chat-window" id="chat-{{ result.name|replace(' ', '-') }}">
528
+ <div class="chat-messages" id="messages-{{ result.name|replace(' ', '-') }}">
529
+ <div class="chat-message bot">
530
+ Hi! Ask me anything about {{ result.name }}.<br>
531
+ <span style="color:#7C3AED; font-size:13px;">
532
+ Example: "What are the daily practices?"<br>
533
+ Example: "How do I get started with this path?"
534
+ </span>
535
+ </div>
536
+ </div>
537
+ <div class="chat-input-area">
538
+ <input type="text"
539
+ class="chat-input"
540
+ id="input-{{ result.name|replace(' ', '-') }}"
541
+ placeholder="Ask about {{ result.name }}..."
542
+ onkeypress="if(event.key==='Enter') sendMessage('{{ result.name }}')">
543
+ <button class="chat-send-btn"
544
+ id="send-{{ result.name|replace(' ', '-') }}"
545
+ onclick="sendMessage('{{ result.name }}')">
546
+ Send
547
+ </button>
548
+ </div>
549
+ </div>
550
+ </div>
551
+ {% endfor %}
552
+ </div>
553
+
554
+ <div class="buttons-row">
555
+ <button class="btn reset-btn" onclick="resetAssessment()">🔄 Retake Assessment</button>
556
+ </div>
557
+ {% endif %}
558
+
559
+ <div style="text-align: center;">
560
+ <a href="/logout" class="btn logout-btn">Logout</a>
561
+ </div>
562
+
563
+ <script>
564
+ var currentQuestion = 1;
565
+ var maxQuestionReached = 1; // Track the furthest question reached
566
+ var assessmentDataEl = document.getElementById('assessmentData');
567
+ var totalQuestions = assessmentDataEl ? parseInt(assessmentDataEl.getAttribute('data-total')) : 0;
568
+ var questionIds = assessmentDataEl ? JSON.parse(assessmentDataEl.getAttribute('data-ids')) : [];
569
+
570
+ // Show first question on load
571
+ window.addEventListener('DOMContentLoaded', function() {
572
+ showQuestion(1);
573
+ });
574
+
575
+ function showQuestion(questionIndex) {
576
+ if (questionIndex > maxQuestionReached + 1) return;
577
+ if (questionIndex > maxQuestionReached) maxQuestionReached = questionIndex;
578
+
579
+ document.querySelectorAll('.question-block').forEach(function(block) {
580
+ block.classList.remove('active');
581
+ var blockIndex = parseInt(block.getAttribute('data-question-index'));
582
+ if (blockIndex === questionIndex) block.classList.add('active');
583
+ if (blockIndex < questionIndex) {
584
+ block.querySelectorAll('input[type="radio"]').forEach(function(radio) { radio.disabled = true; });
585
+ }
586
+ });
587
+
588
+ currentQuestion = questionIndex;
589
+ document.getElementById('questionCounter').textContent = 'Question ' + questionIndex + ' of ' + totalQuestions;
590
+ document.getElementById('progressBar').style.width = ((questionIndex - 1) / totalQuestions) * 100 + '%';
591
+ updateNavigationButtons();
592
+ }
593
+
594
+ function updateNavigationButtons() {
595
+ var nextBtn = document.getElementById('nextBtn' + currentQuestion);
596
+
597
+ if (nextBtn) {
598
+ var currentQuestionId = questionIds[currentQuestion - 1];
599
+ var radioName = 'q' + currentQuestionId;
600
+ var isAnswered = document.querySelector('input[name="' + radioName + '"]:checked') !== null;
601
+
602
+ if (currentQuestion === totalQuestions && isAnswered) {
603
+ nextBtn.style.display = 'none';
604
+ document.getElementById('submitBtn').style.display = 'block';
605
+ } else {
606
+ nextBtn.disabled = !isAnswered;
607
+ nextBtn.style.display = 'inline-block';
608
+ }
609
+ }
610
+ }
611
+
612
+ function handleAnswer(radioElement) {
613
+ var questionIndex = parseInt(radioElement.getAttribute('data-question-index'));
614
+
615
+ // Only process if this is the current question
616
+ if (questionIndex !== currentQuestion) {
617
+ return;
618
+ }
619
+
620
+ updateNavigationButtons();
621
+
622
+ // Auto-advance to next question after selection
623
+ setTimeout(function() {
624
+ if (questionIndex < totalQuestions) {
625
+ showQuestion(questionIndex + 1);
626
+ } else {
627
+ // Last question - show submit button
628
+ var nextBtn = document.getElementById('nextBtn' + questionIndex);
629
+ if (nextBtn) {
630
+ nextBtn.style.display = 'none';
631
+ }
632
+ document.getElementById('submitBtn').style.display = 'block';
633
+ }
634
+ }, 400);
635
+ }
636
+
637
+ function goToNext() {
638
+ if (currentQuestion < totalQuestions) {
639
+ showQuestion(currentQuestion + 1);
640
+ }
641
+ }
642
+
643
+ function submitAssessment() {
644
+ var form = document.getElementById('assessmentForm');
645
+ var answers = [];
646
+
647
+ questionIds.forEach(function(qId) {
648
+ var radioName = 'q' + qId;
649
+ var selectedRadio = form.querySelector('input[name="' + radioName + '"]:checked');
650
+ if (selectedRadio) {
651
+ answers.push({
652
+ question_id: qId,
653
+ answer: selectedRadio.value
654
+ });
655
+ }
656
+ });
657
+
658
+ if (answers.length !== totalQuestions) {
659
+ document.getElementById('errorMsg').innerHTML =
660
+ '<p class="error-msg">⚠️ Please answer all questions</p>';
661
+ return;
662
+ }
663
+
664
+ document.getElementById('submitBtn').disabled = true;
665
+ document.getElementById('submitBtn').textContent = '✨ Calculating...';
666
+
667
+ fetch('/submit_assessment', {
668
+ method: 'POST',
669
+ headers: {'Content-Type': 'application/json'},
670
+ body: JSON.stringify({answers: answers})
671
+ })
672
+ .then(function(response) { return response.json(); })
673
+ .then(function(data) {
674
+ if (data.success) {
675
+ window.location.reload();
676
+ } else {
677
+ document.getElementById('errorMsg').innerHTML =
678
+ '<p class="error-msg">' + data.message + '</p>';
679
+ document.getElementById('submitBtn').disabled = false;
680
+ document.getElementById('submitBtn').textContent = '✨ Discover Your Path';
681
+ }
682
+ });
683
+ }
684
+
685
+ function resetAssessment() {
686
+ if (!confirm('Are you sure you want to retake the assessment? Your current results will be cleared.')) {
687
+ return;
688
+ }
689
+
690
+ fetch('/reset_assessment', {
691
+ method: 'POST',
692
+ headers: {'Content-Type': 'application/json'}
693
+ })
694
+ .then(function(response) { return response.json(); })
695
+ .then(function(data) {
696
+ if (data.success) {
697
+ window.location.reload();
698
+ }
699
+ });
700
+ }
701
+
702
+ // Chat functionality
703
+ var chatHistories = {};
704
+
705
+ function formatBotResponse(text) {
706
+ var div = document.createElement('div');
707
+ div.textContent = text;
708
+ var escaped = div.innerHTML;
709
+
710
+ if (escaped.match(/\*\s+/g) || escaped.match(/•\s+/g) || escaped.match(/^\s*-\s+/gm)) {
711
+ var lines = escaped.split(/(?:\*|•|\n-)\s+/);
712
+ if (lines.length > 1) {
713
+ var formatted = lines[0].trim() ? lines[0].trim() + '<br><br>' : '';
714
+ formatted += '<ul style="margin: 0; padding-left: 20px; line-height: 1.8;">';
715
+ for (var i = 1; i < lines.length; i++) {
716
+ if (lines[i].trim()) formatted += '<li style="margin-bottom: 6px;">' + lines[i].trim() + '</li>';
717
+ }
718
+ return formatted + '</ul>';
719
+ }
720
+ }
721
+ return escaped.replace(/\n/g, '<br>');
722
+ }
723
+
724
+ function toggleChat(religionName) {
725
+ var chatId = 'chat-' + religionName.replace(/\s+/g, '-');
726
+ var chatWindow = document.getElementById(chatId);
727
+
728
+ if (chatWindow.classList.contains('open')) {
729
+ chatWindow.classList.remove('open');
730
+ } else {
731
+ chatWindow.classList.add('open');
732
+ var inputId = 'input-' + religionName.replace(/\s+/g, '-');
733
+ setTimeout(function() {
734
+ document.getElementById(inputId).focus();
735
+ }, 300);
736
+ }
737
+ }
738
+
739
+ function sendMessage(religionName) {
740
+ var inputId = 'input-' + religionName.replace(/\s+/g, '-');
741
+ var messagesId = 'messages-' + religionName.replace(/\s+/g, '-');
742
+ var sendBtnId = 'send-' + religionName.replace(/\s+/g, '-');
743
+
744
+ var inputEl = document.getElementById(inputId);
745
+ var messagesEl = document.getElementById(messagesId);
746
+ var sendBtn = document.getElementById(sendBtnId);
747
+
748
+ var message = inputEl.value.trim();
749
+ if (!message) return;
750
+
751
+ // Initialize chat history if not exists
752
+ if (!chatHistories[religionName]) {
753
+ chatHistories[religionName] = [];
754
+ }
755
+
756
+ // Add user message to UI
757
+ var userMsgDiv = document.createElement('div');
758
+ userMsgDiv.className = 'chat-message user';
759
+ userMsgDiv.textContent = message;
760
+ messagesEl.appendChild(userMsgDiv);
761
+
762
+ // Clear input and disable send button
763
+ inputEl.value = '';
764
+ sendBtn.disabled = true;
765
+
766
+ // Show typing indicator
767
+ var typingDiv = document.createElement('div');
768
+ typingDiv.className = 'chat-typing';
769
+ typingDiv.textContent = '💭 Thinking...';
770
+ messagesEl.appendChild(typingDiv);
771
+
772
+ // Scroll to bottom
773
+ messagesEl.scrollTop = messagesEl.scrollHeight;
774
+
775
+ // Add to chat history
776
+ chatHistories[religionName].push({
777
+ role: 'user',
778
+ content: message
779
+ });
780
+
781
+ // Send to backend
782
+ fetch('/chat', {
783
+ method: 'POST',
784
+ headers: {'Content-Type': 'application/json'},
785
+ body: JSON.stringify({
786
+ message: message,
787
+ religion: religionName,
788
+ history: chatHistories[religionName]
789
+ })
790
+ })
791
+ .then(function(response) { return response.json(); })
792
+ .then(function(data) {
793
+ messagesEl.removeChild(typingDiv);
794
+
795
+ if (data.success) {
796
+ var botMsgDiv = document.createElement('div');
797
+ botMsgDiv.className = 'chat-message bot';
798
+
799
+ // Format the response with proper bullet points
800
+ var formattedResponse = formatBotResponse(data.response);
801
+ botMsgDiv.innerHTML = formattedResponse;
802
+
803
+ messagesEl.appendChild(botMsgDiv);
804
+
805
+ chatHistories[religionName].push({
806
+ role: 'assistant',
807
+ content: data.response
808
+ });
809
+ } else {
810
+ var errorMsgDiv = document.createElement('div');
811
+ errorMsgDiv.className = 'chat-message bot';
812
+ errorMsgDiv.style.color = '#EF4444';
813
+ errorMsgDiv.textContent = '❌ ' + data.message;
814
+ messagesEl.appendChild(errorMsgDiv);
815
+ }
816
+
817
+ sendBtn.disabled = false;
818
+ messagesEl.scrollTop = messagesEl.scrollHeight;
819
+ })
820
+ .catch(function(error) {
821
+ messagesEl.removeChild(typingDiv);
822
+
823
+ var errorMsgDiv = document.createElement('div');
824
+ errorMsgDiv.className = 'chat-message bot';
825
+ errorMsgDiv.style.color = '#EF4444';
826
+ errorMsgDiv.textContent = '❌ Connection error';
827
+ messagesEl.appendChild(errorMsgDiv);
828
+
829
+ sendBtn.disabled = false;
830
+ messagesEl.scrollTop = messagesEl.scrollHeight;
831
+ });
832
+ }
833
+ </script>
834
+ {% endif %}
835
+ </div>
836
+ </body>
837
+ </html>