Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +218 -38
src/streamlit_app.py
CHANGED
@@ -1,40 +1,220 @@
|
|
1 |
-
import
|
2 |
-
import numpy as np
|
3 |
-
import pandas as pd
|
4 |
import streamlit as st
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
In the meantime, below is an example of what you can do with just a few lines of code:
|
14 |
-
"""
|
15 |
-
|
16 |
-
num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
|
17 |
-
num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
|
18 |
-
|
19 |
-
indices = np.linspace(0, 1, num_points)
|
20 |
-
theta = 2 * np.pi * num_turns * indices
|
21 |
-
radius = indices
|
22 |
-
|
23 |
-
x = radius * np.cos(theta)
|
24 |
-
y = radius * np.sin(theta)
|
25 |
-
|
26 |
-
df = pd.DataFrame({
|
27 |
-
"x": x,
|
28 |
-
"y": y,
|
29 |
-
"idx": indices,
|
30 |
-
"rand": np.random.randn(num_points),
|
31 |
-
})
|
32 |
-
|
33 |
-
st.altair_chart(alt.Chart(df, height=700, width=700)
|
34 |
-
.mark_point(filled=True)
|
35 |
-
.encode(
|
36 |
-
x=alt.X("x", axis=None),
|
37 |
-
y=alt.Y("y", axis=None),
|
38 |
-
color=alt.Color("idx", legend=None, scale=alt.Scale()),
|
39 |
-
size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
|
40 |
-
))
|
|
|
1 |
+
import os
|
|
|
|
|
2 |
import streamlit as st
|
3 |
+
import plotly.graph_objects as go
|
4 |
+
import pandas as pd
|
5 |
+
from datetime import datetime
|
6 |
+
|
7 |
+
# ----------------------------- Session Başlatıcı -----------------------------
|
8 |
+
if "history" not in st.session_state:
|
9 |
+
st.session_state.history = {}
|
10 |
+
|
11 |
+
if "kullanici" not in st.session_state:
|
12 |
+
st.session_state.kullanici = None
|
13 |
+
|
14 |
+
# ----------------------------- Konfor Aralıkları -----------------------------
|
15 |
+
def get_comfort_ranges():
|
16 |
+
return {
|
17 |
+
"Yatak Odası": {"sicaklik": (18, 21), "isik": (100, 200), "ses": (20, 30)},
|
18 |
+
"Oturma Odası": {"sicaklik": (20, 22), "isik": (150, 300), "ses": (30, 40)},
|
19 |
+
"Mutfak": {"sicaklik": (20, 24), "isik": (300, 600), "ses": (35, 50)},
|
20 |
+
"Salon": {"sicaklik": (20, 22), "isik": (500, 1000), "ses": (30, 40)},
|
21 |
+
"Banyo": {"sicaklik": (22, 24), "isik": (500, 700), "ses": (35, 50)},
|
22 |
+
}
|
23 |
+
|
24 |
+
# ----------------------------- Skor Hesaplama -----------------------------
|
25 |
+
def calculate_score(value, ideal_min, ideal_max):
|
26 |
+
if ideal_min <= value <= ideal_max:
|
27 |
+
return 100
|
28 |
+
elif value < ideal_min:
|
29 |
+
return max(0, 100 - ((ideal_min - value) / ideal_min * 100))
|
30 |
+
else:
|
31 |
+
return max(0, 100 - ((value - ideal_max) / ideal_max * 100))
|
32 |
+
|
33 |
+
def calculate_comfort(room, temp, light, sound, custom_ranges=None):
|
34 |
+
ranges = custom_ranges if custom_ranges else get_comfort_ranges().get(room)
|
35 |
+
if not ranges:
|
36 |
+
return "Geçersiz oda seçimi."
|
37 |
+
|
38 |
+
temp_score = calculate_score(temp, *ranges["sicaklik"])
|
39 |
+
light_score = calculate_score(light, *ranges["isik"])
|
40 |
+
sound_score = calculate_score(sound, *ranges["ses"])
|
41 |
+
|
42 |
+
weighted_score = temp_score * 0.5 + light_score * 0.3 + sound_score * 0.2
|
43 |
+
penalties = sum(10 for s in [temp_score, light_score, sound_score] if s < 30)
|
44 |
+
|
45 |
+
final_score = max(0, weighted_score - penalties)
|
46 |
+
return round(final_score, 2)
|
47 |
+
|
48 |
+
# ----------------------------- Geri Bildirim -----------------------------
|
49 |
+
def generate_feedback(room, temp, light, sound):
|
50 |
+
feedback = []
|
51 |
+
ranges = get_comfort_ranges().get(room)
|
52 |
+
def within_range(val, min_val, max_val): return min_val <= val <= max_val
|
53 |
+
|
54 |
+
if not within_range(temp, *ranges["sicaklik"]):
|
55 |
+
feedback.append("🌡️ Sıcaklık ideal aralığın dışında.")
|
56 |
+
if not within_range(light, *ranges["isik"]):
|
57 |
+
feedback.append("💡 Işık miktarı ideal aralığın dışında.")
|
58 |
+
if not within_range(sound, *ranges["ses"]):
|
59 |
+
feedback.append("🔊 Ses seviyesi ideal aralığın dışında.")
|
60 |
+
if not feedback:
|
61 |
+
feedback.append("✅ Tüm değerler ideal aralıkta, mükemmel ortam!")
|
62 |
+
return feedback
|
63 |
+
|
64 |
+
def generate_feedback_custom(temp, light, sound, ranges):
|
65 |
+
feedback = []
|
66 |
+
def within_range(val, min_val, max_val): return min_val <= val <= max_val
|
67 |
+
|
68 |
+
if not within_range(temp, *ranges["sicaklik"]):
|
69 |
+
feedback.append("🌡️ Sıcaklık belirlediğiniz aralığın dışında.")
|
70 |
+
if not within_range(light, *ranges["isik"]):
|
71 |
+
feedback.append("💡 Işık miktarı belirlediğiniz aralığın dışında.")
|
72 |
+
if not within_range(sound, *ranges["ses"]):
|
73 |
+
feedback.append("🔊 Ses seviyesi belirlediğiniz aralığın dışında.")
|
74 |
+
if not feedback:
|
75 |
+
feedback.append("✅ Tüm değerler belirlediğiniz aralıkta. Keyfinize bakın!")
|
76 |
+
return feedback
|
77 |
+
|
78 |
+
# ----------------------------- Gauge Chart -----------------------------
|
79 |
+
def show_gauge_chart(score):
|
80 |
+
fig = go.Figure(go.Indicator(
|
81 |
+
mode="gauge+number+delta",
|
82 |
+
value=score,
|
83 |
+
domain={'x': [0, 1], 'y': [0, 1]},
|
84 |
+
title={'text': "Konfor Skoru", 'font': {'size': 24}},
|
85 |
+
gauge={
|
86 |
+
'axis': {'range': [0, 100], 'tickwidth': 1, 'tickcolor': "gray"},
|
87 |
+
'bar': {'color': "darkblue"},
|
88 |
+
'bgcolor': "white",
|
89 |
+
'borderwidth': 2,
|
90 |
+
'bordercolor': "gray",
|
91 |
+
'steps': [
|
92 |
+
{'range': [0, 40], 'color': "red"},
|
93 |
+
{'range': [40, 60], 'color': "orange"},
|
94 |
+
{'range': [60, 80], 'color': "yellow"},
|
95 |
+
{'range': [80, 100], 'color': "green"}
|
96 |
+
],
|
97 |
+
}
|
98 |
+
))
|
99 |
+
st.plotly_chart(fig, use_container_width=True)
|
100 |
+
|
101 |
+
# ----------------------------- Oda Görselleri -----------------------------
|
102 |
+
room_image_map = {
|
103 |
+
"Yatak Odası": "src/yatakodasi.jpg",
|
104 |
+
"Oturma Odası": "src/OTURMA.jpg",
|
105 |
+
"Mutfak": "src/MUTFAK.jpg",
|
106 |
+
"Salon": "src/SALON.jpg",
|
107 |
+
"Banyo": "src/BANYO.jpg"
|
108 |
+
}
|
109 |
+
|
110 |
+
# ----------------------------- Sayfa Ayarı ve Stil -----------------------------
|
111 |
+
st.set_page_config(page_title="🏠 Egzantirik Konfor Hesaplayıcı", layout="wide")
|
112 |
+
|
113 |
+
st.markdown("""
|
114 |
+
<style>
|
115 |
+
.title { font-size:40px; color:#FF4B4B; text-align:center; font-weight:bold; margin-bottom:20px; }
|
116 |
+
.footer { text-align:center; margin-top: 30px; color: gray; }
|
117 |
+
</style>
|
118 |
+
""", unsafe_allow_html=True)
|
119 |
+
st.markdown('<div class="title"> THICK MAPS </div>', unsafe_allow_html=True)
|
120 |
+
|
121 |
+
# ----------------------------- Giriş ve Ayar Paneli -----------------------------
|
122 |
+
with st.sidebar:
|
123 |
+
st.header("🧑 Kullanıcı (Opsiyonel)")
|
124 |
+
if st.session_state.kullanici is None:
|
125 |
+
kullanici_adi = st.text_input("👤 İsim (boş bırakabilirsin)")
|
126 |
+
if st.button("🔓 Devam Et"):
|
127 |
+
if kullanici_adi.strip():
|
128 |
+
st.session_state.kullanici = kullanici_adi.strip()
|
129 |
+
else:
|
130 |
+
st.session_state.kullanici = "Anonim"
|
131 |
+
st.rerun()
|
132 |
+
else:
|
133 |
+
st.markdown(f"👋 Hoş geldin, **{st.session_state.kullanici}**")
|
134 |
+
if st.button("🚪 Çıkış Yap"):
|
135 |
+
st.session_state.kullanici = None
|
136 |
+
st.rerun()
|
137 |
+
|
138 |
+
st.header("🔧 Ayarlar")
|
139 |
+
room = st.selectbox("🛋️ Oda Seçimi", list(get_comfort_ranges().keys()))
|
140 |
+
temp = st.slider("🌡️ Sıcaklık (°C)", 10.0, 35.0, 21.0, step=0.5)
|
141 |
+
light = st.slider("💡 Işık Miktarı (lux)", 50, 1200, 300, step=10)
|
142 |
+
sound = st.slider("🔊 Ses Düzeyi (dB)", 10, 80, 35, step=1)
|
143 |
+
|
144 |
+
custom_ranges = st.checkbox("📐 Kendi konfor aralıklarımı tanımlamak istiyorum")
|
145 |
+
user_ranges = {}
|
146 |
+
if custom_ranges:
|
147 |
+
with st.expander("🎛️ Konfor Aralıklarını Ayarla", expanded=True):
|
148 |
+
user_temp_min = st.number_input("Min Sıcaklık", 0.0, 50.0, 20.0)
|
149 |
+
user_temp_max = st.number_input("Max Sıcaklık", 0.0, 50.0, 24.0)
|
150 |
+
user_light_min = st.number_input("Min Işık", 0, 2000, 200)
|
151 |
+
user_light_max = st.number_input("Max Işık", 0, 2000, 600)
|
152 |
+
user_sound_min = st.number_input("Min Ses", 0, 100, 20)
|
153 |
+
user_sound_max = st.number_input("Max Ses", 0, 100, 45)
|
154 |
+
user_ranges = {
|
155 |
+
"sicaklik": (user_temp_min, user_temp_max),
|
156 |
+
"isik": (user_light_min, user_light_max),
|
157 |
+
"ses": (user_sound_min, user_sound_max)
|
158 |
+
}
|
159 |
+
|
160 |
+
hesapla = st.button("📊 Konforu Hesapla")
|
161 |
+
|
162 |
+
# ----------------------------- Ana İçerik -----------------------------
|
163 |
+
col1, col2 = st.columns([2, 1])
|
164 |
+
|
165 |
+
with col1:
|
166 |
+
st.subheader("📷 Oda Planı")
|
167 |
+
image_path = room_image_map.get(room)
|
168 |
+
if image_path and os.path.exists(image_path):
|
169 |
+
st.image(image_path, caption=room, width=600)
|
170 |
+
else:
|
171 |
+
st.warning("Bu oda için görsel bulunamadı.")
|
172 |
+
|
173 |
+
with col2:
|
174 |
+
if hesapla:
|
175 |
+
score = calculate_comfort(room, temp, light, sound, user_ranges if custom_ranges else None)
|
176 |
+
st.subheader("📈 Konfor Skoru")
|
177 |
+
show_gauge_chart(score)
|
178 |
+
st.markdown(f"### 🎯 Konfor Yüzdesi: **%{score}**")
|
179 |
+
|
180 |
+
st.markdown("### 🧠 Sistem Geri Bildirimi")
|
181 |
+
feedback = generate_feedback_custom(temp, light, sound, user_ranges) if custom_ranges else generate_feedback(room, temp, light, sound)
|
182 |
+
for f in feedback:
|
183 |
+
st.write("- " + f)
|
184 |
+
|
185 |
+
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
186 |
+
user = st.session_state.kullanici or "Anonim"
|
187 |
+
|
188 |
+
if user not in st.session_state.history:
|
189 |
+
st.session_state.history[user] = []
|
190 |
+
|
191 |
+
st.session_state.history[user].append({
|
192 |
+
"Tarih": now,
|
193 |
+
"Oda": room,
|
194 |
+
"Sıcaklık": temp,
|
195 |
+
"Işık": light,
|
196 |
+
"Ses": sound,
|
197 |
+
"Skor": score
|
198 |
+
})
|
199 |
+
|
200 |
+
# ----------------------------- Geçmiş Gösterimi -----------------------------
|
201 |
+
user = st.session_state.kullanici or "Anonim"
|
202 |
+
if user in st.session_state.history:
|
203 |
+
user_data = st.session_state.history[user]
|
204 |
+
df = pd.DataFrame(user_data)
|
205 |
+
df["Tarih"] = pd.to_datetime(df["Tarih"])
|
206 |
+
df_room = df[df["Oda"] == room]
|
207 |
+
|
208 |
+
st.subheader(f"🕓 {room} için Geçmiş Konfor Ölçümleri ({user})")
|
209 |
+
if not df_room.empty:
|
210 |
+
st.dataframe(df_room, use_container_width=True)
|
211 |
+
st.line_chart(df_room.set_index("Tarih")[["Skor"]])
|
212 |
+
else:
|
213 |
+
st.info("Bu oda için henüz geçmiş veri bulunmamaktadır.")
|
214 |
|
215 |
+
# ----------------------------- Footer -----------------------------
|
216 |
+
st.markdown("""
|
217 |
+
<div class="footer">
|
218 |
+
© 2025 Neriman Kafaoğlu. Tüm hakları saklıdır.
|
219 |
+
</div>
|
220 |
+
""", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|