cambio / app.py
Yofran23's picture
Update app.py
9da8dbe verified
Raw
History Blame Contribute Delete
9.05 kB
import streamlit as st
import pandas as pd
import gspread
from google.oauth2.service_account import Credentials
import os
import json
# ==========================================
# 1. PARTE SUPERIOR: LÓGICA DEL LOGIN
# ==========================================
# Configuramos la memoria
if 'usuario_autenticado' not in st.session_state:
st.session_state['usuario_autenticado'] = False
# Función para verificar las credenciales
def verificar_login(usuario, contrasena):
usuario_correcto = os.environ.get("USUARIO")
contrasena_correcta = os.environ.get("PASSWORD")
if usuario == usuario_correcto and contrasena == contrasena_correcta:
st.session_state['usuario_autenticado'] = True
st.success("¡Inicio de sesión exitoso!")
else:
st.error("Usuario o contraseña incorrectos.")
# ==========================================
# 2. SISTEMA DE RUTAS (MOSTRAR LOGIN O TU APP)
# ==========================================
# Si el usuario NO está autenticado, mostramos el formulario
if not st.session_state['usuario_autenticado']:
st.title("🔒 Iniciar Sesión")
usuario_input = st.text_input("Nombre de Usuario")
contrasena_input = st.text_input("Contraseña", type="password")
if st.button("Entrar"):
verificar_login(usuario_input, contrasena_input)
# Si el usuario SÍ está autenticado, mostramos TU APLICACIÓN
else:
# Botón opcional para cerrar sesión en la parte superior
if st.button("Cerrar Sesión"):
st.session_state['usuario_autenticado'] = False
st.rerun()
st.divider()
st.title("💱 Gestor de Compra/Venta de Divisas")
# --- 2. CONEXIÓN A GOOGLE SHEETS (VÍA SECRETO DE HUGGING FACE) ---
@st.cache_resource
def init_connection():
scopes = [
"https://www.googleapis.com/auth/spreadsheets",
]
try:
# 1. Traemos el texto desde los Secretos de Hugging Face
secreto_hf = os.environ.get("GCP_CREDENTIALS")
if secreto_hf is None:
st.error("No se encontró el secreto 'GCP_CREDENTIALS'.")
st.stop()
# 2. Convertimos ese texto en un diccionario de Python
credenciales_dict = json.loads(secreto_hf)
# 3. ¡IMPORTANTE! Usamos info en lugar de file
credentials = Credentials.from_service_account_info(
credenciales_dict,
scopes=scopes
)
client = gspread.authorize(credentials)
return client
except Exception as e:
st.error(f"Error de conexión: {e}")
st.stop()
# Conectamos con Google Sheets
gc = init_connection()
# 1. Pega aquí tu ID largo (el que está en la URL)
ID_DEL_DOCUMENTO = "1vYsYvo4LJERddrXGi4y-ugp-6vVM4xOo-D_ZPaxuMdI"
# 2. Escribe aquí el nombre exacto de la pestaña
NOMBRE_DE_LA_HOJA = "Dol"
try:
documento_completo = gc.open_by_key(ID_DEL_DOCUMENTO)
sheet = documento_completo.worksheet(NOMBRE_DE_LA_HOJA)
except gspread.exceptions.WorksheetNotFound:
st.error(f"Se encontró el documento, pero no existe una pestaña llamada '{NOMBRE_DE_LA_HOJA}'.")
st.stop()
except Exception as e:
st.error(f"No se pudo abrir el documento. Verifica el ID y los permisos. Error: {e}")
st.stop()
# --- 3. INICIALIZAR VARIABLES DE SESIÓN ---
if 'compras' not in st.session_state:
st.session_state.compras = []
if 'ventas' not in st.session_state:
st.session_state.ventas = []
# --- 4. INTERFAZ DE ENTRADA DE DATOS ---
col1, col2 = st.columns(2)
with col1:
st.header("🛒 Compras ($)")
with st.form("form_compra", clear_on_submit=True):
tasa_c = st.number_input("Tasa Compra", min_value=0.0, format="%.2f")
monto_c = st.number_input("Monto ($)", min_value=0.0, format="%.2f")
submit_c = st.form_submit_button("Agregar Compra")
if submit_c and tasa_c > 0 and monto_c > 0:
total_bs_c = tasa_c * monto_c
st.session_state.compras.append({
"Tipo": "Compra", "Tasa": tasa_c, "Monto ($)": monto_c, "Total (Bs)": total_bs_c
})
st.success("¡Compra agregada temporalmente!")
with col2:
st.header("💸 Ventas (USDT)")
with st.form("form_venta", clear_on_submit=True):
tasa_v = st.number_input("Tasa Venta", min_value=0.0, format="%.4f")
monto_v = st.number_input("Monto (USDT)", min_value=0.0, format="%.2f")
submit_v = st.form_submit_button("Agregar Venta")
if submit_v and tasa_v > 0 and monto_v > 0:
total_bs_v = tasa_v * monto_v
st.session_state.ventas.append({
"Tipo": "Venta", "Tasa": tasa_v, "Monto (USDT)": monto_v, "Total (Bs)": total_bs_v
})
st.success("¡Venta agregada temporalmente!")
# --- 5. VISUALIZACIÓN TEMPORAL ---
st.divider()
df_compras = pd.DataFrame(st.session_state.compras)
df_ventas = pd.DataFrame(st.session_state.ventas)
col_tabla1, col_tabla2 = st.columns(2)
with col_tabla1:
st.subheader("Registros de Compra (Sin guardar)")
st.dataframe(df_compras, use_container_width=True)
with col_tabla2:
st.subheader("Registros de Venta (Sin guardar)")
st.dataframe(df_ventas, use_container_width=True)
# --- 6. PUSH A GOOGLE SHEETS ---
if st.button("🚀 Hacer Push a Google Sheets", use_container_width=True):
try:
datos_a_subir = []
for row in st.session_state.compras:
datos_a_subir.append(["Compra", row["Tasa"], row["Monto ($)"], row["Total (Bs)"]])
for row in st.session_state.ventas:
datos_a_subir.append(["Venta", row["Tasa"], row["Monto (USDT)"], row["Total (Bs)"]])
if datos_a_subir:
sheet.append_rows(datos_a_subir)
st.success("¡Datos enviados exitosamente!")
st.session_state.compras = []
st.session_state.ventas = []
st.rerun()
else:
st.warning("No hay datos nuevos para subir.")
except Exception as e:
st.error(f"Error al subir a Google Sheets: {e}")
# --- 7. LECTURA DE GOOGLE SHEETS Y CÁLCULO HISTÓRICO ---
st.divider()
st.header("📈 Resumen Histórico y Ganancias")
try:
datos_historicos = sheet.get_all_values()
if len(datos_historicos) > 0:
df_hist = pd.DataFrame(datos_historicos, columns=["Tipo", "Tasa", "Monto", "Total (Bs)"])
df_hist["Tasa"] = pd.to_numeric(df_hist["Tasa"], errors='coerce')
df_hist["Monto"] = pd.to_numeric(df_hist["Monto"], errors='coerce')
df_hist["Total (Bs)"] = pd.to_numeric(df_hist["Total (Bs)"], errors='coerce')
df_hist = df_hist.dropna(subset=['Total (Bs)'])
hist_compras = df_hist[df_hist["Tipo"].str.contains("Compra", case=False, na=False)]
hist_ventas = df_hist[df_hist["Tipo"].str.contains("Venta", case=False, na=False)]
h_total_bs_comprados = hist_compras["Total (Bs)"].sum()
h_total_usd_comprados = hist_compras["Monto"].sum()
h_tasa_prom_compra = h_total_bs_comprados / h_total_usd_comprados if h_total_usd_comprados > 0 else 0
h_total_bs_vendidos = hist_ventas["Total (Bs)"].sum()
h_total_usdt_vendidos = hist_ventas["Monto"].sum()
h_tasa_prom_venta = h_total_bs_vendidos / h_total_usdt_vendidos if h_total_usdt_vendidos > 0 else 0
h_diferencia_bs = h_total_bs_vendidos - h_total_bs_comprados
diferencia_divisas = h_total_usd_comprados - h_total_usdt_vendidos
valor_bs_sobrantes = h_diferencia_bs / h_tasa_prom_venta if h_tasa_prom_venta > 0 else 0
ganancia_estimada_usd = diferencia_divisas + valor_bs_sobrantes
col_m1, col_m2, col_m3, col_m4 = st.columns(4)
col_m1.metric("Total Invertido ($)", f"{h_total_usd_comprados:,.2f}")
col_m2.metric("Total Vendido (USDT)", f"{h_total_usdt_vendidos:,.2f}")
col_m3.metric("Diferencia (Bs)", f"{h_diferencia_bs:,.2f}")
col_m4.metric("Ganancia Neta Estimada (USD)", f"{ganancia_estimada_usd:,.2f}")
st.write(f"**Tasa Promedio Compra:** {h_tasa_prom_compra:,.2f} Bs | **Tasa Promedio Venta:** {h_tasa_prom_venta:,.2f} Bs")
else:
st.info("La hoja de cálculo está vacía o aún no tiene registros válidos.")
except Exception as e:
st.error(f"Error al leer la hoja histórica: {e}")