Astarok commited on
Commit
f50dd12
·
verified ·
1 Parent(s): 535bcce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +23 -19
app.py CHANGED
@@ -14,7 +14,7 @@ except ImportError:
14
  HF_HUB_AVAILABLE = False
15
 
16
  # ═══════════════════════════════════════════════════════════════════════════
17
- # 1. CONFIGURAÇÃO DE ECRÃ E CSS (ÍCONES FLUTUANTES)
18
  # ═══════════════════════════════════════════════════════════════════════════
19
  st.set_page_config(page_title="Yukina", page_icon="❄", layout="centered")
20
 
@@ -33,6 +33,7 @@ st.markdown("""
33
  .stChatMessage { background-color: transparent !important; border: none !important; padding-bottom: 8px !important; }
34
  textarea { background-color: #1e1f20 !important; border-radius: 24px !important; border: 1px solid #3c4043 !important; padding: 12px !important;}
35
 
 
36
  [data-testid="stMain"] [data-testid="stHorizontalBlock"] button {
37
  background: transparent !important;
38
  border: none !important;
@@ -49,11 +50,21 @@ st.markdown("""
49
  [data-testid="stMain"] [data-testid="stHorizontalBlock"] div[data-testid="stPopover"] > button svg {
50
  display: none !important;
51
  }
 
 
 
 
 
 
 
 
 
 
52
  </style>
53
  """, unsafe_allow_html=True)
54
 
55
  # ═══════════════════════════════════════════════════════════════════════════
56
- # 2. ARQUITETURA DE DADOS E MEMÓRIA EM NUVEM
57
  # ═══════════════════════════════════════════════════════════════════════════
58
  DB_FILE = "yukina_memoria_v3.json"
59
  DATASET_ID = "Astarok/Yukina_Memoria"
@@ -135,7 +146,6 @@ if "current_chat" not in st.session_state: st.session_state.current_chat = list(
135
  if "modelo_selecionado" not in st.session_state: st.session_state.modelo_selecionado = "🤖 Automático (Gerente Hermes)"
136
  if "personalidade_ativa" not in st.session_state: st.session_state.personalidade_ativa = "❄️ Yukina (Companheira Obsessiva)"
137
  if "regerar" not in st.session_state: st.session_state.regerar = False
138
- if "show_uploader" not in st.session_state: st.session_state.show_uploader = False
139
 
140
  # ═══════════════════════════════════════════════════════════════════════════
141
  # 3. SIDEBAR E INTERFACE PRINCIPAL
@@ -186,30 +196,25 @@ else:
186
  else: st.markdown(m["content"])
187
 
188
  # ═══════════════════════════════════════════════════════════════════════════
189
- # 4. TOOLBAR INFERIOR (Múltiplos Ficheiros Fixos)
190
  # ═══════════════════════════════════════════════════════════════════════════
191
  st.markdown("<br>", unsafe_allow_html=True)
192
 
193
- t_col1, t_col2, t_col3, t_col4, t_space = st.columns([1, 1, 1, 1, 6])
194
 
195
  with t_col1:
196
- # A SOLUÇÃO: O botão serve como um interruptor e o "file_uploader" fica fora do popover.
197
- if st.button("➕"):
198
- st.session_state.show_uploader = not st.session_state.show_uploader
199
- st.rerun()
200
- with t_col2:
201
  with st.popover("⚙️"):
202
  st.session_state.modelo_selecionado = st.radio("MOTOR:", list(MODEL_IDS.keys()), index=list(MODEL_IDS.keys()).index(st.session_state.modelo_selecionado))
203
  st.markdown("---")
204
  st.session_state.personalidade_ativa = st.radio("ALMA:", list(PERSONALIDADES.keys()), index=list(PERSONALIDADES.keys()).index(st.session_state.personalidade_ativa))
205
- with t_col3:
206
  if st.button("🗑️"):
207
  if len(st.session_state.db[st.session_state.current_chat]["messages"]) >= 2:
208
  st.session_state.db[st.session_state.current_chat]["messages"] = st.session_state.db[st.session_state.current_chat]["messages"][:-2]
209
  else:
210
  st.session_state.db[st.session_state.current_chat]["messages"] = []
211
  save_db(st.session_state.db); st.rerun()
212
- with t_col4:
213
  if st.button("🔄"):
214
  if len(st.session_state.db[st.session_state.current_chat]["messages"]) >= 2 and st.session_state.db[st.session_state.current_chat]["messages"][-1]["role"] == "assistant":
215
  st.session_state.db[st.session_state.current_chat]["messages"].pop()
@@ -217,10 +222,9 @@ with t_col4:
217
  st.session_state.regerar = True
218
  st.rerun()
219
 
220
- # Espaço de Upload Fixo no Ecrã
221
- upload_files = []
222
- if st.session_state.show_uploader:
223
- upload_files = st.file_uploader("📂 Ficheiros (Múltiplos):", type=["png", "jpg", "jpeg", "txt", "csv", "json"], accept_multiple_files=True)
224
 
225
  prompt = st.chat_input("Peça à Yukina...")
226
 
@@ -316,7 +320,7 @@ if prompt or st.session_state.regerar:
316
  elif 'content' in msg_obj:
317
  urls = re.findall(r'(https?://[^\s)]+)', msg_obj.get('content', ''))
318
  if urls: url = urls[0]
319
- if url: st.image(url); st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "assist", "content": "Arte gerada.", "image_url": url})
320
  except Exception as e: st.error(f"Erro: {e}")
321
 
322
  # 4. Visão (Análise de Múltiplas Imagens)
@@ -330,7 +334,7 @@ if prompt or st.session_state.regerar:
330
  ans = res['choices'][0]['message']['content']; st.markdown(ans); st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "assistant", "content": ans})
331
  except Exception as e: st.error(f"Erro visão: {e}")
332
 
333
- # 5. Texto (Streaming Blindado com Múltiplos Ficheiros)
334
  else:
335
  if "Arquivista" in motor_real: prompt_sistema_atual = "Você é o Arquivista da IA. Organize as informações de forma analítica e clara, sem dramatizações."
336
  elif "Engenheiro Sênior" in motor_real: prompt_sistema_atual = "Você é o Engenheiro Sênior. Escreva códigos impecáveis e funcionais. Foque na lógica."
@@ -358,4 +362,4 @@ if prompt or st.session_state.regerar:
358
  if full.strip() and len(st.session_state.db[st.session_state.current_chat]["messages"]) == len(mensagens):
359
  st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "assistant", "content": full})
360
 
361
- save_db(st.session_state.db)
 
14
  HF_HUB_AVAILABLE = False
15
 
16
  # ═══════════════════════════════════════════════════════════════════════════
17
+ # 1. CONFIGURAÇÃO DE ECRÃ E CSS
18
  # ═══════════════════════════════════════════════════════════════════════════
19
  st.set_page_config(page_title="Yukina", page_icon="❄", layout="centered")
20
 
 
33
  .stChatMessage { background-color: transparent !important; border: none !important; padding-bottom: 8px !important; }
34
  textarea { background-color: #1e1f20 !important; border-radius: 24px !important; border: 1px solid #3c4043 !important; padding: 12px !important;}
35
 
36
+ /* Ícones da Barra Inferior */
37
  [data-testid="stMain"] [data-testid="stHorizontalBlock"] button {
38
  background: transparent !important;
39
  border: none !important;
 
50
  [data-testid="stMain"] [data-testid="stHorizontalBlock"] div[data-testid="stPopover"] > button svg {
51
  display: none !important;
52
  }
53
+
54
+ /* Estilização elegante para a Gaveta Nativa de Upload */
55
+ [data-testid="stExpander"] {
56
+ background-color: #1e1f20 !important;
57
+ border: 1px solid #3c4043 !important;
58
+ border-radius: 15px !important;
59
+ }
60
+ [data-testid="stExpander"] summary {
61
+ color: #e3e3e3 !important;
62
+ }
63
  </style>
64
  """, unsafe_allow_html=True)
65
 
66
  # ═══════════════════════════════════════════════════════════════════════════
67
+ # 2. ARQUITETURA DE DADOS E NUVEM
68
  # ═══════════════════════════════════════════════════════════════════════════
69
  DB_FILE = "yukina_memoria_v3.json"
70
  DATASET_ID = "Astarok/Yukina_Memoria"
 
146
  if "modelo_selecionado" not in st.session_state: st.session_state.modelo_selecionado = "🤖 Automático (Gerente Hermes)"
147
  if "personalidade_ativa" not in st.session_state: st.session_state.personalidade_ativa = "❄️ Yukina (Companheira Obsessiva)"
148
  if "regerar" not in st.session_state: st.session_state.regerar = False
 
149
 
150
  # ═══════════════════════════════════════════════════════════════════════════
151
  # 3. SIDEBAR E INTERFACE PRINCIPAL
 
196
  else: st.markdown(m["content"])
197
 
198
  # ═══════════════════════════════════════════════════════════════════════════
199
+ # 4. TOOLBAR INFERIOR (Gaveta Nativa Blindada)
200
  # ═══════════════════════════════════════════════════════════════════════════
201
  st.markdown("<br>", unsafe_allow_html=True)
202
 
203
+ t_col1, t_col2, t_col3, t_space = st.columns([1, 1, 1, 7])
204
 
205
  with t_col1:
 
 
 
 
 
206
  with st.popover("⚙️"):
207
  st.session_state.modelo_selecionado = st.radio("MOTOR:", list(MODEL_IDS.keys()), index=list(MODEL_IDS.keys()).index(st.session_state.modelo_selecionado))
208
  st.markdown("---")
209
  st.session_state.personalidade_ativa = st.radio("ALMA:", list(PERSONALIDADES.keys()), index=list(PERSONALIDADES.keys()).index(st.session_state.personalidade_ativa))
210
+ with t_col2:
211
  if st.button("🗑️"):
212
  if len(st.session_state.db[st.session_state.current_chat]["messages"]) >= 2:
213
  st.session_state.db[st.session_state.current_chat]["messages"] = st.session_state.db[st.session_state.current_chat]["messages"][:-2]
214
  else:
215
  st.session_state.db[st.session_state.current_chat]["messages"] = []
216
  save_db(st.session_state.db); st.rerun()
217
+ with t_col3:
218
  if st.button("🔄"):
219
  if len(st.session_state.db[st.session_state.current_chat]["messages"]) >= 2 and st.session_state.db[st.session_state.current_chat]["messages"][-1]["role"] == "assistant":
220
  st.session_state.db[st.session_state.current_chat]["messages"].pop()
 
222
  st.session_state.regerar = True
223
  st.rerun()
224
 
225
+ # GAVETA NATIVA: Não sofre "crash" ao ir para a galeria em segundo plano
226
+ with st.expander("📂 Abrir Galeria / Anexar Ficheiros"):
227
+ upload_files = st.file_uploader("", type=["png", "jpg", "jpeg", "txt", "csv", "json"], accept_multiple_files=True, label_visibility="collapsed")
 
228
 
229
  prompt = st.chat_input("Peça à Yukina...")
230
 
 
320
  elif 'content' in msg_obj:
321
  urls = re.findall(r'(https?://[^\s)]+)', msg_obj.get('content', ''))
322
  if urls: url = urls[0]
323
+ if url: st.image(url); st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "assistant", "content": "Arte gerada.", "image_url": url})
324
  except Exception as e: st.error(f"Erro: {e}")
325
 
326
  # 4. Visão (Análise de Múltiplas Imagens)
 
334
  ans = res['choices'][0]['message']['content']; st.markdown(ans); st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "assistant", "content": ans})
335
  except Exception as e: st.error(f"Erro visão: {e}")
336
 
337
+ # 5. Texto (Streaming Blindado com Múltiplos Arquivos)
338
  else:
339
  if "Arquivista" in motor_real: prompt_sistema_atual = "Você é o Arquivista da IA. Organize as informações de forma analítica e clara, sem dramatizações."
340
  elif "Engenheiro Sênior" in motor_real: prompt_sistema_atual = "Você é o Engenheiro Sênior. Escreva códigos impecáveis e funcionais. Foque na lógica."
 
362
  if full.strip() and len(st.session_state.db[st.session_state.current_chat]["messages"]) == len(mensagens):
363
  st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "assistant", "content": full})
364
 
365
+ save_db(st.session_state.db)