Maryam Ilka commited on
Commit
a5344e7
·
verified ·
1 Parent(s): e3051c2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +180 -106
app.py CHANGED
@@ -1,4 +1,6 @@
1
  import streamlit as st
 
 
2
  import random
3
  from datetime import datetime
4
  import gspread
@@ -7,94 +9,97 @@ import os
7
  import json
8
 
9
  # تنظیمات اولیه
10
- st.set_page_config(layout="wide")
11
-
12
- # ========== بخش سناریوها ==========
13
- SCENARIOS = {
14
- "control": {
15
- "title": "سناریوی کنترل (بدون توضیح)",
16
- "description": "شما قصد دارید سفری را از مبدأ X به مقصد Y درخواست کنید. قیمت پیشنهادی این سفر طبق تصمیم هوش مصنوعی ۱۰۰ هزار تومان است."
17
- },
18
- "input_based": {
19
- "title": "سناریوی مبتنی بر ورودی",
20
- "description": """شما قصد دارید سفری را از مبدأ X به مقصد Y درخواست کنید. قیمت پیشنهادی این سفر طبق تصمیم هوش مصنوعی ۱۰۰ هزار تومان است.
21
-
22
- سازمان این توضیحات را به شما ارائه می‌دهد:
23
- این قیمت بر اساس چند عامل تعیین شده است:
24
- • سطح تقاضا در منطقه: زیاد (+)
25
- • تعداد رانندگان فعال: کم (+)
26
- • زمان روز: ساعت اوج ترافیک (+)
27
- • شرایط جوی: هوای بارانی(++)
28
-
29
- به این دلیل، قیمت این سفر بالاتر از حد معمول است."""
30
- },
31
- "counterfactual": {
32
- "title": "سناریوی پادواقعی",
33
- "description": """شما قصد دارید سفری را از مبدأ X به مقصد Y درخواست کنید. قیمت پیشنهادی این سفر طبق تصمیم هوش مصنوعی ۱۰۰ هزار تومان است.
34
-
35
- سازمان این توضیحات را به شما ارائه می‌دهد:
36
- اگر این سفر را ۳۰ دقیقه زودتر یا دیرتر درخواست می‌کردید، به دلیل سطح تقاضای کمتر، رانندگان فعال بیش‌تر، زمان بهتر روز و شرایط جوی بهتر، ممکن بود قیمت ۱۵٪ کمتر باشد.
37
- اگر تعداد رانندگان فعال در منطقه شما دو برابر بود، قیمت‌گذاری نوسانی اعمال نمی‌شد."""
38
- }
39
- }
40
-
41
- # ========== بخش نقشه ==========
42
- def show_map():
43
- # می‌توانید از folium یا تصاویر استاتیک استفاده کنید
44
- st.image("map_placeholder.png", caption="مسیر سفر از X به Y")
45
-
46
- # ========== بخش جمع‌آوری داده‌ها ==========
47
- def get_demographic_data():
48
- with st.form("demographic_form"):
49
- st.header("اطلاعات دموگرافیک")
50
- age = st.number_input("سن", min_value=18, max_value=100)
51
- gender = st.selectbox("جنسیت", ["مرد", "زن", "سایر"])
52
- education = st.selectbox("تحصیلات", ["دیپلم", "لیسانس", "فوق لیسانس", "دکترا"])
53
- ride_frequency = st.selectbox("دفعات استفاده از سرویس‌های اشتراک سفر در ماه", ["کمتر از 5 بار", "5-10 بار", "بیش از 10 بار"])
54
-
55
- if st.form_submit_button("ذخیره اطلاعات دموگرافیک"):
56
- return {
57
- "age": age,
58
- "gender": gender,
59
- "education": education,
60
- "ride_frequency": ride_frequency
61
- }
62
- return None
63
-
64
- # ========== پرسشنامه عدالت قیمتی ==========
65
- def fairness_questionnaire():
66
- st.header("پرسشنامه ادراک انصاف قیمتی")
67
-
68
- fairness = st.slider("به نظر شما این قیمت چقدر منصفانه است؟ (1 کاملاً ناعادلانه - 7 کاملاً عادلانه)", 1, 7)
69
- transparency = st.slider("چقدر توضیحات ارائه شده در مورد قیمت را شفاف می‌دانید؟ (1 کاملاً نامشخص - 7 کاملاً شفاف)", 1, 7)
70
- satisfaction = st.slider("چقدر از این قیمت‌گذاری راضی هستید؟ (1 کاملاً ناراضی - 7 کاملاً راضی)", 1, 7)
71
-
72
- return {
73
- "fairness": fairness,
74
- "transparency": transparency,
75
- "satisfaction": satisfaction
76
- }
77
-
78
 
79
  # ========== تنظیمات دیتا ==========
80
  SHEET_ID = "1mmdWAyOCYq4yXMgP53Duq712AnlqZWLkfIo76JqM7wM"
81
  SHEET_NAME = "Condition1"
82
 
83
- # ========== توابع ==========
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  def get_credentials():
85
  """دریافت اعتبارنامه از Secrets"""
86
  try:
87
- # دریافت اطلاعات از secrets Hugging Face
88
  service_account_json = os.environ.get('GCP_SERVICE_ACCOUNT')
89
-
90
  if not service_account_json:
91
  st.error("مقدار GCP_SERVICE_ACCOUNT در محیط یافت نشد")
92
  return None
93
 
94
- # تبدیل رشته JSON به دیکشنری
95
  service_account_info = json.loads(service_account_json)
96
-
97
- # ایجاد اعتبارنامه
98
  creds = Credentials.from_service_account_info(
99
  service_account_info,
100
  scopes=[
@@ -106,13 +111,6 @@ def get_credentials():
106
  except Exception as e:
107
  st.error(f"خطا در دریافت اعتبارنامه: {str(e)}")
108
  return None
109
-
110
-
111
-
112
-
113
-
114
-
115
- # ========== ذخیره در Google Sheets ==========
116
 
117
  def save_to_sheet(data):
118
  try:
@@ -126,7 +124,8 @@ def save_to_sheet(data):
126
 
127
  row_data = [
128
  datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
129
- data.get("scenario"),
 
130
  data.get("age"),
131
  data.get("gender"),
132
  data.get("education"),
@@ -143,36 +142,111 @@ def save_to_sheet(data):
143
  st.error(f"خطا در ذخیره‌سازی: {str(e)}")
144
  return False
145
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
-
148
-
149
- # ========== اجرای اصلی برنامه ==========
150
- def main():
151
- if 'current_scenario' not in st.session_state:
152
- st.session_state.current_scenario = random.choice(list(SCENARIOS.keys()))
153
-
154
- scenario = SCENARIOS[st.session_state.current_scenario]
155
 
156
- st.title(scenario["title"])
157
- show_map()
158
- st.markdown(scenario["description"])
159
 
160
- demographic_data = get_demographic_data()
 
 
161
 
162
- if demographic_data:
163
- fairness_data = fairness_questionnaire()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
- if st.button("ارسال پاسخ‌ها"):
166
- all_data = {
167
- "scenario": st.session_state.current_scenario,
168
- **demographic_data,
169
- **fairness_data
170
- }
 
 
 
 
 
 
 
 
 
171
 
172
- if save_to_sheet(all_data):
173
- st.success("پاسخ‌های شما با موفقیت ثبت شد. با تشکر از مشارکت شما!")
174
- st.session_state.clear()
175
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
  if __name__ == "__main__":
178
  main()
 
1
  import streamlit as st
2
+ import folium
3
+ from streamlit_folium import folium_static
4
  import random
5
  from datetime import datetime
6
  import gspread
 
9
  import json
10
 
11
  # تنظیمات اولیه
12
+ st.set_page_config(layout="wide", page_title="تحلیل انصاف قیمتی", page_icon="📊")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  # ========== تنظیمات دیتا ==========
15
  SHEET_ID = "1mmdWAyOCYq4yXMgP53Duq712AnlqZWLkfIo76JqM7wM"
16
  SHEET_NAME = "Condition1"
17
 
18
+ # ========== استایل‌های سفارشی ==========
19
+ st.markdown("""
20
+ <style>
21
+ .ride-header {
22
+ background-color: #3d5a80;
23
+ padding: 15px;
24
+ border-radius: 10px;
25
+ color: white;
26
+ margin-bottom: 20px;
27
+ }
28
+ .price-box {
29
+ border: 2px solid #3d5a80;
30
+ border-radius: 10px;
31
+ padding: 15px;
32
+ margin: 15px 0;
33
+ text-align: center;
34
+ font-size: 24px;
35
+ font-weight: bold;
36
+ }
37
+ .explanation-box {
38
+ background-color: #f8f9fa;
39
+ border-radius: 10px;
40
+ padding: 15px;
41
+ margin: 15px 0;
42
+ border-right: 5px solid #3d5a80;
43
+ }
44
+ .survey-section {
45
+ background-color: #f0f2f6;
46
+ border-radius: 10px;
47
+ padding: 20px;
48
+ margin-top: 30px;
49
+ }
50
+ </style>
51
+ """, unsafe_allow_html=True)
52
+
53
+ # ========== توابع اصلی ==========
54
+ def create_ride_map():
55
+ """ایجاد نقشه سفر با Folium"""
56
+ start_point = [35.6892, 51.3890] # تهران
57
+ end_point = [35.8400, 50.9391] # کرج
58
+
59
+ m = folium.Map(location=[35.7, 51.3], zoom_start=11)
60
+ folium.Marker(start_point, popup="<b>مبدأ:</b> میدان انقلاب", icon=folium.Icon(color="green")).add_to(m)
61
+ folium.Marker(end_point, popup="<b>مقصد:</b> میدان امام خمینی", icon=folium.Icon(color="red")).add_to(m)
62
+ folium.PolyLine([start_point, end_point], color="blue", weight=2.5).add_to(m)
63
+ return m
64
+
65
+ def generate_random_price():
66
+ """تولید قیمت تصادفی"""
67
+ return random.randint(80, 200) * 1000 # قیمت به تومان
68
+
69
+ def show_explanation(exp_type):
70
+ """نمایش توضیحات قیمت"""
71
+ explanations = {
72
+ "control": [],
73
+ "input": [
74
+ "• سطح تقاضا در منطقه: زیاد (+)",
75
+ "• تعداد رانندگان فعال: کم (+)",
76
+ "• زمان روز: ساعت اوج ترافیک (+)",
77
+ "• شرایط جوی: هوای بارانی (++)"
78
+ ],
79
+ "counterfactual": [
80
+ "اگر این سفر را ۳۰ دقیقه زودتر یا دیرتر درخواست می‌کردید، قیمت ۱۵٪ کمتر می‌شد",
81
+ "اگر تعداد رانندگان فعال دو برابر بود، قیمت‌گذاری نوسانی اعمال نمی‌شد"
82
+ ]
83
+ }
84
+
85
+ if exp_type != "control":
86
+ with st.expander("🔍 توضیحات قیمت", expanded=True):
87
+ st.markdown("<div class='explanation-box'><h4>علت قیمت گذاری:</h4>", unsafe_allow_html=True)
88
+ for item in explanations.get(exp_type, []):
89
+ st.markdown(f"<p>{item}</p>", unsafe_allow_html=True)
90
+ st.markdown("</div>", unsafe_allow_html=True)
91
+ return exp_type
92
+
93
+ # ========== توابع مدیریت داده‌ها ==========
94
  def get_credentials():
95
  """دریافت اعتبارنامه از Secrets"""
96
  try:
 
97
  service_account_json = os.environ.get('GCP_SERVICE_ACCOUNT')
 
98
  if not service_account_json:
99
  st.error("مقدار GCP_SERVICE_ACCOUNT در محیط یافت نشد")
100
  return None
101
 
 
102
  service_account_info = json.loads(service_account_json)
 
 
103
  creds = Credentials.from_service_account_info(
104
  service_account_info,
105
  scopes=[
 
111
  except Exception as e:
112
  st.error(f"خطا در دریافت اعتبارنامه: {str(e)}")
113
  return None
 
 
 
 
 
 
 
114
 
115
  def save_to_sheet(data):
116
  try:
 
124
 
125
  row_data = [
126
  datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
127
+ data.get("scenario_type"),
128
+ data.get("price"),
129
  data.get("age"),
130
  data.get("gender"),
131
  data.get("education"),
 
142
  st.error(f"خطا در ذخیره‌سازی: {str(e)}")
143
  return False
144
 
145
+ # ========== بخش‌های فرم ==========
146
+ def demographic_form():
147
+ """فرم اطلاعات دموگرافیک"""
148
+ with st.form("demographic"):
149
+ st.header("📝 اطلاعات دموگرافیک")
150
+ age = st.number_input("سن", min_value=18, max_value=100)
151
+ gender = st.selectbox("جنسیت", ["مرد", "زن", "سایر"])
152
+ education = st.selectbox("تحصیلات", ["دیپلم", "لیسانس", "فوق لیسانس", "دکترا"])
153
+ ride_frequency = st.selectbox("دفعات استفاده از سرویس‌های اشتراک سفر در ماه",
154
+ ["کمتر از 5 بار", "5-10 بار", "بیش از 10 بار"])
155
+
156
+ if st.form_submit_button("ذخیره اطلاعات"):
157
+ return {
158
+ "age": age,
159
+ "gender": gender,
160
+ "education": education,
161
+ "ride_frequency": ride_frequency
162
+ }
163
+ return None
164
 
165
+ def fairness_questionnaire():
166
+ """پرسشنامه ادراک انصاف"""
167
+ st.header("📊 پرسشنامه ادراک انصاف قیمتی")
 
 
 
 
 
168
 
169
+ st.markdown("**لطفاً با توجه به قیمت و توضیحات ارائه شده به سوالات زیر پاسخ دهید:**")
 
 
170
 
171
+ fairness = st.slider("به نظر شما این قیمت چقدر منصفانه است؟ (1 کاملاً ناعادلانه - 7 کاملاً عادلانه)", 1, 7)
172
+ transparency = st.slider("چقدر توضیحات ارائه شده در مورد قیمت را شفاف می‌دانید؟ (1 کاملاً نامشخص - 7 کاملاً شفاف)", 1, 7)
173
+ satisfaction = st.slider("چقدر از این قیمت‌گذاری راضی هستید؟ (1 کاملاً ناراضی - 7 کاملاً راضی)", 1, 7)
174
 
175
+ return {
176
+ "fairness": fairness,
177
+ "transparency": transparency,
178
+ "satisfaction": satisfaction
179
+ }
180
+
181
+ # ========== رابط کاربری اصلی ==========
182
+ def main():
183
+ # مدیریت وضعیت
184
+ if 'scenario_type' not in st.session_state:
185
+ st.session_state.scenario_type = random.choice(["control", "input", "counterfactual"])
186
+ if 'price' not in st.session_state:
187
+ st.session_state.price = generate_random_price()
188
+ if 'demographic_data' not in st.session_state:
189
+ st.session_state.demographic_data = None
190
+ if 'survey_completed' not in st.session_state:
191
+ st.session_state.survey_completed = False
192
+
193
+ # نمایش هدر
194
+ st.markdown("""
195
+ <div class="ride-header">
196
+ <h2>تحلیل انصاف قیمتی در پلتفرم‌های اشتراک سفر</h2>
197
+ <p>این تحقیق به بررسی تأثیر توضیحات قیمت بر ادراک انصاف می‌پردازد</p>
198
+ </div>
199
+ """, unsafe_allow_html=True)
200
+
201
+ # اگر اطلاعات دموگرافیک تکمیل نشده
202
+ if not st.session_state.demographic_data:
203
+ data = demographic_form()
204
+ if data:
205
+ st.session_state.demographic_data = data
206
+ st.rerun()
207
+ return
208
+
209
+ # اگر پرسشنامه تکمیل نشده
210
+ if not st.session_state.survey_completed:
211
+ # نمایش سناریو
212
+ st.markdown("### 🗺️ مسیر سفر شما")
213
+ folium_static(create_ride_map(), width=800, height=400)
214
 
215
+ # نمایش قیمت
216
+ st.markdown(f"""
217
+ <div class="price-box">
218
+ قیمت پیشنهادی: {st.session_state.price:,} تومان
219
+ </div>
220
+ """, unsafe_allow_html=True)
221
+
222
+ # نمایش توضیحات (بر اساس نوع سناریو)
223
+ show_explanation(st.session_state.scenario_type)
224
+
225
+ # پرسشنامه
226
+ with st.container():
227
+ st.markdown("<div class='survey-section'>", unsafe_allow_html=True)
228
+ survey_data = fairness_questionnaire()
229
+ st.markdown("</div>", unsafe_allow_html=True)
230
 
231
+ if st.button("ارسال پاسخ‌ها", type="primary"):
232
+ all_data = {
233
+ "scenario_type": st.session_state.scenario_type,
234
+ "price": st.session_state.price,
235
+ **st.session_state.demographic_data,
236
+ **survey_data
237
+ }
238
+
239
+ if save_to_sheet(all_data):
240
+ st.session_state.survey_completed = True
241
+ st.rerun()
242
+ else:
243
+ # صفحه تشکر
244
+ st.success("✅ پاسخ‌های شما با موفقیت ثبت شد. با تشکر از مشارکت شما در این تحقیق!")
245
+ st.balloons()
246
+
247
+ if st.button("بازگشت به ابتدا"):
248
+ st.session_state.clear()
249
+ st.rerun()
250
 
251
  if __name__ == "__main__":
252
  main()