GSMEthesis commited on
Commit
212261d
·
verified ·
1 Parent(s): 2ec192d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -61
app.py CHANGED
@@ -736,55 +736,103 @@ h3 {
736
  }
737
  </style>
738
  """, unsafe_allow_html=True)
 
 
739
  def custom_likert_slider(question_data):
740
- """نمایش سوال لیکرت با اسلایدر ساده و ذخیرهسازی مستقیم"""
741
  question = question_data["question"]
742
  key = question_data["key"]
743
  points = question_data["scale"]
744
  labels = question_data.get("labels", ["کمترین", "بیشترین"])
745
 
746
- # مقدار پیش‌فرض
747
- default_value = st.session_state.get(key, (points + 1) // 2)
 
748
 
749
- # نمایش سوال
750
- st.markdown(f"<p style='font-size:16px; font-weight:bold; text-align:right;'>{question}</p>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
751
 
752
- # اسلایدر معکوس
753
- raw_value = st.slider(
754
- "",
755
- min_value=1,
756
- max_value=points,
757
- value=default_value,
758
- step=1,
759
- key=f"slider_{key}",
760
- label_visibility="hidden"
761
- )
 
762
 
763
- # معکوس کردن مقدار
764
- value = points + 1 - raw_value
765
 
766
- # ذخیره مقدار
767
- st.session_state[key] = value
768
- if 'answers' not in st.session_state:
769
- st.session_state.answers = {}
770
- st.session_state.answers[key] = value
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771
 
772
- # نمایش لیبل‌ها
773
- st.markdown(
774
- f"""
775
- <div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 5px;">
776
- <span>{labels[1]}</span>
777
- <span>{labels[0]}</span>
778
- </div>
779
- <p style='text-align:center; direction:rtl;'>
780
- پاسخ انتخاب‌شده: <strong>{value}</strong>
781
- </p>
782
- """,
783
- unsafe_allow_html=True
784
- )
785
 
786
- return value
787
-
788
  def create_ride_map():
789
  """ایجاد نقشه سفر با Folium - نسخه اصلاح شده با مناطق عمومی"""
790
  # نقاط تقریبی برای مناطق عمومی جنوب و غرب تهران
@@ -1194,7 +1242,8 @@ def attention_check1():
1194
  st.warning("لطفاً یک گزینه را انتخاب کنید")
1195
 
1196
  def random_likert_questions():
1197
- """نمایش سوالات لیکرت به ترتیب مشخص"""
 
1198
  question_groups = [
1199
  {
1200
  "title": "عدالت توزیعی",
@@ -1204,7 +1253,7 @@ def random_likert_questions():
1204
  "key": "distributive_1",
1205
  "question": "قیمتی که به شما ارائه شد، چگونه بود؟",
1206
  "scale": 7,
1207
- "labels": ["کاملاً نامنصفانه", "کاملاً منصفانه"]
1208
  },
1209
  {
1210
  "key": "distributive_2",
@@ -1224,7 +1273,7 @@ def random_likert_questions():
1224
  "title": "سوال توجه",
1225
  "key": "attention_check",
1226
  "questions": [
1227
- {"key": "attention_check2", "question": "تا چه مقدار با دقت به سوالات پاسخ می‌دهید؟", "scale": 7, "labels": ["خیلی کم", "خیلی زیاد"]}
1228
  ]
1229
  },
1230
  {
@@ -1249,6 +1298,7 @@ def random_likert_questions():
1249
  }
1250
  ]
1251
 
 
1252
  # مقداردهی اولیه
1253
  if 'current_likert_group' not in st.session_state:
1254
  st.session_state.current_likert_group = 0
@@ -1256,30 +1306,48 @@ def random_likert_questions():
1256
  # دریافت گروه جاری
1257
  current_group = question_groups[st.session_state.current_likert_group]
1258
 
1259
- # نمایش راهنمای پاسخ
1260
  st.markdown("""
1261
- <div style="background-color: #f8f9fa; padding: 15px; border-radius: 10px; margin-bottom: 20px;">
1262
- <h4>راهنمای پاسخ:</h4>
1263
- <p>لطفاً برای هر سوال با حرکت دادن اسلایدر، میزان موافقت خود را مشخص کنید.</p>
1264
- <p>مقادیر از چپ به راست: کاملاً مخالفم ← کاملاً موافقم</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1265
  </div>
1266
  """, unsafe_allow_html=True)
1267
 
1268
- # نمایش تمام سوالات گروه جاری
1269
  for question in current_group['questions']:
1270
  answer = custom_likert_slider(question)
 
 
1271
 
1272
  # دکمه ادامه/اتمام
1273
- col1, col2 = st.columns([1, 2])
1274
- with col2:
1275
- button_label = "ادامه به گروه بعدی" if st.session_state.current_likert_group < len(question_groups)-1 else "اتمام پرسشنامه"
1276
- if st.button(button_label, use_container_width=True):
1277
- if st.session_state.current_likert_group < len(question_groups) - 1:
1278
- st.session_state.current_likert_group += 1
1279
- else:
1280
- st.session_state.current_page = "explanation_questions"
1281
  st.rerun()
1282
-
 
 
 
1283
  def explanation_questions():
1284
  """نمایش سوالات تکمیلی به صورت مرحله‌ای با دکمه ادامه"""
1285
  st.markdown("### 📋 سوالات تکمیلی")
@@ -1369,7 +1437,7 @@ def explanation_questions():
1369
 
1370
  # رفرش صفحه برای نمایش سوال بعدی
1371
  st.rerun()
1372
-
1373
  def demographic_form():
1374
  """فرم اطلاعات دموگرافیک"""
1375
  st.markdown("### 📝 اطلاعات دموگرافیک")
@@ -1477,7 +1545,11 @@ def main():
1477
  user_agent = st.query_params.get("user_agent", [""])[0]
1478
  st.session_state.is_desktop = "mobile" not in user_agent.lower()
1479
 
1480
- # مقداردهی اولیه session_state
 
 
 
 
1481
  if 'answers' not in st.session_state:
1482
  st.session_state.answers = {}
1483
 
@@ -1490,7 +1562,6 @@ def main():
1490
  st.session_state.price_accepted = 0
1491
  st.session_state.attention_check1 = None
1492
 
1493
- # تعریف صفحات
1494
  pages = {
1495
  "welcome": welcome_page,
1496
  "scenario_explanation": scenario_explanation,
@@ -1498,12 +1569,11 @@ def main():
1498
  "attention_check1": attention_check1,
1499
  "random_likert_questions": random_likert_questions,
1500
  "explanation_questions": explanation_questions,
1501
- "demographic": demographic_form,
1502
- "contact": user_contact,
1503
  "thank_you": thank_you_page
1504
  }
1505
 
1506
- # نمایش صفحه جاری
1507
  pages[st.session_state.current_page]()
1508
 
1509
  if __name__ == "__main__":
 
736
  }
737
  </style>
738
  """, unsafe_allow_html=True)
739
+
740
+ # ========== توابع اصلی ==========
741
  def custom_likert_slider(question_data):
742
+ """نمایش سوال لیکرت با اسلایدر نقطه‌ای و لیبلهای سفارشی"""
743
  question = question_data["question"]
744
  key = question_data["key"]
745
  points = question_data["scale"]
746
  labels = question_data.get("labels", ["کمترین", "بیشترین"])
747
 
748
+ # مقدار پیش‌فرض (وسط طیف)
749
+ default_value = (points + 1) // 2
750
+ current_value = st.session_state.get(key, default_value)
751
 
752
+ # HTML و JavaScript برای اسلایدر
753
+ html = f"""
754
+ <div id="container_{key}" style="direction: ltr; font-family: 'B Nazanin'; margin-bottom: 30px;">
755
+ <label style="font-size: 16px; font-weight: bold; display: block; text-align: right;">{question}</label>
756
+ <div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 5px;">
757
+ <span>{labels[0]}</span>
758
+ <span>{labels[1]}</span>
759
+ </div>
760
+ <input type="range" id="{key}" min="1" max="{points}" step="1" value="{current_value}"
761
+ style="width: 100%; height: 10px; accent-color: #6a0dad; margin-bottom: 15px;"
762
+ oninput="updateSlider('{key}')"
763
+ onchange="updateSlider('{key}')">
764
+ <div style="text-align: center; margin-top: 10px; direction: rtl;">
765
+ پاسخ انتخاب‌شده: <strong><span id="output_{key}">{current_value}</span></strong>
766
+ </div>
767
+ </div>
768
+
769
+ <script>
770
+ function updateSlider(key) {{
771
+ const slider = document.getElementById(key);
772
+ const value = parseInt(slider.value);
773
+ document.getElementById('output_' + key).innerText = value;
774
+
775
+ // ذخیره مقدار در یک متغیر مخفی برای دسترسی Streamlit
776
+ window.sliderValues = window.sliderValues || {{}};
777
+ window.sliderValues[key] = value;
778
+
779
+ // ارسال مقدار به Streamlit
780
+ try {{
781
+ window.parent.postMessage({{
782
+ type: 'streamlit:setComponentValue',
783
+ key: key,
784
+ value: value
785
+ }}, '*');
786
+ }} catch (e) {{
787
+ console.error('Error sending message to Streamlit:', e);
788
+ }}
789
+
790
+ // ذخیره مقدار در localStorage برای اطمینان
791
+ localStorage.setItem(key, value);
792
+ }}
793
 
794
+ // بازیابی مقدار اولیه از localStorage اگر وجود داشته باشد
795
+ window.addEventListener('load', () => {{
796
+ const key = '{key}';
797
+ const savedValue = localStorage.getItem(key);
798
+ if (savedValue) {{
799
+ document.getElementById(key).value = savedValue;
800
+ document.getElementById('output_' + key).innerText = savedValue;
801
+ }}
802
+ });
803
+ </script>
804
+ """
805
 
806
+ # رندر کامپوننت HTML
807
+ components.html(html, height=150)
808
 
809
+ # خواندن مقدار از localStorage یا session_state
810
+ if key in st.session_state:
811
+ current_value = st.session_state[key]
812
+ else:
813
+ # تلاش برای خواندن از localStorage از طریق JavaScript
814
+ st.markdown(
815
+ f"""
816
+ <script>
817
+ const savedValue = localStorage.getItem('{key}');
818
+ if (savedValue) {{
819
+ window.parent.postMessage({{
820
+ type: 'streamlit:setComponentValue',
821
+ key: '{key}',
822
+ value: parseInt(savedValue)
823
+ }}, '*');
824
+ }}
825
+ </script>
826
+ """,
827
+ unsafe_allow_html=True
828
+ )
829
+ current_value = st.session_state.get(key, default_value)
830
 
831
+ # برای دیباگ: نمایش مقدار فعلی
832
+ st.write(f"مقدار فعلی برای {key}: {current_value}")
833
+
834
+ return current_value
 
 
 
 
 
 
 
 
 
835
 
 
 
836
  def create_ride_map():
837
  """ایجاد نقشه سفر با Folium - نسخه اصلاح شده با مناطق عمومی"""
838
  # نقاط تقریبی برای مناطق عمومی جنوب و غرب تهران
 
1242
  st.warning("لطفاً یک گزینه را انتخاب کنید")
1243
 
1244
  def random_likert_questions():
1245
+ """نمایش سوالات لیکرت به ترتیب مشخص با اسلایدر سفارشی"""
1246
+ # تعریف گروه‌های سوالات با لیبل‌های سفارشی
1247
  question_groups = [
1248
  {
1249
  "title": "عدالت توزیعی",
 
1253
  "key": "distributive_1",
1254
  "question": "قیمتی که به شما ارائه شد، چگونه بود؟",
1255
  "scale": 7,
1256
+ "labels": ["کاملاً نامنصفانه", "کاملاً منصفانه"] # لیبل‌های سفارشی برای این سوال
1257
  },
1258
  {
1259
  "key": "distributive_2",
 
1273
  "title": "سوال توجه",
1274
  "key": "attention_check",
1275
  "questions": [
1276
+ {"key": "attention_check2", "question": "تا چه مقدار با دقت به سوالات پاسخ می‌دهید؟", "scale": 7,"labels": ["خیلی کم", "خیلی زیاد"]}
1277
  ]
1278
  },
1279
  {
 
1298
  }
1299
  ]
1300
 
1301
+
1302
  # مقداردهی اولیه
1303
  if 'current_likert_group' not in st.session_state:
1304
  st.session_state.current_likert_group = 0
 
1306
  # دریافت گروه جاری
1307
  current_group = question_groups[st.session_state.current_likert_group]
1308
 
1309
+ # نمایش عنوان گروه
1310
  st.markdown("""
1311
+ <style>
1312
+ .guide-text p {
1313
+ font-size: 14px !important;
1314
+ }
1315
+ </style>
1316
+ """, unsafe_allow_html=True)
1317
+ st.markdown("""
1318
+ <div class="guide-text" style="display: flex; flex-direction: column; align-items: center; background-color: #f0f2f6; border-radius: 10px; padding: 20px; gap: 15px;">
1319
+ <div style="flex: 1;">
1320
+ <h3>راهنمای پاسخ:</h3>
1321
+ <p>برای پاسخ به سوالات، با یک طیف کشویی مواجه خواهید شد.</p>
1322
+ <p>در این طیف 7 نقطه وجود دارد:
1323
+ <br>- سمت چپ: کمترین مقدار
1324
+ <br>- سمت راست: بیشترین مقدار
1325
+ </p>
1326
+ <p>نقطه روی کشو را جابجا کنید و در مقداری که پاسخ شماست متوقف شوید.</p>
1327
+ <p>پاسخ شما زیر طیف نمایش داده خواهد شد.</p>
1328
+ <p>اگر از پاسخ‌هایتان مطمئن هستید، روی دکمه «ادامه» کلیک کنید.</p>
1329
+ </div>
1330
  </div>
1331
  """, unsafe_allow_html=True)
1332
 
1333
+ # نمایش تمام سوالات این گروه در یک صفحه
1334
  for question in current_group['questions']:
1335
  answer = custom_likert_slider(question)
1336
+ st.session_state.answers[question["key"]] = answer
1337
+
1338
 
1339
  # دکمه ادامه/اتمام
1340
+ button_label = "ادامه به گروه بعد��" if st.session_state.current_likert_group < len(question_groups)-1 else "اتمام پرسشنامه"
1341
+
1342
+ if st.button(button_label):
1343
+ # رفتن به گروه بعدی یا صفحه پایانی
1344
+ if st.session_state.current_likert_group < len(question_groups) - 1:
1345
+ st.session_state.current_likert_group += 1
 
 
1346
  st.rerun()
1347
+ else:
1348
+ st.session_state.current_page = "explanation_questions"
1349
+ st.rerun()
1350
+
1351
  def explanation_questions():
1352
  """نمایش سوالات تکمیلی به صورت مرحله‌ای با دکمه ادامه"""
1353
  st.markdown("### 📋 سوالات تکمیلی")
 
1437
 
1438
  # رفرش صفحه برای نمایش سوال بعدی
1439
  st.rerun()
1440
+
1441
  def demographic_form():
1442
  """فرم اطلاعات دموگرافیک"""
1443
  st.markdown("### 📝 اطلاعات دموگرافیک")
 
1545
  user_agent = st.query_params.get("user_agent", [""])[0]
1546
  st.session_state.is_desktop = "mobile" not in user_agent.lower()
1547
 
1548
+
1549
+ if st.session_state.is_desktop:
1550
+ # اطمینان از نمایش همان حالت موبایل برای همه دستگاه‌ها
1551
+ st.session_state.is_desktop = False
1552
+
1553
  if 'answers' not in st.session_state:
1554
  st.session_state.answers = {}
1555
 
 
1562
  st.session_state.price_accepted = 0
1563
  st.session_state.attention_check1 = None
1564
 
 
1565
  pages = {
1566
  "welcome": welcome_page,
1567
  "scenario_explanation": scenario_explanation,
 
1569
  "attention_check1": attention_check1,
1570
  "random_likert_questions": random_likert_questions,
1571
  "explanation_questions": explanation_questions,
1572
+ "demographic": demographic_form, # دموگرافیک قبل از کانتکت
1573
+ "contact": user_contact, # کانتکت در انتها
1574
  "thank_you": thank_you_page
1575
  }
1576
 
 
1577
  pages[st.session_state.current_page]()
1578
 
1579
  if __name__ == "__main__":