Astarok commited on
Commit
d6d582b
·
verified ·
1 Parent(s): 62c9d52

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -76
app.py CHANGED
@@ -21,12 +21,31 @@ st.markdown("""
21
  [data-testid="stSidebar"] { background-color: #0b0b0b !important; border-right: 1px solid #1e1f20 !important; }
22
  .stChatMessage { background-color: transparent !important; border: none !important; padding-bottom: 8px !important; }
23
  textarea { background-color: #1e1f20 !important; border-radius: 24px !important; border: 1px solid #3c4043 !important; padding: 12px !important;}
24
- .stButton > button, [data-testid="stPopover"] > button { border-radius: 30px !important; background-color: #1e1f20 !important; border: 1px solid #3c4043 !important; color: #e3e3e3 !important; padding: 8px 20px !important; font-size: 15px !important; }
 
25
  [data-testid="stSidebar"] button { background-color: transparent !important; border: none !important; box-shadow: none !important; color: #a0a0a0 !important; }
26
  [data-testid="stSidebar"] button:hover { color: #ffffff !important; background-color: #1e1f20 !important; }
27
  [data-testid="stSidebarContent"] [data-testid="stHorizontalBlock"] button { background: none !important; border: none !important; font-size: 22px !important; }
28
  [data-testid="stSidebarNav"] .stButton > button, [data-testid="stSidebarContent"] .stButton > button { width: 100% !important; justify-content: flex-start !important; }
29
  [data-testid="stPopover"] div[data-testid="stMarkdownContainer"] p { margin: 0 !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  </style>
31
  """, unsafe_allow_html=True)
32
 
@@ -82,10 +101,7 @@ def analisar_intencao_gerente(prompt, api_key):
82
 
83
  payload = {
84
  "model": "nousresearch/hermes-2-pro-llama-3-8b",
85
- "messages": [
86
- {"role": "system", "content": prompt_gerente},
87
- {"role": "user", "content": prompt}
88
- ],
89
  "temperature": 0.1
90
  }
91
  try:
@@ -97,32 +113,25 @@ def analisar_intencao_gerente(prompt, api_key):
97
  def load_db():
98
  if os.path.exists(DB_FILE):
99
  try:
100
- with open(DB_FILE, "r", encoding="utf-8") as f:
101
- return json.load(f)
102
- except:
103
- pass
104
  return {"Nova Conversa": {"pinned": False, "messages": []}}
105
 
106
  def save_db(db):
107
- with open(DB_FILE, "w", encoding="utf-8") as f:
108
- json.dump(db, f, ensure_ascii=False, indent=4)
109
 
110
- if "db" not in st.session_state:
111
- st.session_state.db = load_db()
112
- if "current_chat" not in st.session_state:
113
- st.session_state.current_chat = list(st.session_state.db.keys())[0]
114
- if "modelo_selecionado" not in st.session_state:
115
- st.session_state.modelo_selecionado = "🤖 Automático (Gerente Hermes)"
116
- if "personalidade_ativa" not in st.session_state:
117
- st.session_state.personalidade_ativa = "❄️ Yukina (Companheira Obsessiva)"
118
 
119
  # ═══════════════════════════════════════════════════════════════════════════
120
  # 3. SIDEBAR E INTERFACE PRINCIPAL
121
  # ═══════════════════════════════════════════════════════════════════════════
122
  with st.sidebar:
123
  c_title, c_add, c_set = st.columns([5, 1, 1])
124
- with c_title:
125
- st.markdown("<h4 style='color: #ededed; margin-bottom: 0;'>Bate-papos</h4>", unsafe_allow_html=True)
126
  with c_add:
127
  if st.button("+"):
128
  nid = f"Chat {datetime.now().strftime('%H:%M:%S')}"
@@ -137,12 +146,10 @@ with st.sidebar:
137
  arquivo_import = st.file_uploader("Importar conversa:", type=["json"])
138
  if arquivo_import:
139
  try:
140
- dados_importados = json.load(arquivo_import)
141
- st.session_state.db.update(dados_importados)
142
  save_db(st.session_state.db)
143
  st.success("Sincronizado!")
144
- except:
145
- st.error("Erro no ficheiro.")
146
 
147
  st.markdown("<br>", unsafe_allow_html=True)
148
  busca = st.text_input("Pesquisar", placeholder="🔍 Pesquisar...", label_visibility="collapsed")
@@ -161,14 +168,12 @@ with st.sidebar:
161
  with st.popover("⋮"):
162
  if st.button("⚲ Fixar", key=f"pin_{c_id}"):
163
  st.session_state.db[c_id]["pinned"] = not st.session_state.db[c_id]["pinned"]
164
- save_db(st.session_state.db)
165
- st.rerun()
166
  if st.button("🗑 Apagar", key=f"del_{c_id}"):
167
  if len(st.session_state.db) > 1:
168
  del st.session_state.db[c_id]
169
  st.session_state.current_chat = list(st.session_state.db.keys())[0]
170
- save_db(st.session_state.db)
171
- st.rerun()
172
 
173
  st.markdown("<h3 style='margin-top: -10px; color: #ededed;'>❄ Yukina</h3>", unsafe_allow_html=True)
174
  mensagens = st.session_state.db[st.session_state.current_chat]["messages"]
@@ -178,46 +183,61 @@ if len(mensagens) == 0:
178
  else:
179
  for m in mensagens:
180
  with st.chat_message(m["role"]):
181
- if "image_url" in m:
182
- st.image(m["image_url"])
183
- elif "video_url" in m:
184
- st.video(m["video_url"])
185
- else:
186
- st.markdown(m["content"])
187
 
188
  # ═══════════════════════════════════════════════════════════════════════════
189
- # 4. TOOLBAR INFERIOR E PROCESSAMENTO DE AGENTES
190
  # ═══════════════════════════════════════════════════════════════════════════
191
  st.markdown("<br>", unsafe_allow_html=True)
192
- t_col1, t_col2, t_space = st.columns([1.5, 1.5, 7])
 
193
  with t_col1:
194
- with st.popover(""):
195
- upload_file = st.file_uploader("Mídia ou Dados", type=["png", "jpg", "jpeg", "txt", "csv", "json"])
196
  with t_col2:
197
- with st.popover("⚙"):
198
  st.session_state.modelo_selecionado = st.radio("CÉREBRO (Motor):", list(MODEL_IDS.keys()), index=list(MODEL_IDS.keys()).index(st.session_state.modelo_selecionado))
199
  st.markdown("---")
200
  st.session_state.personalidade_ativa = st.radio("ALMA (Personalidade):", list(PERSONALIDADES.keys()), index=list(PERSONALIDADES.keys()).index(st.session_state.personalidade_ativa))
201
-
202
- with t_space:
203
- if len(mensagens) > 0 and st.button("🗑️ Desfazer Última"):
204
  if len(st.session_state.db[st.session_state.current_chat]["messages"]) >= 2:
205
  st.session_state.db[st.session_state.current_chat]["messages"] = st.session_state.db[st.session_state.current_chat]["messages"][:-2]
206
  else:
207
  st.session_state.db[st.session_state.current_chat]["messages"] = []
208
  save_db(st.session_state.db)
209
  st.rerun()
 
 
 
 
 
 
 
 
210
 
211
- if prompt := st.chat_input("Peça à Yukina..."):
212
- conteudo_arquivo = ""
213
- mensagem_display = prompt
214
- if upload_file is not None and upload_file.name.endswith(('.txt', '.csv', '.json')):
215
- conteudo_arquivo = upload_file.getvalue().decode("utf-8")
216
- mensagem_display = f"📄 **Arquivo enviado:** `{upload_file.name}`\n\n{prompt}"
217
-
218
- st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "user", "content": mensagem_display})
219
- with st.chat_message("user"):
220
- st.markdown(mensagem_display)
 
 
 
 
 
 
 
 
 
 
221
 
222
  with st.chat_message("assistant"):
223
  or_key = os.getenv("OPENROUTER_API_KEY")
@@ -320,26 +340,4 @@ if prompt := st.chat_input("Peça à Yukina..."):
320
  else:
321
  matches = re.findall(r'(https?://[^\s)]+)', msg_obj.get('content', ''))
322
  if matches:
323
- url = matches[0]
324
-
325
- if url:
326
- st.image(url)
327
- st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "assistant", "content": "Arte gerada.", "image_url": url})
328
- else:
329
- st.error("Erro ao gerar a imagem.")
330
- except Exception as e:
331
- st.error(f"Erro: {e}")
332
-
333
- # 4. Visão (MiMo V2)
334
- elif "Visão" in motor_real and upload_file is not None and upload_file.name.endswith(('.png', '.jpg', '.jpeg')):
335
- with st.spinner("MiMo a analisar..."):
336
- img_b64 = base64.b64encode(upload_file.read()).decode()
337
- payload_visao = {
338
- "model": modelo_id,
339
- "messages": [
340
- {"role": "system", "content": prompt_sistema_atual},
341
- {"role": "user", "content": [{"type": "text", "text": prompt}, {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_b64}"}}]}
342
- ],
343
- "max_tokens": 4000
344
- }
345
-
 
21
  [data-testid="stSidebar"] { background-color: #0b0b0b !important; border-right: 1px solid #1e1f20 !important; }
22
  .stChatMessage { background-color: transparent !important; border: none !important; padding-bottom: 8px !important; }
23
  textarea { background-color: #1e1f20 !important; border-radius: 24px !important; border: 1px solid #3c4043 !important; padding: 12px !important;}
24
+
25
+ /* Botões da Sidebar */
26
  [data-testid="stSidebar"] button { background-color: transparent !important; border: none !important; box-shadow: none !important; color: #a0a0a0 !important; }
27
  [data-testid="stSidebar"] button:hover { color: #ffffff !important; background-color: #1e1f20 !important; }
28
  [data-testid="stSidebarContent"] [data-testid="stHorizontalBlock"] button { background: none !important; border: none !important; font-size: 22px !important; }
29
  [data-testid="stSidebarNav"] .stButton > button, [data-testid="stSidebarContent"] .stButton > button { width: 100% !important; justify-content: flex-start !important; }
30
  [data-testid="stPopover"] div[data-testid="stMarkdownContainer"] p { margin: 0 !important; }
31
+
32
+ /* BARRA DE FERRAMENTAS INFERIOR (Apenas Ícones Flutuantes) */
33
+ [data-testid="stMain"] [data-testid="stHorizontalBlock"] button {
34
+ background-color: transparent !important;
35
+ border: none !important;
36
+ box-shadow: none !important;
37
+ font-size: 24px !important;
38
+ color: #a0a0a0 !important;
39
+ padding: 0px !important;
40
+ display: flex;
41
+ justify-content: center;
42
+ align-items: center;
43
+ }
44
+ [data-testid="stMain"] [data-testid="stHorizontalBlock"] button:hover {
45
+ color: #ffffff !important;
46
+ transform: scale(1.1);
47
+ transition: 0.2s;
48
+ }
49
  </style>
50
  """, unsafe_allow_html=True)
51
 
 
101
 
102
  payload = {
103
  "model": "nousresearch/hermes-2-pro-llama-3-8b",
104
+ "messages": [{"role": "system", "content": prompt_gerente}, {"role": "user", "content": prompt}],
 
 
 
105
  "temperature": 0.1
106
  }
107
  try:
 
113
  def load_db():
114
  if os.path.exists(DB_FILE):
115
  try:
116
+ with open(DB_FILE, "r", encoding="utf-8") as f: return json.load(f)
117
+ except: pass
 
 
118
  return {"Nova Conversa": {"pinned": False, "messages": []}}
119
 
120
  def save_db(db):
121
+ with open(DB_FILE, "w", encoding="utf-8") as f: json.dump(db, f, ensure_ascii=False, indent=4)
 
122
 
123
+ if "db" not in st.session_state: st.session_state.db = load_db()
124
+ if "current_chat" not in st.session_state: st.session_state.current_chat = list(st.session_state.db.keys())[0]
125
+ if "modelo_selecionado" not in st.session_state: st.session_state.modelo_selecionado = "🤖 Automático (Gerente Hermes)"
126
+ if "personalidade_ativa" not in st.session_state: st.session_state.personalidade_ativa = "❄️ Yukina (Companheira Obsessiva)"
127
+ if "regerar" not in st.session_state: st.session_state.regerar = False
 
 
 
128
 
129
  # ═══════════════════════════════════════════════════════════════════════════
130
  # 3. SIDEBAR E INTERFACE PRINCIPAL
131
  # ═══════════════════════════════════════════════════════════════════════════
132
  with st.sidebar:
133
  c_title, c_add, c_set = st.columns([5, 1, 1])
134
+ with c_title: st.markdown("<h4 style='color: #ededed; margin-bottom: 0;'>Bate-papos</h4>", unsafe_allow_html=True)
 
135
  with c_add:
136
  if st.button("+"):
137
  nid = f"Chat {datetime.now().strftime('%H:%M:%S')}"
 
146
  arquivo_import = st.file_uploader("Importar conversa:", type=["json"])
147
  if arquivo_import:
148
  try:
149
+ st.session_state.db.update(json.load(arquivo_import))
 
150
  save_db(st.session_state.db)
151
  st.success("Sincronizado!")
152
+ except: st.error("Erro no ficheiro.")
 
153
 
154
  st.markdown("<br>", unsafe_allow_html=True)
155
  busca = st.text_input("Pesquisar", placeholder="🔍 Pesquisar...", label_visibility="collapsed")
 
168
  with st.popover("⋮"):
169
  if st.button("⚲ Fixar", key=f"pin_{c_id}"):
170
  st.session_state.db[c_id]["pinned"] = not st.session_state.db[c_id]["pinned"]
171
+ save_db(st.session_state.db); st.rerun()
 
172
  if st.button("🗑 Apagar", key=f"del_{c_id}"):
173
  if len(st.session_state.db) > 1:
174
  del st.session_state.db[c_id]
175
  st.session_state.current_chat = list(st.session_state.db.keys())[0]
176
+ save_db(st.session_state.db); st.rerun()
 
177
 
178
  st.markdown("<h3 style='margin-top: -10px; color: #ededed;'>❄ Yukina</h3>", unsafe_allow_html=True)
179
  mensagens = st.session_state.db[st.session_state.current_chat]["messages"]
 
183
  else:
184
  for m in mensagens:
185
  with st.chat_message(m["role"]):
186
+ if "image_url" in m: st.image(m["image_url"])
187
+ elif "video_url" in m: st.video(m["video_url"])
188
+ else: st.markdown(m["content"])
 
 
 
189
 
190
  # ═══════════════════════════════════════════════════════════════════════════
191
+ # 4. TOOLBAR INFERIOR (Ícones Horizontais)
192
  # ═══════════════════════════════════════════════════════════════════════════
193
  st.markdown("<br>", unsafe_allow_html=True)
194
+ t_col1, t_col2, t_col3, t_col4, t_space = st.columns([1, 1, 1, 1, 6])
195
+
196
  with t_col1:
197
+ with st.popover("", help="Upload de Mídia ou Dados"):
198
+ upload_file = st.file_uploader("Upload", type=["png", "jpg", "jpeg", "txt", "csv", "json"], label_visibility="collapsed")
199
  with t_col2:
200
+ with st.popover("⚙", help="Configurações de IA"):
201
  st.session_state.modelo_selecionado = st.radio("CÉREBRO (Motor):", list(MODEL_IDS.keys()), index=list(MODEL_IDS.keys()).index(st.session_state.modelo_selecionado))
202
  st.markdown("---")
203
  st.session_state.personalidade_ativa = st.radio("ALMA (Personalidade):", list(PERSONALIDADES.keys()), index=list(PERSONALIDADES.keys()).index(st.session_state.personalidade_ativa))
204
+ with t_col3:
205
+ if st.button("🗑️", help="Apagar a última mensagem"):
 
206
  if len(st.session_state.db[st.session_state.current_chat]["messages"]) >= 2:
207
  st.session_state.db[st.session_state.current_chat]["messages"] = st.session_state.db[st.session_state.current_chat]["messages"][:-2]
208
  else:
209
  st.session_state.db[st.session_state.current_chat]["messages"] = []
210
  save_db(st.session_state.db)
211
  st.rerun()
212
+ with t_col4:
213
+ if st.button("🔄", help="Gerar nova resposta"):
214
+ if len(st.session_state.db[st.session_state.current_chat]["messages"]) >= 2:
215
+ if st.session_state.db[st.session_state.current_chat]["messages"][-1]["role"] == "assistant":
216
+ st.session_state.db[st.session_state.current_chat]["messages"].pop()
217
+ save_db(st.session_state.db)
218
+ st.session_state.regerar = True
219
+ st.rerun()
220
 
221
+ prompt = st.chat_input("Peça à Yukina...")
222
+
223
+ # Captura de arquivo em memória para não perder dados se a página recarregar
224
+ conteudo_arquivo = ""
225
+ if upload_file is not None and upload_file.name.endswith(('.txt', '.csv', '.json')):
226
+ conteudo_arquivo = upload_file.getvalue().decode("utf-8")
227
+
228
+ if prompt or st.session_state.regerar:
229
+ if st.session_state.regerar:
230
+ # Se for o botão de regerar, pegamos o último pedido do usuário
231
+ prompt = st.session_state.db[st.session_state.current_chat]["messages"][-1]["content"]
232
+ st.session_state.regerar = False
233
+ else:
234
+ mensagem_display = prompt
235
+ if conteudo_arquivo:
236
+ mensagem_display = f"📄 **Arquivo enviado:** `{upload_file.name}`\n\n{prompt}"
237
+
238
+ st.session_state.db[st.session_state.current_chat]["messages"].append({"role": "user", "content": mensagem_display})
239
+ with st.chat_message("user"):
240
+ st.markdown(mensagem_display)
241
 
242
  with st.chat_message("assistant"):
243
  or_key = os.getenv("OPENROUTER_API_KEY")
 
340
  else:
341
  matches = re.findall(r'(https?://[^\s)]+)', msg_obj.get('content', ''))
342
  if matches:
343
+ url = matches