import streamlit as st import folium from streamlit_folium import folium_static from datetime import datetime import gspread from google.oauth2.service_account import Credentials import os import json import random # تنظیمات اولیه st.set_page_config( layout="wide", # حالت گسترده برای همه دستگاهها page_title="راهیار - تحلیل انصاف قیمتی", page_icon="🚖", initial_sidebar_state="auto" # تنظیم خودکار وضعیت نوار کناری ) # ========== تنظیمات دیتا ========== SHEET_ID = "1mmdWAyOCYq4yXMgP53Duq712AnlqZWLkfIo76JqM7wM" SHEET_NAME = "Condition1" # ========== استایلهای سفارشی ========== st.markdown(""" """, unsafe_allow_html=True) # ========== توابع اصلی ========== def create_ride_map(): start_point = [35.7698, 51.4116] # میدان ونک end_point = [35.8044, 51.4258] # میدان تجریش m = folium.Map(location=[35.7871, 51.4187], zoom_start=13) # اضافه کردن مبدأ و مقصد folium.Marker(start_point, popup="مبدأ: میدان ونک", icon=folium.Icon(color="green")).add_to(m) folium.Marker(end_point, popup="مقصد: میدان تجریش", icon=folium.Icon(color="red")).add_to(m) # خط مسیر folium.PolyLine([start_point, end_point], color="#6a0dad", weight=3).add_to(m) # تنظیمات واکنشگرا برای نقشه m.get_root().width = "100%" m.get_root().height = "100%" m.get_root().add_child(folium.Element(""" """)) return m def show_explanation(exp_type): """نمایش توضیحات قیمت""" explanations = { "input": [ "سطح تقاضا در منطقه: زیاد", "تعداد رانندگان فعال: کم", "زمان روز: ساعت اوج ترافیک", "شرایط جوی: هوای بارانی" ], "counterfactual": [ "اگر این سفر را ۳۰ دقیقه زودتر یا دیرتر درخواست میکردید، قیمت ۱۵٪ کمتر میشد", "اگر تعداد رانندگان فعال دو برابر بود، قیمتگذاری نوسانی اعمال نمیشد" ] } if exp_type != "control": st.markdown("
علت قیمت گذاری:
", unsafe_allow_html=True) for item in explanations.get(exp_type, []): st.markdown(f"• {item}
", unsafe_allow_html=True) # ========== توابع مدیریت دادهها ========== def get_credentials(): """دریافت اعتبارنامه از Secrets""" try: service_account_json = os.environ.get('GCP_SERVICE_ACCOUNT') if not service_account_json: st.error("مقدار GCP_SERVICE_ACCOUNT در محیط یافت نشد") return None service_account_info = json.loads(service_account_json) creds = Credentials.from_service_account_info( service_account_info, scopes=[ "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive.file" ] ) return creds except Exception as e: st.error(f"خطا در دریافت اعتبارنامه: {str(e)}") return None def save_to_sheet(data): try: creds = get_credentials() if not creds: return False client = gspread.authorize(creds) spreadsheet = client.open_by_key(SHEET_ID) worksheet = spreadsheet.worksheet(SHEET_NAME) row_data = [ datetime.now().strftime("%Y-%m-%d %H:%M:%S"), data.get("scenario_type"), data.get("price"), data.get("age"), data.get("gender"), data.get("education"), data.get("ride_frequency"), *data.get("transparency_answers", []), *data.get("fairness_answers", []) ] worksheet.append_row(row_data) return True except Exception as e: st.error(f"خطا در ذخیرهسازی: {str(e)}") return False # ========== بخشهای فرم ========== def welcome_page(): """صفحه خوشامدگویی""" st.markdown("""این تحقیق به بررسی تأثیر توضیحات قیمت بر ادراک انصاف میپردازد
این پرسشنامه بخشی از یک پژوهش علمی است که به بررسی ادراک انصاف در قیمتگذاری پویا میپردازد.
پس از مشاهده سناریو، لطفاً به سوالات پاسخ دهید.
سفرهای درون شهری سریع و مطمئن
شما قصد دارید سفری را از مبدأ میدان ونک به مقصد میدان تجریش درخواست کنید.
قیمت پیشنهادی این سفر 200,000 تومان است.
شما قصد دارید سفری را از مبدأ میدان ونک به مقصد میدان تجریش درخواست کنید.
قیمت پیشنهادی این سفر 200,000 تومان است.
پلتفرم توضیحاتی درباره علت این قیمت ارائه میدهد.
سفرهای درون شهری سریع و مطمئن
{question}
", unsafe_allow_html=True) cols = st.columns(5) options = { 1: "کاملاً مخالفم", 2: "مخالفم", 3: "نظری ندارم", 4: "موافقم", 5: "کاملاً موافقم" } selected = st.session_state.get(key, None) for value, label in options.items(): with cols[value-1]: if st.button( label, key=f"{key}_{value}", on_click=lambda v=value: st.session_state.update({key: v}), type="primary" if selected == value else "secondary" ): pass if selected: st.markdown(f"پاسخ شما: {options[selected]}
", unsafe_allow_html=True) return selected def transparency_questions(): """سوالات شفافیت""" st.header("📊 پرسشنامه شفافیت قیمت") st.markdown("**لطفاً میزان موافقت خود با جملات زیر را مشخص کنید:**") questions = [ "پلتفرم به صورت صادقانه دلایل تغییر قیمت (مثل افزایش تقاضا یا شرایط جوی) را توضیح داد.", "پلتفرم به طور کامل عوامل مؤثر بر قیمت (مثل ترافیک، تعداد رانندگان) را شرح داد.", "دلایل ارائهشده برای تغییر قیمت منطقی و قابل قبول بود.", "توضیحات درباره قیمت بلافاصله و در زمان مناسب نمایش داده شد.", "توضیحات پلتفرم متناسب با شرایط سفر من (مثل مسیر یا ساعت درخواست) بود." ] answers = [] for i, question in enumerate(questions): answer = create_likert_question(question, f"transparency_q{i}") answers.append(answer) if None not in answers: st.session_state.transparency_answers = answers if st.button("ادامه به سوالات بعدی", type="primary"): st.session_state.current_page = "fairness_questions" st.rerun() def fairness_questions(): """سوالات انصاف""" st.header("📊 پرسشنامه ادراک انصاف") st.markdown("**لطفاً میزان موافقت خود با جملات زیر را مشخص کنید:**") questions = [ "قیمتی که به شما ارائه شد، منصفانه است.", "قیمتی که به شما ارائه شد، معقول است.", "قیمتی که به شما ارائه شد، قابل قبول است.", "فرآیند و رویه قیمتگذاری پلتفرم قابل قبول است.", "فرآیند و رویه قیمتگذاری پلتفرم منصفانه است.", "فرآیند و رویه قیمتگذاری پلتفرم معقول است." ] answers = [] for i, question in enumerate(questions): answer = create_likert_question(question, f"fairness_q{i}") answers.append(answer) if None not in answers: st.session_state.fairness_answers = answers if st.button("ارسال پاسخها", type="primary"): all_data = { "scenario_type": st.session_state.scenario_type, "price": st.session_state.price, **st.session_state.demographic_data, "transparency_answers": st.session_state.transparency_answers, "fairness_answers": st.session_state.fairness_answers } if save_to_sheet(all_data): st.session_state.current_page = "thank_you" st.rerun() def thank_you_page(): """صفحه تشکر""" st.success("✅ پاسخهای شما با موفقیت ثبت شد. با تشکر از مشارکت شما در این تحقیق!") st.balloons() if st.button("بازگشت به ابتدا"): st.session_state.clear() st.rerun() # ========== مدیریت وضعیت و صفحهبندی ========== def main(): if 'current_page' not in st.session_state: st.session_state.current_page = "welcome" st.session_state.scenario_type = random.choice(["control", "input", "counterfactual"]) st.session_state.price = 200000 # قیمت ثابت 200 هزار تومان st.session_state.demographic_data = None st.session_state.transparency_answers = [] st.session_state.fairness_answers = [] # نمایش صفحه فعلی pages = { "welcome": welcome_page, "demographic": demographic_form, "scenario_explanation": scenario_explanation, "map_view": map_view, "transparency_questions": transparency_questions, "fairness_questions": fairness_questions, "thank_you": thank_you_page } pages[st.session_state.current_page]() if __name__ == "__main__": main()