Spaces:
Running
Running
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +21 -49
src/streamlit_app.py
CHANGED
|
@@ -13,23 +13,10 @@ from llama_cpp import Llama
|
|
| 13 |
from streamlit_cookies_manager import EncryptedCookieManager
|
| 14 |
|
| 15 |
# --- НАСТРОЙКА КУК (ВАЖНО) ---
|
| 16 |
-
|
| 17 |
-
cookies = EncryptedCookieManager(password="HiperDoubleSecretKey123")
|
| 18 |
if not cookies.ready():
|
| 19 |
st.stop()
|
| 20 |
|
| 21 |
-
# --- ПРОВЕРКА СОХРАНЕННОГО ВХОДА ---
|
| 22 |
-
if "user_email" not in st.session_state:
|
| 23 |
-
# Пытаемся достать email из памяти браузера
|
| 24 |
-
st.session_state.user_email = cookies.get("saved_email")
|
| 25 |
-
st.session_state.user_name = cookies.get("saved_name", "Пользователь")
|
| 26 |
-
|
| 27 |
-
# --- В ФУНКЦИИ ОБРАБОТКИ GOOGLE (ТАМ ГДЕ ПОЛУЧАЕМ INFO) ---
|
| 28 |
-
# После строки st.session_state.user_email = info.get("email") добавь:
|
| 29 |
-
cookies["saved_email"] = info.get("email")
|
| 30 |
-
cookies["saved_name"] = info.get("name")
|
| 31 |
-
cookies.save() # Записываем в память телефона
|
| 32 |
-
|
| 33 |
# --- КОНФИГ GOOGLE АВТОРИЗАЦИИ ---
|
| 34 |
CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID")
|
| 35 |
CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET")
|
|
@@ -38,27 +25,24 @@ REDIRECT_URI = f"https://{host}/" if host else ""
|
|
| 38 |
|
| 39 |
def get_google_auth_url():
|
| 40 |
params = {
|
| 41 |
-
"client_id": CLIENT_ID,
|
| 42 |
-
"
|
| 43 |
-
"
|
| 44 |
-
"scope": "openid email profile",
|
| 45 |
-
"access_type": "offline",
|
| 46 |
-
"prompt": "select_account"
|
| 47 |
}
|
| 48 |
return f"https://accounts.google.com/o/oauth2/v2/auth?{'&'.join([f'{k}={v}' for k, v in params.items()])}"
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
| 52 |
|
| 53 |
-
# Обработка ответа от Google
|
| 54 |
if "code" in st.query_params and not st.session_state.user_email:
|
| 55 |
try:
|
| 56 |
code = st.query_params["code"]
|
| 57 |
res = requests.post("https://oauth2.googleapis.com/token", data={
|
| 58 |
-
"code": code,
|
| 59 |
-
"
|
| 60 |
-
"client_secret": CLIENT_SECRET,
|
| 61 |
-
"redirect_uri": REDIRECT_URI,
|
| 62 |
"grant_type": "authorization_code"
|
| 63 |
}).json()
|
| 64 |
token = res.get("access_token")
|
|
@@ -66,15 +50,17 @@ if "code" in st.query_params and not st.session_state.user_email:
|
|
| 66 |
info = requests.get("https://www.googleapis.com/oauth2/v3/userinfo", headers={"Authorization": f"Bearer {token}"}).json()
|
| 67 |
st.session_state.user_email = info.get("email")
|
| 68 |
st.session_state.user_name = info.get("name")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
st.rerun()
|
| 70 |
except: pass
|
| 71 |
|
| 72 |
# --- ФИКС АЙДИ ПОЛЬЗОВАТЕЛЯ ---
|
| 73 |
def get_user_id():
|
| 74 |
-
# Приоритет Google Auth для приватности
|
| 75 |
if st.session_state.user_email:
|
| 76 |
return st.session_state.user_email.replace("@", "_").replace(".", "_")
|
| 77 |
-
|
| 78 |
for header in ["X-Huggingface-User-User", "X-Repo-Guest-Name", "X-Forwarded-User"]:
|
| 79 |
user = st.context.headers.get(header)
|
| 80 |
if user: return user
|
|
@@ -160,15 +146,7 @@ def generate_llama_stream(prompt, system_prompt):
|
|
| 160 |
f"<|start_header_id|>user<|end_header_id|>\n\n{prompt}<|eot_id|>"
|
| 161 |
f"<|start_header_id|>assistant<|end_header_id|>\n\n"
|
| 162 |
)
|
| 163 |
-
|
| 164 |
-
stream = llm(
|
| 165 |
-
formatted_prompt,
|
| 166 |
-
max_tokens=512,
|
| 167 |
-
stop=["<|eot_id|>", "User:", "AI:"],
|
| 168 |
-
stream=True,
|
| 169 |
-
temperature=0.6,
|
| 170 |
-
repeat_penalty=1.2
|
| 171 |
-
)
|
| 172 |
for chunk in stream:
|
| 173 |
if "choices" in chunk and len(chunk["choices"]) > 0:
|
| 174 |
yield chunk["choices"][0]["text"]
|
|
@@ -234,7 +212,6 @@ st.markdown("<style>[data-testid='stAppViewContainer'] { background: #050508; co
|
|
| 234 |
with st.sidebar:
|
| 235 |
st.title("🧬 HiperDouble")
|
| 236 |
|
| 237 |
-
# Блок авторизации
|
| 238 |
if not st.session_state.user_email:
|
| 239 |
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; font-weight: bold;">Войти через Google</a>', unsafe_allow_html=True)
|
| 240 |
st.stop()
|
|
@@ -242,6 +219,9 @@ with st.sidebar:
|
|
| 242 |
st.write(f"Аккаунт: **{st.session_state.user_name}**")
|
| 243 |
if st.button("Выйти"):
|
| 244 |
st.session_state.user_email = None
|
|
|
|
|
|
|
|
|
|
| 245 |
st.rerun()
|
| 246 |
|
| 247 |
lang = st.radio("🌐 Language:", ["RU", "EN"], horizontal=True)
|
|
@@ -309,27 +289,20 @@ if run_btn and user_input:
|
|
| 309 |
with st.chat_message("assistant"):
|
| 310 |
resp_placeholder = st.empty()
|
| 311 |
final_text = ""
|
| 312 |
-
|
| 313 |
if cfg["engine"] == "llama":
|
| 314 |
for chunk in generate_llama_stream(user_input, full_sys):
|
| 315 |
final_text += chunk
|
| 316 |
resp_placeholder.markdown(final_text + "▌")
|
| 317 |
resp_placeholder.markdown(final_text)
|
| 318 |
-
|
| 319 |
elif cfg["engine"] == "titan":
|
| 320 |
final_text = generate_titan(user_input)
|
| 321 |
resp_placeholder.markdown(final_text)
|
| 322 |
-
|
| 323 |
elif cfg["engine"] == "groq":
|
| 324 |
-
|
| 325 |
-
key = os.environ.get(key_name, "").strip()
|
| 326 |
resp = requests.post("https://api.groq.com/openai/v1/chat/completions",
|
| 327 |
json={"model": cfg["model"], "messages": [{"role": "system", "content": full_sys}, {"role": "user", "content": full_prompt}]},
|
| 328 |
headers={"Authorization": f"Bearer {key}"}, timeout=25).json()
|
| 329 |
-
if 'choices' in resp
|
| 330 |
-
final_text = resp['choices'][0]['message']['content']
|
| 331 |
-
else:
|
| 332 |
-
st.error(f"Error ({key_name}): {resp.get('error', {}).get('message', 'Unknown')}")
|
| 333 |
resp_placeholder.markdown(final_text)
|
| 334 |
else:
|
| 335 |
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "").strip())
|
|
@@ -342,7 +315,6 @@ if run_btn and user_input:
|
|
| 342 |
st.session_state.chats[st.session_state.current_chat].append({"role": "assistant", "content": final_text})
|
| 343 |
save_chats(st.session_state.chats)
|
| 344 |
st.rerun()
|
| 345 |
-
|
| 346 |
except Exception as e: st.error(f"Error: {e}")
|
| 347 |
|
| 348 |
st.write("---")
|
|
|
|
| 13 |
from streamlit_cookies_manager import EncryptedCookieManager
|
| 14 |
|
| 15 |
# --- НАСТРОЙКА КУК (ВАЖНО) ---
|
| 16 |
+
cookies = EncryptedCookieManager(password="HiperDoubleSecretKey123_Unique")
|
|
|
|
| 17 |
if not cookies.ready():
|
| 18 |
st.stop()
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
# --- КОНФИГ GOOGLE АВТОРИЗАЦИИ ---
|
| 21 |
CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID")
|
| 22 |
CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET")
|
|
|
|
| 25 |
|
| 26 |
def get_google_auth_url():
|
| 27 |
params = {
|
| 28 |
+
"client_id": CLIENT_ID, "redirect_uri": REDIRECT_URI,
|
| 29 |
+
"response_type": "code", "scope": "openid email profile",
|
| 30 |
+
"access_type": "offline", "prompt": "select_account"
|
|
|
|
|
|
|
|
|
|
| 31 |
}
|
| 32 |
return f"https://accounts.google.com/o/oauth2/v2/auth?{'&'.join([f'{k}={v}' for k, v in params.items()])}"
|
| 33 |
|
| 34 |
+
# Проверка: если в сессии пусто, пробуем взять из КУК
|
| 35 |
+
if "user_email" not in st.session_state or st.session_state.user_email is None:
|
| 36 |
+
st.session_state.user_email = cookies.get("saved_email")
|
| 37 |
+
st.session_state.user_name = cookies.get("saved_name", "Пользователь")
|
| 38 |
|
| 39 |
+
# Обработка ответа от Google (если пришли по ссылке с кодом)
|
| 40 |
if "code" in st.query_params and not st.session_state.user_email:
|
| 41 |
try:
|
| 42 |
code = st.query_params["code"]
|
| 43 |
res = requests.post("https://oauth2.googleapis.com/token", data={
|
| 44 |
+
"code": code, "client_id": CLIENT_ID,
|
| 45 |
+
"client_secret": CLIENT_SECRET, "redirect_uri": REDIRECT_URI,
|
|
|
|
|
|
|
| 46 |
"grant_type": "authorization_code"
|
| 47 |
}).json()
|
| 48 |
token = res.get("access_token")
|
|
|
|
| 50 |
info = requests.get("https://www.googleapis.com/oauth2/v3/userinfo", headers={"Authorization": f"Bearer {token}"}).json()
|
| 51 |
st.session_state.user_email = info.get("email")
|
| 52 |
st.session_state.user_name = info.get("name")
|
| 53 |
+
# ЗАПИСЫВАЕМ В ПАМЯТЬ БРАУЗЕРА
|
| 54 |
+
cookies["saved_email"] = info.get("email")
|
| 55 |
+
cookies["saved_name"] = info.get("name")
|
| 56 |
+
cookies.save()
|
| 57 |
st.rerun()
|
| 58 |
except: pass
|
| 59 |
|
| 60 |
# --- ФИКС АЙДИ ПОЛЬЗОВАТЕЛЯ ---
|
| 61 |
def get_user_id():
|
|
|
|
| 62 |
if st.session_state.user_email:
|
| 63 |
return st.session_state.user_email.replace("@", "_").replace(".", "_")
|
|
|
|
| 64 |
for header in ["X-Huggingface-User-User", "X-Repo-Guest-Name", "X-Forwarded-User"]:
|
| 65 |
user = st.context.headers.get(header)
|
| 66 |
if user: return user
|
|
|
|
| 146 |
f"<|start_header_id|>user<|end_header_id|>\n\n{prompt}<|eot_id|>"
|
| 147 |
f"<|start_header_id|>assistant<|end_header_id|>\n\n"
|
| 148 |
)
|
| 149 |
+
stream = llm(formatted_prompt, max_tokens=512, stop=["<|eot_id|>", "User:", "AI:"], stream=True, temperature=0.6, repeat_penalty=1.2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
for chunk in stream:
|
| 151 |
if "choices" in chunk and len(chunk["choices"]) > 0:
|
| 152 |
yield chunk["choices"][0]["text"]
|
|
|
|
| 212 |
with st.sidebar:
|
| 213 |
st.title("🧬 HiperDouble")
|
| 214 |
|
|
|
|
| 215 |
if not st.session_state.user_email:
|
| 216 |
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; font-weight: bold;">Войти через Google</a>', unsafe_allow_html=True)
|
| 217 |
st.stop()
|
|
|
|
| 219 |
st.write(f"Аккаунт: **{st.session_state.user_name}**")
|
| 220 |
if st.button("Выйти"):
|
| 221 |
st.session_state.user_email = None
|
| 222 |
+
cookies["saved_email"] = None
|
| 223 |
+
cookies["saved_name"] = None
|
| 224 |
+
cookies.save()
|
| 225 |
st.rerun()
|
| 226 |
|
| 227 |
lang = st.radio("🌐 Language:", ["RU", "EN"], horizontal=True)
|
|
|
|
| 289 |
with st.chat_message("assistant"):
|
| 290 |
resp_placeholder = st.empty()
|
| 291 |
final_text = ""
|
|
|
|
| 292 |
if cfg["engine"] == "llama":
|
| 293 |
for chunk in generate_llama_stream(user_input, full_sys):
|
| 294 |
final_text += chunk
|
| 295 |
resp_placeholder.markdown(final_text + "▌")
|
| 296 |
resp_placeholder.markdown(final_text)
|
|
|
|
| 297 |
elif cfg["engine"] == "titan":
|
| 298 |
final_text = generate_titan(user_input)
|
| 299 |
resp_placeholder.markdown(final_text)
|
|
|
|
| 300 |
elif cfg["engine"] == "groq":
|
| 301 |
+
key = os.environ.get(cfg.get("key_name", "GROQ_API_KEY"), "").strip()
|
|
|
|
| 302 |
resp = requests.post("https://api.groq.com/openai/v1/chat/completions",
|
| 303 |
json={"model": cfg["model"], "messages": [{"role": "system", "content": full_sys}, {"role": "user", "content": full_prompt}]},
|
| 304 |
headers={"Authorization": f"Bearer {key}"}, timeout=25).json()
|
| 305 |
+
final_text = resp['choices'][0]['message']['content'] if 'choices' in resp else "Ошибка"
|
|
|
|
|
|
|
|
|
|
| 306 |
resp_placeholder.markdown(final_text)
|
| 307 |
else:
|
| 308 |
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "").strip())
|
|
|
|
| 315 |
st.session_state.chats[st.session_state.current_chat].append({"role": "assistant", "content": final_text})
|
| 316 |
save_chats(st.session_state.chats)
|
| 317 |
st.rerun()
|
|
|
|
| 318 |
except Exception as e: st.error(f"Error: {e}")
|
| 319 |
|
| 320 |
st.write("---")
|