Maryam Ilka commited on
Commit
6baf2ce
·
verified ·
1 Parent(s): dd0d02b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -508
app.py CHANGED
@@ -17,249 +17,17 @@ SHEET_ID = "1mmdWAyOCYq4yXMgP53Duq712AnlqZWLkfIo76JqM7wM"
17
  SHEET_NAME = "Condition1"
18
 
19
  # ========== استایل‌های سفارشی یکپارچه ==========
20
- st.markdown("""
21
- <style>
22
- @font-face {
23
- font-family: 'Vazir';
24
- src: url('https://cdn.jsdelivr.net/gh/rastikerdar/vazir-font@v30.1.0/dist/Vazir.woff') format('woff');
25
- }
26
-
27
- :root {
28
- --primary: #6a0dad;
29
- --text: #333333;
30
- --background: #ffffff;
31
- --border: #dddddd;
32
- --input-bg: #ffffff;
33
- --secondary-bg: #f8f9fa;
34
- --green: #f0ff0;
35
- }
36
-
37
- * {
38
- font-family: 'Vazir', sans-serif !important;
39
- text-align: right !important;
40
- direction: rtl !important;
41
- }
42
-
43
- /* تنظیمات اصلی */
44
- body, .stApp, [data-testid="stAppViewContainer"] {
45
- background-color: var(--background) !important;
46
- color: var(--text) !important;
47
- }
48
-
49
- /* هدر راهیار */
50
- .rahyar-title {
51
- color: var(--primary) !important;
52
- margin: 0 !important;
53
- }
54
-
55
- .rahyar-subtitle {
56
- color: var(--primary) !important;
57
- margin: 0 !important;
58
- font-size: 14px !important;
59
- }
60
-
61
- /* باکس‌های ورودی */
62
- .stTextInput input,
63
- .stNumberInput input,
64
- .stSelectbox select,
65
- .stTextArea textarea,
66
- .stDateInput input,
67
- .stTimeInput input,
68
- .stMultiSelect div[role="combobox"],
69
- div[data-testid="stVerticalBlock"] > div[data-testid="stHorizontalBlock"] > div > div > div > div > input,
70
- /* لیست dropdown */
71
- .st-bq, .st-br, .st-bs, .st-bt, .st-bu, .st-bv, .st-bw, .st-bx, .st-by, .st-bz {
72
- color: var(--text) !important;
73
- background-color: var(--input-bg) !important;
74
- }
75
-
76
- /* استایل برای متن بالای باکس‌های دموگرافیک */
77
- .stTextInput > label,
78
- .stNumberInput > label,
79
- .stSelectbox > label,
80
- .stRadio > label,
81
- .stSlider > label {
82
- color: black !important;
83
- font-weight: bold !important;
84
- }
85
-
86
- /* Placeholder */
87
- ::placeholder {
88
- color: var(--text) !important;
89
- opacity: 0.7 !important;
90
- }
91
-
92
- /* دکمه اصلی (بنفش با متن سفید) */
93
- .stButton>button,
94
- [data-testid="baseButton-primary"],
95
- .accept-btn,
96
- div[data-testid="stVerticalBlock"] > div[data-testid="stHorizontalBlock"] > div > div > button {
97
- background-color: var(--primary) !important;
98
- color: white !important;
99
- border: none !important;
100
- border-radius: 8px !important;
101
- padding: 10px 20px !important;
102
- font-weight: bold !important;
103
- }
104
-
105
- /* دکمه ثانویه (سفید با حاشیه بنفش) */
106
- .stFormSubmitButton>button,
107
- [data-testid="baseButton-secondary"],
108
- .reject-btn {
109
- background-color: var(--primary) !important;
110
- color: var(--input-bg) !important;
111
- border: 1px solid var(--primary) !important;
112
- border-radius: 8px !important;
113
- padding: 10px 20px !important;
114
- font-weight: bold !important;
115
- }
116
-
117
-
118
- /* کامپوننت‌های سفارشی */
119
- .rahyar-header {
120
- background-color: var(--primary) !important;
121
- color: white !important;
122
- padding: 15px !important;
123
- border-radius: 10px !important;
124
- margin-bottom: 20px !important;
125
- text-align: center !important;
126
- }
127
-
128
- .price-container {
129
- background-color: var(--secondary-bg) !important;
130
- border-radius: 10px !important;
131
- padding: 15px !important;
132
- margin: 15px 0 !important;
133
- border-right: 5px solid var(--primary) !important;
134
- }
135
-
136
- .rahyar-price {
137
- color: var(--primary) !important;
138
- font-size: 28px !important;
139
- font-weight: bold !important;
140
- }
141
-
142
- /* فرم دموگرافیک */
143
- .stSelectbox > div > div {
144
- background-color: white !important;
145
- color: var(--text) !important;
146
- }
147
-
148
- .stSelectbox option {
149
- background-color: white !important;
150
- color: var(--text) !important;
151
- }
152
-
153
- /* توضیحات */
154
- .explanation-title {
155
- color: var(--primary) !important;
156
- font-weight: bold !important;
157
- margin: 20px 0 10px 0 !important;
158
- font-size: 18px !important;
159
- }
160
-
161
- .explanation-item {
162
- background-color: var(--secondary-bg) !important;
163
- border-radius: 8px !important;
164
- padding: 12px 15px !important;
165
- margin: 8px 0 !important;
166
- border-right: 3px solid var(--primary) !important;
167
- }
168
-
169
- /* استایل برای سوالات رادیویی و گزینه‌ها */
170
- .stRadio > label,
171
- .stRadio > div > label,
172
- .stRadio > div > div > label,
173
- .stRadio > div > div > div > label,
174
- .stRadio span {
175
- color: black !important;
176
- }
177
-
178
- /* استایل برای متن سوالات */
179
- .stMarkdown h3,
180
- .stMarkdown p {
181
- color: black !important;
182
- }
183
-
184
- /* استایل برای دکمه ثبت */
185
- .stButton > button {
186
- color: white !important;
187
- }
188
-
189
- /* پیام موفقیت */
190
- .stAlert .stSuccess {
191
- color: var(--text) !important;
192
- background-color: #f0fff0 !important;
193
- }
194
-
195
-
196
- /* تنظیمات مخصوص دسکتاپ */
197
- @media (min-width: 769px) {
198
- .folium-map {
199
- height: 500px !important;
200
- }
201
- }
202
-
203
- /* تنظیمات مخصوص موبایل */
204
- @media (max-width: 768px) {
205
- .folium-map {
206
- height: 300px !important;
207
- }
208
-
209
- .stSelectbox > div > div {
210
- padding: 8px !important;
211
- }
212
- }
213
- </style>
214
- """, unsafe_allow_html=True)
215
 
216
  # ========== توابع اصلی ==========
217
  def create_ride_map():
218
  """ایجاد نقشه سفر با Folium"""
219
- start_point = [35.7698, 51.4116] # میدان ونک
220
- end_point = [35.8044, 51.4258] # میدان تجریش
221
-
222
- m = folium.Map(location=[35.7871, 51.4187], zoom_start=13)
223
-
224
- folium.Marker(
225
- start_point,
226
- popup="<b>مبدأ:</b> میدان ونک",
227
- icon=folium.Icon(color="green", icon="flag", prefix="fa")
228
- ).add_to(m)
229
-
230
- folium.Marker(
231
- end_point,
232
- popup="<b>مقصد:</b> میدان تجریش",
233
- icon=folium.Icon(color="red", icon="flag", prefix="fa")
234
- ).add_to(m)
235
-
236
- folium.PolyLine(
237
- [start_point, end_point],
238
- color="#6a0dad",
239
- weight=3,
240
- opacity=1
241
- ).add_to(m)
242
-
243
- return m
244
 
245
  def show_explanation(exp_type):
246
  """نمایش توضیحات قیمت"""
247
- explanations = {
248
- "input": [
249
- "سطح تقاضا در منطقه: زیاد",
250
- "تعداد رانندگان فعال: کم",
251
- "زمان روز: ساعت اوج ترافیک",
252
- "شرایط جوی: هوای بارانی"
253
- ],
254
- "counterfactual": [
255
- "اگر این سفر را ۳۰ دقیقه دیرتر درخواست می‌کردید، به دلیل سطح تقاضای کمتر، رانندگان فعال بیش‌تر، زمان بهتر روز و شرایط جوی بهتر، ممکن بود قیمت ۱۵٪ کمتر باشد.",
256
- ]
257
- }
258
-
259
- if exp_type != "control":
260
- st.markdown("<p class='explanation-title'>علت قیمت گذاری:</p>", unsafe_allow_html=True)
261
- for item in explanations.get(exp_type, []):
262
- st.markdown(f"<p class='explanation-item'>• {item}</p>", unsafe_allow_html=True)
263
 
264
  def create_likert_question(question, key, scale_type="5point"):
265
  """سوال لیکرت با دکمه‌ها"""
@@ -306,24 +74,7 @@ def create_likert_question(question, key, scale_type="5point"):
306
  # ========== توابع مدیریت داده‌ها ==========
307
  def get_credentials():
308
  """دریافت اعتبارنامه از Secrets"""
309
- try:
310
- service_account_json = os.environ.get('GCP_SERVICE_ACCOUNT')
311
- if not service_account_json:
312
- st.error("مقدار GCP_SERVICE_ACCOUNT در محیط یافت نشد")
313
- return None
314
-
315
- service_account_info = json.loads(service_account_json)
316
- creds = Credentials.from_service_account_info(
317
- service_account_info,
318
- scopes=[
319
- "https://www.googleapis.com/auth/spreadsheets",
320
- "https://www.googleapis.com/auth/drive.file"
321
- ]
322
- )
323
- return creds
324
- except Exception as e:
325
- st.error(f"خطا در دریافت اعتبارنامه: {str(e)}")
326
- return None
327
 
328
  def save_to_sheet(data):
329
  try:
@@ -385,198 +136,46 @@ def save_to_sheet(data):
385
  return False
386
 
387
  # ========== بخش‌های فرم ==========
388
-
389
- def welcome_page():
390
- """صفحه خوشامدگویی"""
391
- st.markdown("""
392
- <div style="text-align: center; margin-bottom: 30px;">
393
- <h2> 🚖 قیمت‌گذاری در پلتفرم‌های درخواست تاکسی اینترنتی</h2>
394
- <p>👋با سلام و درود</p>
395
- <p>پیشاپیش بابت زمانی که برای پاسخ به سوالات این پرسشنامه و پیش‌برد اهداف علمی دانشجویان می‌گذارید، متشکرم.</p>
396
- <p>جهت تقدیر از شرکت‌کنندگان، به دو نفر به قید قرعه جایزه 5 میلیون ریالی تقدیم خواهد شد.</p>
397
- </div>
398
-
399
- <div style="display: flex; align-items: center; background-color: #f0f2f6; border-radius: 10px; padding: 20px; gap: 20px;">
400
- <div style="flex: 0 0 100px;">
401
- <img src="https://huggingface.co/spaces/maryamilka/surge-pricing/resolve/main/shariflogo.png" alt="لوگو دانشگاه شریف" style="width: 100%; max-width: 100px;">
402
- </div>
403
- <div style="flex: 1;">
404
- <h3>درباره تحقیق:</h3>
405
- <p>این پرسشنامه بخشی از یک پایان‌نامه کارشناسی ارشد در دانشگاه صنعتی شریف است که به بررسی ادراک انصاف در قیمت‌گذاری در پلتفرم‌های درخواست تاکسی اینترنتی می‌پردازد.</p>
406
- <p>پاسخ‌های شما به سوالات کاملاً محرمانه خواهد بود و فقط در جهت اهداف علمی استفاده خواهد شذ.</p>
407
- <p>جهت شروع روی دکمه زیر کلیک کنید 👇🏻</p>
408
- </div>
409
- </div>
410
- """, unsafe_allow_html=True)
411
-
412
- if st.button("شروع پرسشنامه", key="start_btn", type="primary"):
413
- st.session_state.current_page = "contact"
414
- st.session_state.start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
415
- st.rerun()
416
-
417
-
418
- def user_contact():
419
- """راه ارتباطی ساده"""
420
- st.markdown("""
421
- <div style="text-align: center; margin-bottom: 30px;">
422
- <h3>📩 راه ارتباطی شما (اختیاری)</h3>
423
- <p>در صورت تمایل به شرکت در قرعه‌کشی می‌توانید آیدی تلگرام، شماره تماس یا ایمیل خود را وارد کنید:</p>
424
- </div>
425
- """, unsafe_allow_html=True)
426
-
427
- contact_info = st.text_input(
428
- "راه ارتباطی (اختیاری)",
429
- placeholder="مثال: @username یا 09123456789 یا example@email.com",
430
- key="user_contact_input"
431
- )
432
-
433
- if st.button("ادامه", key="continue_btn", type="primary"):
434
- st.session_state.user_contact = contact_info
435
- st.session_state.current_page = "demographic"
436
- st.rerun()
437
-
438
- def demographic_form():
439
- """فرم اطلاعات دموگرافیک"""
440
- st.markdown("### 📝 اطلاعات دموگرافیک")
441
-
442
- with st.form("demographic_form"):
443
- age = st.number_input("سن", min_value=18, max_value=100)
444
- gender = st.selectbox("جنسیت", ["مرد", "زن", "سایر"])
445
- education = st.selectbox("تحصیلات", ["دیپلم", "لیسانس", "فوق لیسانس", "دکترا"])
446
- ride_frequency = st.selectbox("دفعات استفاده از سرویس‌های اشتراک سفر در ماه",
447
- ["کمتر از 5 بار", "5-10 بار", "بیش از 10 بار"])
448
-
449
- if st.form_submit_button("ادامه"):
450
- st.session_state.demographic_data = {
451
- "age": age,
452
- "gender": gender,
453
- "education": education,
454
- "ride_frequency": ride_frequency
455
- }
456
- st.session_state.current_page = "scenario_explanation"
457
- st.rerun()
458
-
459
- def scenario_explanation():
460
- """توضیح سناریو"""
461
- col1, col2 = st.columns([1, 4])
462
- with col1:
463
- try:
464
- st.image("rahyar.png", width=80)
465
- except:
466
- st.image("https://via.placeholder.com/80/6a0dad/FFFFFF?text=LOGO", width=80)
467
- with col2:
468
- st.markdown("""
469
- <h2 class="rahyar-title">رهیار 🚖</h2>
470
- <p class="rahyar-subtitle">همراه سفرهای درون‌شهری شما، راهی مطمئن، راهی روشن، رهیار</p>
471
- """, unsafe_allow_html=True)
472
-
473
- st.markdown("### سناریوی تحقیق")
474
-
475
- st.markdown("""
476
- <div style="background-color: #f8f9fa; padding: 15px; border-radius: 10px;">
477
- <p>فرض کنید یک اپلیکیشن حمل‌ونقل آنلاین ایرانی به اسم رهیار طراحی شده، چیزی شبیه اسنپ یا تپسی، اما جدیدتر و با شعار "همراه سفرهای شما، راهی مطمئن، راهی روشن، رهیار"</p>
478
- <p>در یک روز عادی، شما قصد دارید برای سفری از طریق این پلتفرم اقدام کنید..</p>
479
- <p>با کلیک بر دکمه ادامه، اطلاعات سفر را مشاهده کنید.</p>
480
- </div>
481
- """, unsafe_allow_html=True)
482
-
483
- if st.button("ادامه", key="continue_btn", type="primary"):
484
- st.session_state.current_page = "map_view"
485
- st.rerun()
486
-
487
- def map_view():
488
- """نمایش نقشه و قیمت"""
489
- col1, col2 = st.columns([1, 4])
490
- with col1:
491
- st.image("https://via.placeholder.com/80/6a0dad/FFFFFF?text=LOGO", width=80)
492
- with col2:
493
- st.markdown("""
494
- <h2 style="color: #6a0dad; margin: 0;">رهیار 🚖</h2>
495
- <p style="color: #6a0dad; margin: 0;">همراه سفرهای درون‌شهری شما، راهی مطمئن، راهی روشن، رهیار</p>
496
- """, unsafe_allow_html=True)
497
-
498
- st.markdown("### مسیر سفر شما")
499
- folium_static(create_ride_map(), width=1000 if st.session_state.is_desktop else 800,
500
- height=500 if st.session_state.is_desktop else 400)
501
-
502
- # قیمت
503
- st.markdown(f"""
504
- <div class="price-container">
505
- <div style="display: flex; justify-content: space-between; align-items: center;">
506
- <span>راهیار <span style="background-color: #e6e6fa; color: #6a0dad; padding: 2px 8px; border-radius: 12px; font-size: 14px;">به صرفه</span></span>
507
- <span class="rahyar-price">{st.session_state.price:,} تومان</span>
508
- </div>
509
- </div>
510
- """, unsafe_allow_html=True)
511
-
512
- show_explanation(st.session_state.scenario_type)
513
-
514
- # دکمه‌ها
515
- col1, col2 = st.columns(2)
516
- with col1:
517
- if st.button("درخواست راهیار", key="accept_btn", use_container_width=True):
518
- st.session_state.price_accepted = 1
519
- st.session_state.current_page = "attention_check1"
520
- st.rerun()
521
-
522
- with col2:
523
- if st.button("رد قیمت", key="reject_btn", use_container_width=True):
524
- st.session_state.price_accepted = 0
525
- st.session_state.current_page = "attention_check1"
526
- st.rerun()
527
 
528
  def attention_check1():
529
- """سوال توجه اول"""
530
  st.markdown("### سوال توجه")
531
 
532
- options = {
533
- 1: "قرمز",
534
- 2: "سبز",
535
- 3: "بنفش",
536
- 4: "آبی",
537
- 5: "زرد"
538
- }
539
-
540
- answer = create_likert_question(
541
  "رنگ سازمانی اپلیکیشن رهیار چه رنگی بود؟",
542
- "attention_check1",
543
- "5point"
 
544
  )
545
 
546
  if answer:
547
- if answer == 3: # پاسخ صحیح (بنفش)
548
  st.session_state.current_page = "random_likert_questions"
549
  st.rerun()
550
  else:
551
  st.error("پاسخ صحیح نبود. لطفاً دقت بیشتری به خرج دهید.")
552
- time.sleep(2) # تاخیر برای خواندن پیام
553
  st.rerun()
554
 
555
  def attention_check2():
556
- """سوال توجه دوم"""
557
  st.markdown("### سوال توجه")
558
 
559
- options = {
560
- 1: "اسنپ",
561
- 2: "تپسی",
562
- 3: "راهیار",
563
- 4: "ماکسیم",
564
- 5: "دیگر"
565
- }
566
-
567
- answer = create_likert_question(
568
  "نام اپلیکیشنی که در این تحقیق بررسی می‌شود چیست؟",
569
- "attention_check2",
570
- "5point"
 
571
  )
572
 
573
  if answer:
574
- if answer == 3: # پاسخ صحیح (راهیار)
575
  st.session_state.current_page = "explanation_questions"
576
  st.rerun()
577
  else:
578
  st.error("پاسخ صحیح نبود. لطفاً دقت بیشتری به خرج دهید.")
579
- time.sleep(2) # تاخیر برای خواندن پیام
580
  st.rerun()
581
 
582
  def random_likert_questions():
@@ -609,101 +208,18 @@ def random_likert_questions():
609
  if st.session_state.current_question_index < len(st.session_state.all_questions):
610
  q = st.session_state.all_questions[st.session_state.current_question_index]
611
 
612
- st.markdown(f"### سوال {st.session_state.current_question_index + 1} از {len(st.session_state.all_questions)}")
613
  answer = create_likert_question(q["question"], q["key"], q["scale"])
614
 
615
  if answer:
616
  st.session_state.current_question_index += 1
617
- time.sleep(0.5) # تاخیر کوتاه برای UX بهتر
618
  st.rerun()
619
  else:
620
  st.session_state.current_page = "attention_check2"
621
  st.rerun()
622
 
623
- def explanation_questions():
624
- """سوالات درباره توضیحات قیمت"""
625
- st.markdown("""
626
- <style>
627
- /* تضمین رنگ متن برای تمام سطوح */
628
- .st-ec, .st-ed, .st-ee, .st-ef, .st-eg, .st-eh, .st-ei, .st-ej {
629
- color: black !important;
630
- }
631
- </style>
632
- """, unsafe_allow_html=True)
633
- st.markdown("### 📋 سوالات تکمیلی")
634
-
635
- # سوال اول
636
- explanation_received = st.radio(
637
- "آیا برای قیمت پیشنهادی این سفر، توضیحی به شما ارائه شد؟",
638
- ["بله", "خیر"],
639
- index=None,
640
- key="explanation_received"
641
- )
642
-
643
- # سوال دوم (فقط اگر پاسخ بله باشد)
644
- explanation_type = None
645
- if explanation_received == "بله":
646
- explanation_type = st.radio(
647
- "اگر توضیحی دریافت کردید، ای�� توضیح بیشتر به کدام مورد شباهت داشت؟",
648
- [
649
- "بر اساس عواملی که در قیمت‌گذاری لحاظ شده‌اند",
650
- "شامل سناریوهای جایگزین که می‌توانستند قیمت متفاوتی ایجاد کنند",
651
- "توضیحی دریافت نکردم"
652
- ],
653
- index=None,
654
- key="explanation_type"
655
- )
656
-
657
- if st.button("ثبت پاسخ‌ها", type="primary"):
658
- if explanation_received is None:
659
- st.warning("لطفاً به سوال اول پاسخ دهید")
660
- elif explanation_received == "بله" and explanation_type is None:
661
- st.warning("لطفاً به سوال دوم پاسخ دهید")
662
- else:
663
- st.session_state.explanation_data = {
664
- "explanation_received": explanation_received,
665
- "explanation_type": explanation_type if explanation_received == "بله" else "N/A"
666
- }
667
-
668
- # جمع‌آوری تمام داده‌ها برای ذخیره‌سازی
669
- end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
670
- start_time = datetime.strptime(st.session_state.start_time, "%Y-%m-%d %H:%M:%S")
671
- completion_time = (datetime.now() - start_time).total_seconds()
672
-
673
- save_data = {
674
- "start_time": st.session_state.start_time,
675
- "end_time": end_time,
676
- "completion_time": completion_time,
677
- "scenario_type": st.session_state.scenario_type,
678
- "price": st.session_state.price,
679
- "user_contact": st.session_state.get("user_contact", ""),
680
- "price_accepted": st.session_state.get("price_accepted", 0),
681
- "attention_check1": st.session_state.get("attention_check1", None),
682
- "attention_check2": st.session_state.get("attention_check2", None),
683
- "explanation_received": explanation_received,
684
- "explanation_type": explanation_type if explanation_received == "بله" else "N/A",
685
- **st.session_state.demographic_data
686
- }
687
-
688
- # اضافه کردن پاسخ‌های لیکرت
689
- for q in st.session_state.all_questions:
690
- save_data[q["label"]] = st.session_state.get(q["key"], None)
691
-
692
- if save_to_sheet(save_data):
693
- st.session_state.current_page = "thank_you"
694
- st.rerun()
695
- else:
696
- st.error("خطا در ذخیره‌سازی داده‌ها. لطفاً دوباره تلاش کنید.")
697
-
698
-
699
- def thank_you_page():
700
- """صفحه تشکر"""
701
- st.success("✅ پاسخ‌های شما با موفقیت ثبت شد. با تشکر از مشارکت شما در این تحقیق!")
702
- st.balloons()
703
-
704
- if st.button("بازگشت به ابتدا"):
705
- st.session_state.clear()
706
- st.rerun()
707
 
708
  # ========== مدیریت وضعیت و صفحه‌بندی ==========
709
  def main():
@@ -726,8 +242,8 @@ def main():
726
  "scenario_explanation": scenario_explanation,
727
  "map_view": map_view,
728
  "attention_check1": attention_check1,
729
- "attention_check2": attention_check2,
730
  "random_likert_questions": random_likert_questions,
 
731
  "explanation_questions": explanation_questions,
732
  "thank_you": thank_you_page
733
  }
 
17
  SHEET_NAME = "Condition1"
18
 
19
  # ========== استایل‌های سفارشی یکپارچه ==========
20
+ # (استایل‌ها مانند قبل باقی می‌مانند)
21
+ # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  # ========== توابع اصلی ==========
24
  def create_ride_map():
25
  """ایجاد نقشه سفر با Folium"""
26
+ # د مانند قبل)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  def show_explanation(exp_type):
29
  """نمایش توضیحات قیمت"""
30
+ # (کد مانند قبل)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  def create_likert_question(question, key, scale_type="5point"):
33
  """سوال لیکرت با دکمه‌ها"""
 
74
  # ========== توابع مدیریت داده‌ها ==========
75
  def get_credentials():
76
  """دریافت اعتبارنامه از Secrets"""
77
+ # (کد مانند قبل)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
  def save_to_sheet(data):
80
  try:
 
136
  return False
137
 
138
  # ========== بخش‌های فرم ==========
139
+ # (صفحات welcome, contact, demographic, scenario_explanation, map_view مانند قبل)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
  def attention_check1():
142
+ """سوال توجه اول (رادیویی ساده)"""
143
  st.markdown("### سوال توجه")
144
 
145
+ answer = st.radio(
 
 
 
 
 
 
 
 
146
  "رنگ سازمانی اپلیکیشن رهیار چه رنگی بود؟",
147
+ ["قرمز", "سبز", "بنفش", "آبی", "زرد"],
148
+ index=None,
149
+ key="attention_check1"
150
  )
151
 
152
  if answer:
153
+ if answer == "بنفش":
154
  st.session_state.current_page = "random_likert_questions"
155
  st.rerun()
156
  else:
157
  st.error("پاسخ صحیح نبود. لطفاً دقت بیشتری به خرج دهید.")
158
+ time.sleep(2)
159
  st.rerun()
160
 
161
  def attention_check2():
162
+ """سوال توجه دوم (رادیویی ساده)"""
163
  st.markdown("### سوال توجه")
164
 
165
+ answer = st.radio(
 
 
 
 
 
 
 
 
166
  "نام اپلیکیشنی که در این تحقیق بررسی می‌شود چیست؟",
167
+ ["اسنپ", "تپسی", "راهیار", "ماکسیم", "دیگر"],
168
+ index=None,
169
+ key="attention_check2"
170
  )
171
 
172
  if answer:
173
+ if answer == "راهیار":
174
  st.session_state.current_page = "explanation_questions"
175
  st.rerun()
176
  else:
177
  st.error("پاسخ صحیح نبود. لطفاً دقت بیشتری به خرج دهید.")
178
+ time.sleep(2)
179
  st.rerun()
180
 
181
  def random_likert_questions():
 
208
  if st.session_state.current_question_index < len(st.session_state.all_questions):
209
  q = st.session_state.all_questions[st.session_state.current_question_index]
210
 
211
+ # نمایش سوال بدون شماره
212
  answer = create_likert_question(q["question"], q["key"], q["scale"])
213
 
214
  if answer:
215
  st.session_state.current_question_index += 1
216
+ time.sleep(0.5)
217
  st.rerun()
218
  else:
219
  st.session_state.current_page = "attention_check2"
220
  st.rerun()
221
 
222
+ # (صفحات explanation_questions و thank_you مانند قبل)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
  # ========== مدیریت وضعیت و صفحه‌بندی ==========
225
  def main():
 
242
  "scenario_explanation": scenario_explanation,
243
  "map_view": map_view,
244
  "attention_check1": attention_check1,
 
245
  "random_likert_questions": random_likert_questions,
246
+ "attention_check2": attention_check2,
247
  "explanation_questions": explanation_questions,
248
  "thank_you": thank_you_page
249
  }