Abobasnik commited on
Commit
2576262
·
verified ·
1 Parent(s): 04b245a

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +89 -192
src/streamlit_app.py CHANGED
@@ -5,262 +5,159 @@ import os
5
  import json
6
  from streamlit_cookies_manager import EncryptedCookieManager
7
 
8
- # --- ИНИЦИАЛИЗАЦИЯ КУКИ ---
9
  cookies = EncryptedCookieManager(password="HiperDouble_Secret_2026_Key")
10
  if not cookies.ready():
11
- # Вместо пустого экрана показываем статус
12
- st.markdown("<h3 style='color:white; text-align:center; margin-top:50vh;'>🧬 Загрузка системы HiperDouble...</h3>", unsafe_allow_html=True)
13
  st.stop()
14
 
15
- # --- ПАРАМЕТРЫ GOOGLE ---
16
  CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID")
17
  CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET")
18
  host = st.context.headers.get("Host", "")
19
  REDIRECT_URI = f"https://{host}/" if host else ""
20
 
21
  def get_google_auth_url():
22
- params = {
23
- "client_id": CLIENT_ID,
24
- "redirect_uri": REDIRECT_URI,
25
- "response_type": "code",
26
- "scope": "openid email profile",
27
- "access_type": "offline",
28
- "prompt": "select_account"
29
- }
30
  return f"https://accounts.google.com/o/oauth2/v2/auth?{'&'.join([f'{k}={v}' for k, v in params.items()])}"
31
 
32
- # --- ЛОГИКА АККАУНТА ---
33
- if "user_email" not in st.session_state or st.session_state.user_email is None:
34
  st.session_state.user_email = cookies.get("saved_email")
35
  st.session_state.user_name = cookies.get("saved_name", "Пользователь")
36
 
 
37
  if "code" in st.query_params and not st.session_state.user_email:
38
  try:
39
- code = st.query_params["code"]
40
  res = requests.post("https://oauth2.googleapis.com/token", data={
41
- "code": code, "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET,
42
  "redirect_uri": REDIRECT_URI, "grant_type": "authorization_code"
43
  }).json()
44
  token = res.get("access_token")
45
  if token:
46
- info = requests.get("https://www.googleapis.com/oauth2/v3/userinfo",
47
- headers={"Authorization": f"Bearer {token}"}).json()
48
- st.session_state.user_email = info.get("email")
49
- st.session_state.user_name = info.get("name")
50
- cookies["saved_email"] = info.get("email")
51
- cookies["saved_name"] = info.get("name")
52
- cookies.save()
53
- st.rerun()
54
- except:
55
- pass
56
 
57
  def logout():
58
- # Безопасная очистка без ошибок кодирования
59
- for k in ["saved_email", "saved_name"]:
60
- if k in cookies:
61
- cookies[k] = "" # Устанавливаем пустую строку вместо None
62
  cookies.save()
63
  st.session_state.user_email = None
64
- st.session_state.user_name = "Пользователь"
65
  st.rerun()
66
 
67
- # --- РАБОТА С БД ---
68
- def get_db_path():
69
- u_id = st.session_state.user_email.replace('@','_').replace('.','_') if st.session_state.user_email else 'guest'
70
- return f"chats_db_{u_id}.json"
71
-
72
- def load_chats():
73
- path = get_db_path()
74
- if os.path.exists(path):
75
- try:
76
- with open(path, "r", encoding="utf-8") as f:
77
- return json.load(f) or {"Чат 1": []}
78
- except:
79
- return {"Чат 1": []}
80
- return {"Чат 1": []}
81
-
82
- def save_chats(chats):
83
- with open(get_db_path(), "w", encoding="utf-8") as f:
84
- json.dump(chats, f, ensure_ascii=False, indent=4)
85
-
86
- # --- КОНФИГ МОДЕЛЕЙ ---
87
- MODELS_CONFIG = {
88
- "🌌 HiperAi v2.1 (Grew up)": {"engine": "groq", "key_name": "GROQ_API_KEY3", "model": "llama-3.3-70b-versatile", "identity": "HiperAI v2.1 Grew up."},
89
- "🧠 HiperAI v2.3 (CORTEX)": {"engine": "groq", "key_name": "GROQ_API_KEY", "model": "llama-3.3-70b-versatile", "identity": "HiperAI v2.3 Cortex."},
90
- "🔥 HiperAI v2.1 (ADULT)": {"engine": "groq", "key_name": "GROQ_API_KEY2", "model": "llama-3.1-8b-instant", "identity": "HiperAI v2.1 Adult."},
91
- "🌐 HiperAI v2.2 (NETWORK)": {"engine": "groq", "key_name": "GROQ_API_KEY", "model": "llama-3.1-8b-instant", "identity": "HiperAI v2.2 Network."},
92
- "👶 HiperAI v2.1 (BABY)": {"engine": "titan", "model": "titan-89m", "identity": "HiperAI v2.1 Baby."},
93
- "🚀 HiperAI v2.0 (Test 1)": {"engine": "groq", "key_name": "GROQ_API_KEY", "model": "llama-3.3-70b-versatile", "identity": "HiperAI v2.0 Test."},
94
- "✨ HiperAI v1.1.3 (Stable)": {"engine": "openai", "model": "gpt-4o-mini", "identity": "HiperAI v1.1.3."},
95
- }
96
-
97
- # --- ИНТЕРФЕЙС ---
98
  st.set_page_config(page_title="HiperDouble AI", page_icon="🧬", layout="wide")
99
 
100
- if "chats" not in st.session_state: st.session_state.chats = load_chats()
101
- if "current_chat" not in st.session_state or st.session_state.current_chat not in st.session_state.chats:
102
- st.session_state.current_chat = list(st.session_state.chats.keys())[0]
103
- if "edit_mode" not in st.session_state: st.session_state.edit_mode = None
104
-
105
- # --- СТИЛИ (CSS) ---
106
  st.markdown("""
107
  <style>
108
  html, body, [data-testid="stAppViewContainer"] {
109
  background: radial-gradient(circle at top right, #1a0b2e, #020205);
110
  background-attachment: fixed;
111
  }
112
-
113
  .main-title {
114
- font-size: clamp(2rem, 8vw, 3.5rem);
115
- font-weight: 900;
116
- text-align: center;
117
  background: linear-gradient(90deg, #00f2fe, #7367f0, #ff00cc, #00f2fe);
118
- background-size: 200% auto;
119
- -webkit-background-clip: text;
120
- -webkit-text-fill-color: transparent;
121
- animation: shine 4s linear infinite;
122
- padding: 15px 0;
123
  }
124
  @keyframes shine { to { background-position: 200% center; } }
125
-
126
- /* ГЛАВНЫЙ ФИКС СКРОЛЛА: Сообщения растут вверх */
127
  .main .block-container {
128
- display: flex !important;
129
- flex-direction: column-reverse !important;
130
- padding-bottom: 200px !important;
131
- padding-top: 20px !important;
132
  }
133
-
134
- /* ФИКСИРОВАННАЯ НИЖНЯЯ ПАНЕЛЬ */
135
  [data-testid="stBottom"] {
136
- position: fixed !important;
137
- bottom: 0px !important;
138
  background: rgba(10, 10, 20, 0.96) !important;
139
- backdrop-filter: blur(15px);
140
- z-index: 1000 !important;
141
- padding: 10px 5% 45px 5% !important;
142
  border-top: 1px solid rgba(115, 103, 240, 0.4);
143
  }
144
-
145
- /* ПУЗЫРИ СООБЩЕНИЙ */
146
  .chat-bubble {
147
- padding: 18px 22px;
148
- border-radius: 22px;
149
- margin-top: 15px;
150
- background: rgba(255, 255, 255, 0.05);
151
- border: 1px solid rgba(255, 255, 255, 0.1);
152
- backdrop-filter: blur(8px);
153
- color: #f0f0f0;
154
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
155
- }
156
- .user-bubble {
157
- border-left: 5px solid #ff00cc;
158
- background: rgba(255, 0, 204, 0.07);
159
  }
160
-
161
- [data-testid="stSidebar"] { background-color: #080812 !important; }
162
  header, footer { visibility: hidden; }
163
  </style>
164
  """, unsafe_allow_html=True)
165
 
166
- # --- SIDEBAR ---
167
- with st.sidebar:
168
- st.markdown("### 🧬 HiperDouble AI")
169
- if st.session_state.user_email:
170
- st.markdown(f"👤 **{st.session_state.user_name}**")
171
- if st.button("🚪 Выйти", use_container_width=True): logout()
172
- else:
173
- st.markdown(f'<a href="{get_google_auth_url()}" target="_self" style="background-color: #4285F4; color: white; padding: 12px; text-decoration: none; border-radius: 8px; display: block; text-align: center;">Войти через Google</a>', unsafe_allow_html=True)
174
- st.stop()
175
-
176
- st.markdown("---")
177
- lang = st.radio("🌐", ["RU", "EN"], horizontal=True)
178
- T = {"RU":{"new":"➕ Новый чат","clear":"🗑️ Очистить","mod":"🤖 Модель:","in":"Сообщение..."},
179
- "EN":{"new":"➕ New Chat","clear":"🗑️ Clear","mod":"🤖 Model:","in":"Message..."}}[lang]
180
-
181
- selected_name = st.selectbox(T['mod'], list(MODELS_CONFIG.keys()))
182
- cfg = MODELS_CONFIG[selected_name]
183
-
184
- if st.button(T['new'], use_container_width=True):
185
- n = f"Чат {len(st.session_state.chats) + 1}"
186
- st.session_state.chats[n] = []
187
- save_chats(st.session_state.chats)
188
- st.session_state.current_chat = n
189
- st.rerun()
190
 
191
- if st.button(T['clear'], use_container_width=True):
192
- st.session_state.chats[st.session_state.current_chat] = []
193
- save_chats(st.session_state.chats)
194
- st.rerun()
195
 
196
- st.markdown("---")
197
- for chat_name in list(st.session_state.chats.keys()):
198
- col_c, col_e, col_d = st.columns([0.6, 0.2, 0.2])
199
- if col_c.button(f"💬 {chat_name[:12]}", key=f"s_{chat_name}"):
200
- st.session_state.current_chat = chat_name
201
- st.rerun()
202
- if col_e.button("✏️", key=f"e_{chat_name}"):
203
- st.session_state.edit_mode = chat_name
204
- if col_d.button("🗑️", key=f"d_{chat_name}"):
205
- if len(st.session_state.chats) > 1:
206
- del st.session_state.chats[chat_name]
207
- save_chats(st.session_state.chats)
208
- st.session_state.current_chat = list(st.session_state.chats.keys())[0]
209
- st.rerun()
210
-
211
- if st.session_state.edit_mode == chat_name:
212
- new_n = st.text_input("Имя:", chat_name, key=f"in_{chat_name}")
213
- if st.button("ОК", key=f"ok_{chat_name}"):
214
- st.session_state.chats[new_n] = st.session_state.chats.pop(chat_name)
215
- save_chats(st.session_state.chats)
216
- st.session_state.edit_mode = None
217
- st.session_state.current_chat = new_n
218
- st.rerun()
219
 
220
- # --- ОСНОВНОЙ ЭКРАН ---
 
 
 
221
 
222
- # Поле ввода (закреплено в stBottom через CSS)
223
- u_input = st.chat_input(T['in'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
  if st.session_state.current_chat in st.session_state.chats:
226
- # 1. НЕВИДИМЫЙ БЛОК-СТОПОР (снизу)
227
- st.markdown("<div style='height: 25vh; min-height: 180px;'></div>", unsafe_allow_html=True)
228
-
229
- # 2. СООБЩЕНИЯ (column-reverse сам сделает новые сверху)
230
- messages = st.session_state.chats[st.session_state.current_chat]
231
- for m in messages:
232
- role_label, bubble_style = ("Вы", "user-bubble") if m['role'] == 'user' else ("HiperAi", "")
233
- st.markdown(f"<div class='chat-bubble {bubble_style}'><b>{role_label}:</b><br>{m['content']}</div>", unsafe_allow_html=True)
234
-
235
- # 3. ЗАГОЛОВОК (будет в самом верху)
236
  st.markdown('<p class="main-title">HiperDouble AI</p>', unsafe_allow_html=True)
237
 
238
- # --- ЛОГИКА ОТПРАВКИ ---
239
  if u_input:
240
  st.session_state.chats[st.session_state.current_chat].append({"role": "user", "content": u_input})
241
  try:
242
  key = st.secrets.get(cfg["key_name"]) or os.environ.get(cfg["key_name"], "").strip()
243
- if cfg["engine"] == "titan":
244
- res_text = "Модель HiperAI Titan активна. Текстовый режим подтвержден."
245
- elif cfg["engine"] == "openai":
246
- client = OpenAI(api_key=st.secrets.get("OPENAI_API_KEY") or os.environ.get("OPENAI_API_KEY", ""))
247
- r = client.chat.completions.create(model=cfg["model"], messages=[
248
- {"role": "system", "content": cfg['identity']},
249
- {"role": "user", "content": u_input}
250
- ])
251
- res_text = r.choices[0].message.content
252
- else: # GROQ
253
- resp = requests.post("https://api.groq.com/openai/v1/chat/completions",
254
- json={
255
- "model": cfg["model"],
256
- "messages": [{"role": "system", "content": cfg['identity']}] + st.session_state.chats[st.session_state.current_chat][-6:]
257
- },
258
- headers={"Authorization": f"Bearer {key}"}, timeout=25)
259
- res_text = resp.json()['choices'][0]['message']['content']
260
- except Exception as e:
261
- res_text = f"⚠️ Ошибка связи с моделью. Попробуйте позже. ({str(e)})"
262
 
263
  st.session_state.chats[st.session_state.current_chat].append({"role": "assistant", "content": res_text})
264
- save_chats(st.session_state.chats)
265
- st.rerun()
266
 
 
5
  import json
6
  from streamlit_cookies_manager import EncryptedCookieManager
7
 
8
+ # --- ИНИЦИАЛИЗАЦИЯ КУКИ (Улучшенная) ---
9
  cookies = EncryptedCookieManager(password="HiperDouble_Secret_2026_Key")
10
  if not cookies.ready():
11
+ st.markdown("<h3 style='color:white; text-align:center; margin-top:45vh;'>🧬 Инициализация памяти...</h3>", unsafe_allow_html=True)
 
12
  st.stop()
13
 
14
+ # --- ПАРАМЕТРЫ ---
15
  CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID")
16
  CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET")
17
  host = st.context.headers.get("Host", "")
18
  REDIRECT_URI = f"https://{host}/" if host else ""
19
 
20
  def get_google_auth_url():
21
+ params = {"client_id": CLIENT_ID, "redirect_uri": REDIRECT_URI, "response_type": "code", "scope": "openid email profile", "access_type": "offline", "prompt": "select_account"}
 
 
 
 
 
 
 
22
  return f"https://accounts.google.com/o/oauth2/v2/auth?{'&'.join([f'{k}={v}' for k, v in params.items()])}"
23
 
24
+ # --- ЛОГИКА СЕССИИ ---
25
+ if "user_email" not in st.session_state:
26
  st.session_state.user_email = cookies.get("saved_email")
27
  st.session_state.user_name = cookies.get("saved_name", "Пользователь")
28
 
29
+ # Обработка входа от Google
30
  if "code" in st.query_params and not st.session_state.user_email:
31
  try:
 
32
  res = requests.post("https://oauth2.googleapis.com/token", data={
33
+ "code": st.query_params["code"], "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET,
34
  "redirect_uri": REDIRECT_URI, "grant_type": "authorization_code"
35
  }).json()
36
  token = res.get("access_token")
37
  if token:
38
+ info = requests.get("https://www.googleapis.com/oauth2/v3/userinfo", headers={"Authorization": f"Bearer {token}"}).json()
39
+ st.session_state.user_email, st.session_state.user_name = info.get("email"), info.get("name")
40
+ cookies["saved_email"], cookies["saved_name"] = info.get("email"), info.get("name")
41
+ cookies.save(); st.rerun()
42
+ except: pass
 
 
 
 
 
43
 
44
  def logout():
45
+ cookies["saved_email"], cookies["saved_name"] = "", ""
 
 
 
46
  cookies.save()
47
  st.session_state.user_email = None
 
48
  st.rerun()
49
 
50
+ # --- СТИЛИ (CSS) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  st.set_page_config(page_title="HiperDouble AI", page_icon="🧬", layout="wide")
52
 
 
 
 
 
 
 
53
  st.markdown("""
54
  <style>
55
  html, body, [data-testid="stAppViewContainer"] {
56
  background: radial-gradient(circle at top right, #1a0b2e, #020205);
57
  background-attachment: fixed;
58
  }
 
59
  .main-title {
60
+ font-size: clamp(2rem, 8vw, 3.5rem); font-weight: 900; text-align: center;
 
 
61
  background: linear-gradient(90deg, #00f2fe, #7367f0, #ff00cc, #00f2fe);
62
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
63
+ animation: shine 4s linear infinite; padding: 15px 0;
 
 
 
64
  }
65
  @keyframes shine { to { background-position: 200% center; } }
66
+
 
67
  .main .block-container {
68
+ display: flex !important; flex-direction: column-reverse !important;
69
+ padding-bottom: 220px !important;
 
 
70
  }
 
 
71
  [data-testid="stBottom"] {
72
+ position: fixed !important; bottom: 0px !important;
 
73
  background: rgba(10, 10, 20, 0.96) !important;
74
+ z-index: 1000 !important; padding: 10px 5% 45px 5% !important;
 
 
75
  border-top: 1px solid rgba(115, 103, 240, 0.4);
76
  }
 
 
77
  .chat-bubble {
78
+ padding: 18px; border-radius: 20px; margin-top: 15px;
79
+ background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1);
80
+ color: #f0f0f0; backdrop-filter: blur(10px);
 
 
 
 
 
 
 
 
 
81
  }
82
+ .user-bubble { border-left: 5px solid #ff00cc; background: rgba(255, 0, 204, 0.07); }
 
83
  header, footer { visibility: hidden; }
84
  </style>
85
  """, unsafe_allow_html=True)
86
 
87
+ # --- ПРОВЕРКА ВХОДА ---
88
+ if not st.session_state.user_email:
89
+ st.markdown('<p class="main-title">HiperDouble AI</p>', unsafe_allow_html=True)
90
+ st.markdown(f"""
91
+ <div style="text-align: center; margin-top: 10vh;">
92
+ <h2 style="color: white;">Добро пожаловать</h2>
93
+ <p style="color: #aaa;">Для начала работы нужно войти в систему</p>
94
+ <a href="{get_google_auth_url()}" target="_self"
95
+ style="background: #4285F4; color: white; padding: 15px 30px;
96
+ text-decoration: none; border-radius: 10px; font-weight: bold; display: inline-block; margin-top: 20px;">
97
+ Войти через Google
98
+ </a>
99
+ </div>
100
+ """, unsafe_allow_html=True)
101
+ st.stop()
 
 
 
 
 
 
 
 
 
102
 
103
+ # --- ОСНОВНОЙ КОНТЕНТ (только если вошел) ---
 
 
 
104
 
105
+ def load_chats():
106
+ u_id = st.session_state.user_email.replace('@','_').replace('.','_')
107
+ path = f"chats_db_{u_id}.json"
108
+ if os.path.exists(path):
109
+ try:
110
+ with open(path, "r", encoding="utf-8") as f: return json.load(f) or {"Чат 1": []}
111
+ except: return {"Чат 1": []}
112
+ return {"Чат 1": []}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ def save_chats(chats):
115
+ u_id = st.session_state.user_email.replace('@','_').replace('.','_')
116
+ with open(f"chats_db_{u_id}.json", "w", encoding="utf-8") as f:
117
+ json.dump(chats, f, ensure_ascii=False, indent=4)
118
 
119
+ MODELS_CONFIG = {
120
+ "🌌 HiperAi v2.1 (Grew up)": {"engine": "groq", "key_name": "GROQ_API_KEY3", "model": "llama-3.3-70b-versatile", "identity": "HiperAI v2.1 Grew up."},
121
+ "🧠 HiperAI v2.3 (CORTEX)": {"engine": "groq", "key_name": "GROQ_API_KEY", "model": "llama-3.3-70b-versatile", "identity": "HiperAI v2.3 Cortex."},
122
+ "🔥 HiperAI v2.1 (ADULT)": {"engine": "groq", "key_name": "GROQ_API_KEY2", "model": "llama-3.1-8b-instant", "identity": "HiperAI v2.1 Adult."},
123
+ "🌐 HiperAI v2.2 (NETWORK)": {"engine": "groq", "key_name": "GROQ_API_KEY", "model": "llama-3.1-8b-instant", "identity": "HiperAI v2.2 Network."},
124
+ "👶 HiperAI v2.1 (BABY)": {"engine": "titan", "model": "titan-89m", "identity": "HiperAI v2.1 Baby."},
125
+ "🚀 HiperAI v2.0 (Test 1)": {"engine": "groq", "key_name": "GROQ_API_KEY", "model": "llama-3.3-70b-versatile", "identity": "HiperAI v2.0 Test."},
126
+ "✨ HiperAI v1.1.3 (Stable)": {"engine": "openai", "model": "gpt-4o-mini", "identity": "HiperAI v1.1.3."},
127
+ }
128
+
129
+ if "chats" not in st.session_state: st.session_state.chats = load_chats()
130
+ if "current_chat" not in st.session_state: st.session_state.current_chat = list(st.session_state.chats.keys())[0]
131
+
132
+ with st.sidebar:
133
+ st.markdown(f"👤 **{st.session_state.user_name}**")
134
+ if st.button("🚪 Выйти", use_container_width=True): logout()
135
+ st.markdown("---")
136
+ sel_mod = st.selectbox("🤖 Модель:", list(MODELS_CONFIG.keys()))
137
+ cfg = MODELS_CONFIG[sel_mod]
138
+ if st.button("➕ Новый чат", use_container_width=True):
139
+ n = f"Чат {len(st.session_state.chats)+1}"; st.session_state.chats[n] = []; st.session_state.current_chat = n; save_chats(st.session_state.chats); st.rerun()
140
+
141
+ # --- РЕНДЕР ЧАТА ---
142
+ u_input = st.chat_input("Напишите сообщение...")
143
 
144
  if st.session_state.current_chat in st.session_state.chats:
145
+ st.markdown("<div style='height: 25vh;'></div>", unsafe_allow_html=True)
146
+ for m in st.session_state.chats[st.session_state.current_chat]:
147
+ role, style = ("Вы", "user-bubble") if m['role'] == 'user' else ("HiperAi", "")
148
+ st.markdown(f"<div class='chat-bubble {style}'><b>{role}:</b><br>{m['content']}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
149
  st.markdown('<p class="main-title">HiperDouble AI</p>', unsafe_allow_html=True)
150
 
 
151
  if u_input:
152
  st.session_state.chats[st.session_state.current_chat].append({"role": "user", "content": u_input})
153
  try:
154
  key = st.secrets.get(cfg["key_name"]) or os.environ.get(cfg["key_name"], "").strip()
155
+ resp = requests.post("https://api.groq.com/openai/v1/chat/completions",
156
+ json={"model": cfg["model"], "messages": [{"role": "system", "content": cfg['identity']}] + st.session_state.chats[st.session_state.current_chat][-6:]},
157
+ headers={"Authorization": f"Bearer {key}"}, timeout=25).json()
158
+ res_text = resp['choices'][0]['message']['content']
159
+ except: res_text = "⚠️ Ошибка модели."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
  st.session_state.chats[st.session_state.current_chat].append({"role": "assistant", "content": res_text})
162
+ save_chats(st.session_state.chats); st.rerun()
 
163