diff --git a/clase1/edisontana.py b/clase1/edisontana.py new file mode 100644 index 0000000..460857d --- /dev/null +++ b/clase1/edisontana.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# tarea1.py +# +# Copyright 2025 edisontana +# +# Tarea 1. +# Programa que solicita al usuario un número n y visualiza todos los números primos del 1 al n. + +from datetime import datetime + +def esprimo(inumero): + """ + Funcion para saber si un numero es primo. + """ + if inumero <= 1: + False + for i in range( 2, int( inumero ** 0.5) + 1): + if inumero % i == 0: + return False + return True + +def evaluanumeros(n): + listaprimos = [] + icontador = 1 + x = 1 + while True: + if icontador <= n: + if esprimo(x): + listaprimos.append(x) + icontador = icontador + 1 + x = x + 1 + else: + break + print(f"Resultado: Los {n} numeros primos son: ") + print(listaprimos) + + +def visualizafrase(): + texto = "Los buenos equipos incorporan el trabajo en grupo \n a la cultura, creando así los pilares del éxito." + frase = f"{texto:>50}" + texto2 = "Ted Sundquist" + autor = f"{texto2:>50}" + print(frase) + print(autor) + print("") + +def visualizafechaactual(): + print(datetime.now()) + +def muestramenu(opcion): + if opcion == 1: + visualizafrase() + elif opcion == 2: + visualizafechaactual() + else: + quit() + +if __name__ == '__main__': + print("Programa para hallar 'n' numero primos") + print("Realizado por 2025 Edison TANA") + n = int(input("¿Cuantos números primos desea, por favor digite aquí? (numero): ")) + evaluanumeros(n) + print("------------------") + print("Menu interactivo") + print("1. Ver frase motivacional") + print("2. Ver hora actual") + print("3. Salir") + eleccion = int(input("Por favor digite su opcion (1-3): ")) + muestramenu(eleccion) + print("Fin del programa") + + diff --git a/clase1/erika_torres.py b/clase1/erika_torres.py new file mode 100644 index 0000000..61097a8 --- /dev/null +++ b/clase1/erika_torres.py @@ -0,0 +1,53 @@ + + +## 🧪 Ejercicio 1: Números primos + +def es_primo(num): + if num < 2: + return False + for i in range(2, int(num ** 0.5) + 1): + if num % i == 0: + return False + return True + +def mostrar_primos_hasta_n(n): + print(f"Números primos del 1 al {n}:") + for i in range(1, n + 1): + if es_primo(i): + print(i, end=" ") + +# Programa principal +try: + n = int(input("Ingresa un número entero positivo: ")) + if n < 1: + print("Por favor, ingresa un número mayor o igual a 1.") + else: + mostrar_primos_hasta_n(n) +except ValueError: + print("Entrada inválida. Por favor ingresa un número entero.") + +## 🧪 Ejercicio 2: Menú interactivo + +import datetime + +def mostrar_menu(): + print("\n📋 MENÚ PRINCIPAL") + print("1. Mostrar una frase motivacional") + print("2. Mostrar la fecha actual") + print("3. Salir del programa") + +while True: + mostrar_menu() + opcion = input("Elige una opción (1, 2 o 3): ") + + if opcion == "1": + print("\n💬 Frase motivacional:") + print("✨ El éxito es la suma de pequeños esfuerzos repetidos día tras día.") + elif opcion == "2": + fecha_actual = datetime.datetime.now() + print(f"\n📅 Fecha actual: {fecha_actual.strftime('%d/%m/%Y - %H:%M:%S')}") + elif opcion == "3": + print("\n👋 ¡Gracias por usar el programa! Hasta pronto.") + break + else: + print("⚠️ Opción no válida. Por favor, elige 1, 2 o 3.") diff --git a/clase1/jorge_luis_castellanos.py b/clase1/jorge_luis_castellanos.py index 10e390e..6579a30 100644 --- a/clase1/jorge_luis_castellanos.py +++ b/clase1/jorge_luis_castellanos.py @@ -1 +1,54 @@ -print ("Jorge Luis Castellanos") \ No newline at end of file +import datetime + +#Tarea Uno +#____________________________________________________________ +#Ejercicio número 1 +#Determinar si un número ingresado es primo +#____________________________________________________________ + +def numero_primo(numero): + if numero % 2 == 0: + return False + for i in range(3, int(numero ** 0.5) + 1, 2): + if numero % i == 0: + return False + return True + +def numeros_primos(numero): + primos = [] + for i in range(2, numero + 1): + if numero_primo(i): + primos.append(i) + return primos + +#____________________________________________________________ +#Ejercicio número 2 +#Menú interactivo +#____________________________________________________________ + +def menu(): + print("--- Bienvenido al menú interactivo ---") + print("|1| Frase motivacional") + print("|2| Fecha actual") + print("|3| Salir") + opcion = input("Ingrese una opcion: ") + if opcion == "1": + print("🎯 El éxito es la suma de pequeños esfuerzos repetidos día tras día.") + elif opcion == "2": + fecha_actual = print(" 🗓️ La fecha actual es: ", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + else: + print("👋🏼 Fin del programa, Hasta pronto.") + + +if __name__ == "__main__": + + #Ejercicio número 1 + numero = int(input("Ingrese un número mayor a 2: ")) + if numero <= 2: + print("Por favor, ingrese un número mayor a 2.") + else: + primos = numeros_primos(numero) + print(f"Numeros primos hasta {numero}: {primos}") + + #Ejercicio número 2 + menu() \ No newline at end of file diff --git a/clase2/edisontana.py b/clase2/edisontana.py new file mode 100644 index 0000000..1f1a2ed --- /dev/null +++ b/clase2/edisontana.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# tarea2.py +# +# Copyright 2025 edisontana +# +# Tarea 2. +# Ejercicio1: Defina un clase Pais con dos metodos +# Ejercicio2: Listas y diccionarios +# Ejercicio3: Trivia con POO + +from datetime import datetime + +class Pais: + + def __init__(self, nombreES, nombreEN, codigoISOA3): + """ + Crea un constructor + """ + self.nombreES = nombreES + self.nombreEN = nombreEN + self.codigoISOA3 = codigoISOA3 + + def verArea(self, pais): + """ + Visuliza el area superficial del pais + """ + # Diccionario de áreas de países (puedes expandir este diccionario) + self.areas = { + 'ecuador': 256370, + 'colombia': 1141748, + 'peru': 1285216, + 'argentina': 2780400, + 'chile': 756102 + } + + strPais = pais.lower() + if strPais in self.areas: + return self.areas[strPais] + else: + return f"No se encontró información para el país {pais}" + + + def verCapital(self, pais): + """ + Muestra la capital del pais + """ + self.capitales = { + 'ecuador': 'Quito', + 'colombia': 'Bogota', + 'peru': 'Lima', + 'argentina': 'Buenos Aires', + 'chile': 'Santiago' + } + strPais = pais.lower() + if strPais in self.capitales: + return self.capitales[strPais] + else: + return f"No se encontró información para el país {pais}" + +# Ejercicio2: Defina un clase Pais con dos metodos + +class Pelicula: + def __init__(self, anio, nombre, genero): + """ + Constructor de la clase Pelicula + + Args: + anio (int): Año de producción + nombre (str): Nombre de la pelicula + genero (str): Género de la pelicula + """ + self.anio = anio + self.nombre = nombre + self.genero = genero + + def __str__(self): + """ + Representación en cadena de la película + """ + return f"{self.nombre} ({self.anio}) - {self.genero}" + +class PeliculasFavoritas: + def __init__(self): + """ + Constructor de la clase PeliculasFavoritas + """ + self.peliculas = [] + + def agregapelicula(self, anio, nombre, genero): + """ + Agrega una nueva película a la lista + + Args: + anio (int): Año de producción + nombre (str): Nombre de la pelicula + genero (str): Género de la pelicula + """ + nuevapelicula = Pelicula(anio, nombre, genero) + self.peliculas.append(nuevapelicula) + print(f"Se agregó {nombre}") + + def buscaporanio(self, anio): + """ + Busca una pelicula por su año de producción + + Args: + anio (int): Año a buscar + + Returns: + Pelicula or str: Pelicula encontrada o mensaje de no encontrado + """ + for pelicula in self.peliculas: + if pelicula.anio == anio: + return pelicula + return f"No se encontró pelicula en el {anio}" + + def muestratodaspeliculas(self): + """ + Muestra todas las peliculas en la lista + """ + if not self.peliculas: + print("El catálogo está vacío.") + return 0 + + print("\n--- Catálogo de Películas ---") + for pelicula in self.peliculas: + print(pelicula) + +def main(): + """ + Función principal para demostrar el catálogo de películas + """ + # Crear instancia del catálogo + favorita1 = PeliculasFavoritas() + + # Agregar películas al catálogo + favorita1.agregapelicula(2010, "Inception", "Ciencia Ficción") + favorita1.agregapelicula(1972, "El Padrino", "Drama") + favorita1.agregapelicula(1999, "Matrix", "Ciencia Ficción") + + # Mostrar películas + favorita1.muestratodaspeliculas() + +# Ejercicio3: Defina un clase Pais con dos metodos +class Pregunta: + + def __init__(self, enunciado, opciones, respuesta): + """ + Constructor de la clase Pregunta + + Args: + enunciado (str): cadena de texto del enunciado + opciones (int): numero de opcion + respuesta (int): respuesta correcta + """ + self.enunciado = enunciado + self.opciones = opciones + self.respuesta = respuesta + + def __str__(self): + """ + Representación en cadena de la pregunta + """ + return f"{self.enunciado}" + + def visualizaopciones(self): + """ + Muestra las opciones de respuesta + """ + print(self.enunciado) + for i, opcion in enumerate(self.opciones, 1): + print(f"{i}. {opcion}") + + def verificarespuesta(self, respuesta_usuario): + """ + Verifica si la respuesta del usuario es correcta + + Args: + respuesta_usuario (int): respuesta seleccionada por el usuario + + Returns: + bool: True si la respuesta es correcta, False en caso contrario + """ + # Ajustar el índice para que coincida con la lista (restar 1) + return respuesta_usuario - 1 == self.respuesta + + def obtienerespuestacorrecta(self): + """ + Devuelve la respuesta correcta + + Returns: + str: Opción correcta + """ + return self.opciones[self.respuesta] + +# Ejemplo de pregunta +def main3(): + # Crear una pregunta + pregunta1 = Pregunta( + "¿Cuál es la capital de Francia?", + ["Londres", "Berlín", "París", "Madrid"], + 2 # París es la respuesta correcta (índice 2) + ) + + # Mostrar la pregunta y sus opciones + pregunta1.visualizaopciones() + + # Solicitar respuesta del usuario + try: + respuestausuario = int(input("^.^ Ingrese el número de su respuesta: ")) + + # Verificar la respuesta + if pregunta1.verificarespuesta(respuestausuario): + print("¡Respuesta correcta!") + else: + print(f"Respuesta incorrecta. La respuesta correcta es: {pregunta1.obtienerespuestacorrecta()}") + + except ValueError: + print("Por favor, ingrese un número válido.") + +if __name__ == '__main__': + + print("Programa de la Tarea 2") + print("Realizado por 2025 Edison TANA") + print("Enunciado 1") + pais1 = Pais('Ecuador','Ecuador','ECU') + pais2 = Pais('Colombia','Colombia','COL') + print(f" >> Pais: {pais1.nombreES}") + print(pais1.verCapital(pais1.nombreES)) + print(f"{pais1.verArea(pais1.nombreES)} km²") + print(f" >> Pais: {pais2.nombreES}") + print(pais2.verCapital(pais2.nombreES)) + print(f"{pais2.verArea(pais2.nombreES)} km²") + print("Enunciado 2") + main() + print("Enunciado 3") + main3() + print("Fin del programa") diff --git a/clase2/erika_torres.py b/clase2/erika_torres.py new file mode 100644 index 0000000..321787d --- /dev/null +++ b/clase2/erika_torres.py @@ -0,0 +1,85 @@ +## 🧪 Ejercicio 1: Objetos + +class Bicicleta: + """ + Clase Bicicleta: + Representa una bicicleta con atributos básicos y métodos para simular su uso. + """ + def __init__(self, marca, tipo, color, velocidad_max): + self.marca = marca + self.tipo = tipo # Montaña, Ruta, Urbana, etc. + self.color = color + self.velocidad_max = velocidad_max + self.velocidad_actual = 0 + + def pedalear(self): + if self.velocidad_actual < self.velocidad_max: + self.velocidad_actual += 5 + print(f"Pedaleando... 🚴 Velocidad actual: {self.velocidad_actual} km/h") + else: + print("🚨 Has alcanzado la velocidad máxima.") + + def frenar(self): + if self.velocidad_actual > 0: + self.velocidad_actual -= 5 + print(f"Frenando... ⚠️ Velocidad actual: {self.velocidad_actual} km/h") + else: + print("La bicicleta ya está detenida.") + +# Crear objeto bicicleta +mi_bici = Bicicleta("Giant", "Montaña", "Roja", 25) + +# Usar métodos +mi_bici.pedalear() +mi_bici.pedalear() +mi_bici.frenar() + +## 🧪 Ejercicio 2: Listas y diccionarios + +# Lista de mis 3 películas favoritas +peliculas = ["El Origen", "Coco", "Intensamente"] + +# Diccionario con información de una de ellas +pelicula_favorita = { + "nombre": "El Origen", + "género": "Ciencia Ficción", + "año": 2010 +} + +# Operaciones +print("🎬 Mis películas favoritas son:", peliculas) +print("🎥 Detalles de la favorita:") +print("Nombre:", pelicula_favorita["nombre"]) +print("Género:", pelicula_favorita["género"]) +print("Año:", pelicula_favorita["año"]) + +## 🧪 Ejercicio 3: Trivia con PO + +class Pregunta: + def __init__(self, enunciado, opciones, respuesta_correcta): + self.enunciado = enunciado + self.opciones = opciones + self.respuesta_correcta = respuesta_correcta + + def mostrar(self): + print("❓", self.enunciado) + for i, opcion in enumerate(self.opciones, 1): + print(f"{i}. {opcion}") + + def responder(self, seleccion): + if self.opciones[seleccion - 1] == self.respuesta_correcta: + print("✅ ¡Correcto!") + else: + print(f"❌ Incorrecto. La respuesta era: {self.respuesta_correcta}") + +# Crear pregunta +pregunta1 = Pregunta( + "¿Cuál es la capital de Ecuador?", + ["Guayaquil", "Quito", "Cuenca"], + "Quito" +) + +# Mostrar y pedir respuesta +pregunta1.mostrar() +numero = int(input("Ingresa el número de tu respuesta: ")) +pregunta1.responder(numero) diff --git a/clase2/jorge_luis_castellanos.py b/clase2/jorge_luis_castellanos.py new file mode 100644 index 0000000..4fcd00d --- /dev/null +++ b/clase2/jorge_luis_castellanos.py @@ -0,0 +1,111 @@ +#Tarea Dos +#____________________________________________________________ +#Ejercicio número 1 +#Ejercicios de tuplas, listas y diccionarios +#____________________________________________________________ + +class automovil: + def __init__(self): + self.marca = "" + self.modelo = "" + self.anio = "" + self.color = "" + + def __init__(self,marca,modelo,anio,color): + self.marca = marca + self.modelo = modelo + self.anio = anio + self.color = color + + def informacion(self): + print(f"Marca: {self.marca} Modelo: {self.modelo} Año: {self.anio} Color: {self.color}") + + def aceleracion(self): + print(f"El auto {self.marca} {self.modelo}, tiene un tiempo de aceleracion de 5 segundos de 0/100 Km") + + def cantidad_pasajeros(self): + print(f"El auto {self.marca} {self.modelo}, tiene la capacidad de 5 pasajeros") + + def sonido(self): + print(f"El auto {self.marca} {self.modelo} posee android car y Apple Car, con Spotify") + + def seguridad(self): + print(f"El auto {self.marca} {self.modelo} posee camaras 360° y graba todo el recorrido del viaje") + +#____________________________________________________________ +#Ejercicio número 2 +#Creación de un juego de trivia +#____________________________________________________________ +class Pregunta: + opciones = [] + def __init__(self,pregunta,respuesta,opciones): + self.pregunta = pregunta + self.opciones = list(opciones) + self.respuesta = respuesta + + def mostrar_pregunta(self): + print(f" {self.pregunta} : ") + indice = 1 + for opcion in self.opciones: + print(f" {indice} {opcion}") + indice += 1 + + def validar_respuesta(self,respuesta_usuario): + if self.respuesta == respuesta_usuario: + return True + else: + return False + + +if __name__ == "__main__": + + #Ejercicio número 1 + print("Caracteristicas de Automovil") + automovil = automovil("Mazda","CX-30","2025","rojo") + automovil.informacion() + automovil.aceleracion() + automovil.cantidad_pasajeros() + automovil.sonido() + automovil.seguridad() + print("\n") + + print("Listas y Diccionarios") + pelicula_1 = {"Nombre":"Lord of the rings : La comunidad del anillo","genero":"acción","Anio":2001} + pelicula_2 = {"Nombre":"Lord of the rings : Las dos torres","genero":"acción","Anio":2002} + pelicula_3 = {"Nombre":"Lord of the rings : El retorno del rey","genero":"drama","Anio":2023} + + Listado = [pelicula_1, pelicula_2, pelicula_3] + + for pelicula in Listado: + print(pelicula) + + pelicula_3["genero"]="accion" + pelicula_3["Anio"] = 2003 + + pelicula_4 = {"Nombre":"El hobbit : Un viaje inesperado","genero":"accion","Anio":2012} + + Listado.append(pelicula_4) + Listado.remove(pelicula_3) + + print("\n") + print("Listado despues de eliminar pelicula 3 y posicionar pelicula 4") + print("\n") + + for pelicula in Listado: + print(pelicula) + + print("\n") + + + #Ejercicio número 2 + print("Trivia") + pregunta = Pregunta("Cuál es la primera pelicula de Lord of the rings", 2, ["EL retorno del rey","La comunindad del anillo","Las dos torres","Un viaje inesperado"]) + + pregunta.mostrar_pregunta() + + respuesta_correcta = int(input("Su respuesta es (ingrese el número correspondiente):")) + + if pregunta.validar_respuesta(respuesta_correcta): + print("Respuesta correcta") + else: + print("Respuesta Incorrecta") \ No newline at end of file diff --git a/clase2/valeria_ramos.py b/clase2/valeria_ramos.py new file mode 100644 index 0000000..754232f --- /dev/null +++ b/clase2/valeria_ramos.py @@ -0,0 +1,112 @@ + +# # Objeto Televisión +# """ +# Estudiante: +# - edad +# - año +# - nota +# Metodos: +# - información +# - aprobar +# """ + +#EJERCICIO 1 OBJETOS +# ¿Qué es un objeto? +# Un objeto es como una cosa o persona en la vida real, pero en programación. Tiene datos que lo describen y cosas que puede hacer. + +# ¿Qué hace el objeto Estudiante? +# Este objeto representa a un estudiante, con su nombre, edad, nota y curso. Además, puede mostrar su información y decir si aprobó o no. + +# ¿Por qué elegí Estudiante? +# Porque es fácil de entender y es algo que todos conocemos. Así puedo practicar cómo guardar información y usarla para hacer cosas, como decir si el estudiante pasó la materia. + +class Estudiante: + def __init__(self, nombre, edad, nota, curso): + self.nombre = nombre + self.edad = edad + self.nota = nota + self.curso = curso + + def informacion (self): + print (f"Nombre:{nombre}") + print (f"Edad:{edad}") + print (f"Nota:{nota}") + print (f"curso:{curso}") + + def aprobar (self): + if self.nota>=7: + print(f"{self.nombre} Felicidades! aprobaste.") + else: + print(f"{self.nombre} No aprobaste." ) + +#se pide los datos +nombre = input ("Ingresa tu nombre:") +edad = int ( input ("Ingresa tu edad:")) +nota = float(input("Ingresa tu nota:")) +curso = input("Ingrea tu curso:") + + +#creación de objeto +est1 = Estudiante(nombre, edad, nota, curso) + +#uso de métodos +est1.informacion() +est1.aprobar() + +# Ejercicio2: LISTAS Y DICCIONARIOS +#lista +pelis_fav = ["voces inocentes", "crepusculo", "Yo antes de ti"] + +print(f"Mi pelis favoritas son: {pelis_fav}") + +#dicionario + +peliculas = [ + {"nombre": "Voces Inocentes","genero": "Drama", "año": 2004 }, + {"nombre":"Crepúsculo", "genero": "Fantasía", "año": 2000}, + {"nombre": "Yo antes de ti", "genero":"Romance", "año":2005} +] + +for peli in peliculas: + print("Nombre:", peli["nombre"]) + print("Género:", peli["genero"]) + print("Año:", peli["año"]) + print("---") + + +#EJERCICIO 3: TRIVIA CON PPO + +class Pregunta: + def __init__(self, enunciado, opciones, respuesta): + self.enunciado = enunciado + self.opciones = opciones + self.respuesta = respuesta + + + def mostrar(self): + print(self.enunciado) + for i, opcion in enumerate(self.opciones, 1): + print(f"{i}. {opcion}") + + def verificar(self, respuesta): + return respuesta == self.respuesta + + + +# Objectos de clase pregunta +p1 = Pregunta("¿Cuál es la capital de Francia?", ["Madrid", "París", "Londres"], 2) +p2 = Pregunta("¿Qué planeta es conocido como el Planeta Rojo?", ["Venus", "Marte", "Júpiter"], 2) +p3 = Pregunta("¿Cuántos continentes hay en el mundo?", ["5", "6", "7", "8"], 3) + +# Los ponemos en una lista +lista_preguntas = [p1, p2, p3] + +# Recorremos la lista para jugar la trivia +for pregunta in lista_preguntas: + pregunta.mostrar() + respuesta = int(input("Escribe el número de la opción correcta: ")) + if pregunta.verificar(respuesta): + print("¡Correcto!\n") + else: + print(f"Incorrecto. La respuesta correcta era la opción {pregunta.respuesta}\n") + \ No newline at end of file diff --git a/clase3/flask_chistes/erika_torres.py b/clase3/flask_chistes/erika_torres.py new file mode 100644 index 0000000..20c0fe7 --- /dev/null +++ b/clase3/flask_chistes/erika_torres.py @@ -0,0 +1,61 @@ +import requests + +URL = "https://fakestoreapi.com" + +def deserialize_json(json_data): + """ + Deserialize JSON data into a Python object. + """ + try: + return json_data.json() + except ValueError as e: + print(f"Error deserializing JSON: {e}") + return None + +def serialize_json(data): + """ + Serialize a Python object into JSON format. + """ + try: + return json.dumps(data, indent=2) + except TypeError as e: + print(f"Error serializing to JSON: {e}") + return None + +def get_products(): + url = f"{URL}/products" + response = requests.get(url) + if response.status_code == 200: + return response.json() + else: + return None + +def get_product_by_id(product_id): + url = f"{URL}/products/{product_id}" + response = requests.get(url) + if response.status_code == 200: + return response.json() + else: + return None + +if __name__ == "__main__": + products = get_products() + for product in products: + print(f"Product ID: {product['id']}") + print(f"Title: {product['title']}") + print(f"Price: {product['price']}") + print(f"Description: {product['description']}") + print(f"Imagen: {product['image']}") + print("-" * 20) + + product = get_product_by_id(15) + print(f"Product ID: {product['id']}") + print(f"Title: {product['title']}") + print(f"Price: {product['price']}") + print(f"Description: {product['description']}") + print(f"Imagen: {product['image']}") + print("-" * 20) + + objserialize = serialize_json(products) + print(f"Serialized JSON: {objserialize}") + \ No newline at end of file diff --git a/clase3/jorge_luis_castellanos/jokes/app.py b/clase3/jorge_luis_castellanos/jokes/app.py new file mode 100644 index 0000000..e81e3a6 --- /dev/null +++ b/clase3/jorge_luis_castellanos/jokes/app.py @@ -0,0 +1,27 @@ +import requests +from flask import Flask, render_template + +app = Flask(__name__) + +@app.route('/') +def chiste(): + chiste = {} + error = None + + try: + response = requests.get("https://official-joke-api.appspot.com/jokes/random") + if response.status_code == 200: + chiste = response.json() + else: + error = "No se pudo obtener un chiste. Intenta de nuevo." + except Exception as e: + error = f"Error al conectarse a la API: {e}" + + return render_template("index.html", chiste=chiste, error=error) + +@app.route('/salir') +def salir(): + return "

👋 ¡Gracias por reír con nosotros! Hasta la próxima.

" + +if __name__ == '__main__': + app.run(debug=True) diff --git a/clase3/jorge_luis_castellanos/jokes/templates/index.html b/clase3/jorge_luis_castellanos/jokes/templates/index.html new file mode 100644 index 0000000..ae97246 --- /dev/null +++ b/clase3/jorge_luis_castellanos/jokes/templates/index.html @@ -0,0 +1,64 @@ + + + + + + 😂 Chiste del Día + + + + + + + + + + + +
+
+
+
+
😂
+

Chiste del Día

+ + {% if error %} +
{{ error }}
+ {% else %} +

{{ chiste.setup }}

+

{{ chiste.punchline }}

+ {% endif %} + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/clase3/jorge_luis_castellanos/pokemon/app.py b/clase3/jorge_luis_castellanos/pokemon/app.py new file mode 100644 index 0000000..94dbb0f --- /dev/null +++ b/clase3/jorge_luis_castellanos/pokemon/app.py @@ -0,0 +1,54 @@ +import math + +import requests +from flask import Flask, render_template, request + +app = Flask(__name__) + +@app.route('/') +def index(): + page = int(request.args.get('page', 1)) + search = request.args.get('search', '').lower() + per_page = 9 + total_pokemons = 100 + offset = (page - 1) * per_page + pokemons = [] + + if search: + data = get_pokemon(search) + if data: + pokemons.append(data) + total_pages = 1 + else: + url = f'https://pokeapi.co/api/v2/pokemon?offset={offset}&limit={per_page}' + response = requests.get(url) + results = response.json().get('results', []) + for item in results: + poke_data = get_pokemon(item['name']) + if poke_data: + pokemons.append(poke_data) + total_pages = math.ceil(total_pokemons / per_page) + + return render_template('index.html', + pokemon_list=pokemons, + search_query=search, + page=page, + total_pages=total_pages) + +def get_pokemon(name): + url = f'https://pokeapi.co/api/v2/pokemon/{name}' + response = requests.get(url) + if response.status_code == 200: + data = response.json() + return { + 'name': data['name'].capitalize(), + 'image_front': data['sprites']['front_default'], + 'image_back': data['sprites']['back_default'], + 'height': data['height'], + 'weight': data['weight'], + 'abilities': [a['ability']['name'] for a in data['abilities']] + } + return None + +if __name__ == '__main__': + app.run(debug=True) diff --git a/clase3/jorge_luis_castellanos/pokemon/templates/index.html b/clase3/jorge_luis_castellanos/pokemon/templates/index.html new file mode 100644 index 0000000..a9d1ea8 --- /dev/null +++ b/clase3/jorge_luis_castellanos/pokemon/templates/index.html @@ -0,0 +1,59 @@ + + + + + + + Pokédex Flask + + + +
+

POKEAPI

+ +
+
+ + +
+
+ + {% if pokemon_list %} +
+ {% for pokemon in pokemon_list %} +
+
+
+ Frente + Atrás +
+
+
{{ pokemon.name }}
+

+ Altura: {{ pokemon.height }}
+ Peso: {{ pokemon.weight }}
+ Habilidades: {{ pokemon.abilities | join(', ') }} +

+
+
+
+ {% endfor %} +
+ + + + + {% else %} +

No se encontraron Pokémon.

+ {% endif %} +
+ + diff --git a/clase3/valeria_ramos/app.py b/clase3/valeria_ramos/app.py new file mode 100644 index 0000000..04e28d6 --- /dev/null +++ b/clase3/valeria_ramos/app.py @@ -0,0 +1,18 @@ +from flask import Flask, render_template +import requests + +app = Flask(__name__) + +@app.route('/') +def mostrar_chiste(): + url = "https://official-joke-api.appspot.com/jokes/random" + try: + response = requests.get(url) + response.raise_for_status() + data = response.json() + return render_template('index.html', setup=data['setup'], punchline=data['punchline']) + except Exception as e: + return f"Ocurrió un error: {e}" + +if __name__ == '__main__': + app.run(debug=True) diff --git a/clase3/valeria_ramos/templates/index.html b/clase3/valeria_ramos/templates/index.html new file mode 100644 index 0000000..f82137e --- /dev/null +++ b/clase3/valeria_ramos/templates/index.html @@ -0,0 +1,19 @@ + + + + Chiste Random + + + +
+

😂 Chiste Random

+
+

Chiste: {{ setup }}

+

Respuesta: {{ punchline }}

+
+ +
+
+
+ + diff --git a/clase3/valeria_ramos/valeria_ramos.py b/clase3/valeria_ramos/valeria_ramos.py new file mode 100644 index 0000000..3bcabb1 --- /dev/null +++ b/clase3/valeria_ramos/valeria_ramos.py @@ -0,0 +1,41 @@ +import requests + + +limit = 9 +offset = 0 + +while True: + url = f"https://pokeapi.co/api/v2/pokemon?limit={limit}&offset={offset}" + response = requests.get (url) + + if response.status_code == 200: + data = response.json() + print (f"Mostrando Pokemmón {offset+1} a {offset+limit}") + for poke in data ['results']: + print ("-", poke['name']) + else: + print ("Error al obtener datos.") + break + option = input ("Ver más.. (s/n):") + if option.lower() == 's': + offset += limit + else: + break +nombre = input ("\n Ingresa el nombre del Pokemón para ver sus datos:") + +url_pokemon = f"https://pokeapi.co/api/v2/pokemon/{nombre.lower()}" +resp_poke = requests.get(url_pokemon) + +if resp_poke.status_code == 200: + datos = resp_poke.json() + print("\nDatos del Pokémon:") + print("ID:", datos['id']) + print("Nombre:", datos['name']) + tipos = [t['type']['name'] for t in datos['types']] + print("Tipos:", tipos) + print("Altura:", datos['height']) + print("Imagen URL:", datos['sprites']['front_default']) + print("Sprite:", datos['sprites']['front_default']) +else: + print("Pokémon no encontrado.") + \ No newline at end of file diff --git a/entorno/Scripts/dotenv.exe b/entorno/Scripts/dotenv.exe new file mode 100644 index 0000000..793faec Binary files /dev/null and b/entorno/Scripts/dotenv.exe differ diff --git a/entorno/Scripts/pyrsa-decrypt.exe b/entorno/Scripts/pyrsa-decrypt.exe new file mode 100644 index 0000000..340d43f Binary files /dev/null and b/entorno/Scripts/pyrsa-decrypt.exe differ diff --git a/entorno/Scripts/pyrsa-encrypt.exe b/entorno/Scripts/pyrsa-encrypt.exe new file mode 100644 index 0000000..3e6ed2c Binary files /dev/null and b/entorno/Scripts/pyrsa-encrypt.exe differ diff --git a/entorno/Scripts/pyrsa-keygen.exe b/entorno/Scripts/pyrsa-keygen.exe new file mode 100644 index 0000000..bb4eacb Binary files /dev/null and b/entorno/Scripts/pyrsa-keygen.exe differ diff --git a/entorno/Scripts/pyrsa-priv2pub.exe b/entorno/Scripts/pyrsa-priv2pub.exe new file mode 100644 index 0000000..3c36e3a Binary files /dev/null and b/entorno/Scripts/pyrsa-priv2pub.exe differ diff --git a/entorno/Scripts/pyrsa-sign.exe b/entorno/Scripts/pyrsa-sign.exe new file mode 100644 index 0000000..61596ed Binary files /dev/null and b/entorno/Scripts/pyrsa-sign.exe differ diff --git a/entorno/Scripts/pyrsa-verify.exe b/entorno/Scripts/pyrsa-verify.exe new file mode 100644 index 0000000..601e2fc Binary files /dev/null and b/entorno/Scripts/pyrsa-verify.exe differ diff --git a/entorno/Scripts/tqdm.exe b/entorno/Scripts/tqdm.exe new file mode 100644 index 0000000..c743393 Binary files /dev/null and b/entorno/Scripts/tqdm.exe differ diff --git a/proyecto/edisontana/README.md b/proyecto/edisontana/README.md new file mode 100644 index 0000000..6a953f4 --- /dev/null +++ b/proyecto/edisontana/README.md @@ -0,0 +1,20 @@ + +--- + +# Proyecto del bot en telegram + +Por Edison TANA +Archivo: mitelegrambotTopograf.py + +## Licencia + +[![CC BY-SA 4.0][cc-by-sa-shield]][cc-by-sa] + +Este trabajo está licenciado bajo +[Creative Commons Attribution-ShareAlike 4.0 International License][cc-by-sa] y GNU GPL v3 + +[![CC BY-SA 4.0][cc-by-sa-image]][cc-by-sa] + +[cc-by-sa]: http://creativecommons.org/licenses/by-sa/4.0/ +[cc-by-sa-image]: https://licensebuttons.net/l/by-sa/4.0/88x31.png +[cc-by-sa-shield]: https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg \ No newline at end of file diff --git a/proyecto/edisontana/proyectobot/mitelegrambotTopograf.py b/proyecto/edisontana/proyectobot/mitelegrambotTopograf.py new file mode 100644 index 0000000..e6ecf94 --- /dev/null +++ b/proyecto/edisontana/proyectobot/mitelegrambotTopograf.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# mitelegrambotTopograf.py +# +# Copyright 2025 Edison TANA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# +# Desarrollado en GNU_Linux + + +from telegram import Update, ReplyKeyboardMarkup +from telegram.ext import ( + ApplicationBuilder, CommandHandler, MessageHandler, ContextTypes, + filters, ConversationHandler +) +from mailjet_rest import Client +import requests +import os +import re +import sqlite3 +import logging +from datetime import datetime +from dotenv import load_dotenv + +load_dotenv() + +BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") +api_key = os.getenv('MAILJET_API_KEY') +api_secret = os.getenv('MAILJET_SECRET_KEY') + +correoremite = os.getenv('EMAIL_REMITENTE') +correodestino = os.getenv('EMAIL_DESTINATARIO') + + +MAIN_MENU, FIRST_MENU, SECOND_MENU, THIRD_MENU = range(4) + +SERVICIOS = { + "1. 🗺️ Modelos de terreno en 3D": 100, + "2. 📏 Nivelaciones y replanteos": 12, + "3. 🌎 Levantamientos topograficos": 180, + "4. 👨 Asesoría topografica": 60 +} + +conn = sqlite3.connect("mibase.db", check_same_thread=False) +cursor = conn.cursor() + +cursor.execute(""" +CREATE TABLE IF NOT EXISTS chat_data ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, + username TEXT, + servicio TEXT, + message_id INTEGER, + timestamp TEXT +) +""") +conn.commit() + +def guardar_interaccion(update: Update): + user = update.effective_user + username = user.username or "Sin username" + message_id = update.message.message_id + servicio = update.message.text + timestamp = datetime.now().isoformat() + + cursor.execute(""" + INSERT INTO chat_data (user_id, message_id, username, servicio, timestamp) + VALUES (?, ?, ?, ?, ?) + """, (user.id, username, servicio, message_id, timestamp)) + conn.commit() + +# Extraer correo desde un texto +def extraer_email(texto): + match = re.search(r'[\w\.-]+@[\w\.-]+\.\w+', texto) + return match.group(0) if match else None + +def enviarcorreos(context, correodestino, asunto, contenido): + + mailjet = Client(auth=(api_key, api_secret), version='v3.1') + data = { + 'Messages': [ + { + "From": { + "Email": correoremite, # Remove $ and use variable directly + "Name": "Info EuatorTopografia" + }, + "To": [ + { + "Email": correodestino, # Remove $ and use variable directly + "Name": "Cliente de equatortopografia " + } + ], + "Subject": asunto, + "TextPart": "Saludos desde Topografia!", + "HTMLPart": f""" +

Estimado usuario, bienvenido a EquatorTopografia!


Un gusto conectar con usted! +
+

Usted ha elegido el servicio de:

+
    +
  • +

    {context.user_data['servicio']}

    +
  • +
  • Su detalle es {context.user_data['datos']}
  • +
  • Su costo es ${SERVICIOS[context.user_data['servicio']]}
  • +
+
+ Gracias por escribirnos, hasta pronto. +
+

Más servicios

+
+
    +
  1. Modelos de terreno en 3D
  2. +
  3. Levantamientos topograficos
  4. +
  5. +

    Nivelaciones y replanteos con precision topografica

    +
  6. +
  7. +

    Georeferenciaciones

    +
  8. +
  9. +

    Digitalización topografica

    +
  10. +
+
+
+

Contacta por telegram con nuestro asesor en t.me/leosAcadUIO

+ """ + } + ] + } + + result = mailjet.send.create(data=data) + print(result.status_code) + print('Ok') + + +# Inicio del bot +async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): + mensaje = ( + """ + Hola. Buen día \n 🌟 Bienvenido/a a AsistenteBot! (@academicobot) 🌟.\n + ______________________________________ + < Te ayudamos en soporte y asesoría de > + ----------------------------------------------------------------------- + + A continuacion elige un ítem de la lista: + """ + ) + keyboard = [[opcion] for opcion in SERVICIOS.keys()] + await update.message.reply_text( + mensaje, + reply_markup=ReplyKeyboardMarkup(keyboard, resize_keyboard=True, one_time_keyboard=True), + parse_mode="Markdown" + ) + guardar_interaccion(update) + return MAIN_MENU + +# Selección del servicio +async def seleccionar_servicio(update: Update, context: ContextTypes.DEFAULT_TYPE): + servicio = update.message.text.strip() + if servicio in SERVICIOS: + context.user_data["servicio"] = servicio + await update.message.reply_text( + f"📝 Has seleccionado *{servicio}*.\n\nPor favor, digita su:\n1. Nombre completo\n2. Correo electrónico\n3. Una breve detalle de su caso:", + parse_mode="Markdown" + ) + guardar_interaccion(update) + return FIRST_MENU + else: + await update.message.reply_text("Opción inválida. Selecciona un servicio del menú.") + return await start(update, context) + + +# Recolección de datos +async def recibir_datos(update: Update, context: ContextTypes.DEFAULT_TYPE): + texto = update.message.text.strip() + email = extraer_email(texto) + if not email: + await update.message.reply_text( + "Se encontró un error.\n De nuevo ingrese su informacion de acuerdo a este formato:\n\n`Nombre - correo@ejemplo.com - detalle`", + parse_mode="Markdown" + ) + guardar_interaccion(update) + return FIRST_MENU + + context.user_data["datos"] = texto + keyboard = [["Sí", "No"]] + await update.message.reply_text( + " Autorizo a EquatorTopografia a verificar la autenticidad de la información proporcionada y utilizarla para fines informativos. Entiendo que mis datos serán tratados conforme a la Ley de Protección de Datos Personales de EC.: \n SI / NO", + reply_markup=ReplyKeyboardMarkup(keyboard, resize_keyboard=True, one_time_keyboard=True) + ) + guardar_interaccion(update) + return SECOND_MENU + +async def autorizacion(update: Update, context: ContextTypes.DEFAULT_TYPE): + respuesta = update.message.text.lower() + # Fix: Remove redundant 'in respuesta' checks + if "si" in respuesta or "sí" in respuesta: + servicio = context.user_data["servicio"] + precio = SERVICIOS[servicio] + keyboard = [["✅ Confirmar", "❌ Cancelar"]] + await update.message.reply_text( + f"El *{servicio}* tiene un costo de *${precio}*.\n\n¿Deseas confirmar el pedido?\n Confirmar / Cancelar", + reply_markup=ReplyKeyboardMarkup(keyboard, resize_keyboard=True, one_time_keyboard=True), + parse_mode="Markdown" + ) + guardar_interaccion(update) + return THIRD_MENU + elif "no" in respuesta: + await update.message.reply_text("No podemos continuar sin tu autorización. Escribe /start para comenzar de nuevo.") + return ConversationHandler.END + else: + await update.message.reply_text("Respuesta inválida. Selecciona *Sí* o *No* desde el menú.") + return SECOND_MENU + +async def confirmar(update: Update, context: ContextTypes.DEFAULT_TYPE): + texto = update.message.text.lower() + guardar_interaccion(update) + # A + if "confirmar" in texto: + servicio = context.user_data["servicio"] + detalle = context.user_data["datos"] + precio = SERVICIOS[servicio] + correo = extraer_email(detalle) + correodestinos = correo + + mensaje = ( + f"*Gracias por tu pedido!*\n\n" + f"*Servicio:* {servicio}\n" + f"*Detalle:* {detalle}\n" + f"*Precio:* ${precio}\n\n" + "Nos pondremos en contacto contigo pronto. 📧" + ) + + # Optional: Add logging instead of print statements + logging.info(f"Email: {detalle}, Precio: {precio}, Correo: {correo}") + logging.info(f"Mensaje: {mensaje}") + + if correo: + try: + enviado = enviarcorreos(context, correodestinos, ":) Info sobre cotizacion para "+correo, mensaje) + await update.message.reply_text("Correo enviado exitosamente.") + except Exception as e: + logging.error(f"Error enviando correo: {e}") + await update.message.reply_text("Hubo un problema al enviar el correo.") + else: + await update.message.reply_text("Correo NO enviado") + + await update.message.reply_text("¿Requieres cotizarotro servicio? Digita /start para volver al menú principal") + return ConversationHandler.END + elif "cancelar" in texto or texto == "❌": + await update.message.reply_text("Servicio cancelado. Si deseas iniciar de nuevo, escribe /start.") + return ConversationHandler.END + else: + await update.message.reply_text("Respuesta inválida. Selecciona *Confirmar* o *Cancelar* desde el menú.") + return THIRD_MENU # Fix: Return to THIRD_MENU instead of MAIN_MENU + + + +# Mi funcion pincipal +def main(): + app = ApplicationBuilder().token(BOT_TOKEN).build() + + conv_handler = ConversationHandler( + entry_points=[CommandHandler("start", start)], + states={ + MAIN_MENU: [MessageHandler(filters.TEXT & ~filters.COMMAND, seleccionar_servicio)], + FIRST_MENU: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_datos)], + SECOND_MENU: [MessageHandler(filters.TEXT & ~filters.COMMAND, autorizacion)], + THIRD_MENU: [MessageHandler(filters.TEXT & ~filters.COMMAND, confirmar)], + }, + fallbacks=[], + ) + + app.add_handler(conv_handler) + print("mi bot ejecutandose") + app.run_polling() + +if __name__ == "__main__": + main() diff --git a/proyecto/jorge_luis_castellanos/app.py b/proyecto/jorge_luis_castellanos/app.py new file mode 100644 index 0000000..30ac87c --- /dev/null +++ b/proyecto/jorge_luis_castellanos/app.py @@ -0,0 +1,59 @@ +from telegram import Update, ReplyKeyboardMarkup +from telegram.ext import ( + ApplicationBuilder, CommandHandler, MessageHandler, ContextTypes, + filters, ConversationHandler +) +from mailjet_rest import Client +import requests +import os +import re +import sqlite3 +from datetime import datetime +from dotenv import load_dotenv +from telebot import TeleBot, types +import datetime + +load_dotenv() + +BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") +bot = TeleBot(BOT_TOKEN) + +# Estado temporal de los usuarios +user_data = {} + +@bot.message_handler(commands=['start']) +def start(message): + bot.send_message(message.chat.id, "Hola...\nTe saluda Terra Habitat Bienes Raices\nPor favor, escribe tu nombre completo:") + bot.register_next_step_handler(message, process_nombre) + +def process_nombre(message): + user_data[message.chat.id] = {"nombre": message.text} + + bot.send_message(message.chat.id, "¿Qué servicio deseas? \n (Compra - Venta - Alquiler - Avalúo - Administración - Otro Servicio)") + bot.register_next_step_handler(message, process_servicio) + +def process_servicio(message): + user_data[message.chat.id]["servicio"] = message.text + + bot.send_message(message.chat.id, "Ayudame con tu número de teléfono") + bot.register_next_step_handler(message, process_telefono) + +def process_telefono(message): + user_data[message.chat.id]["telefono"] = message.text + + bot.send_message(message.chat.id, "Ayudame con tu correo electrónico") + bot.register_next_step_handler(message, cita) + +def cita(message): + user_data[message.chat.id]["time"] = message.text + data = user_data[message.chat.id] + + bot.send_message(message.chat.id, "🔹¡Tu cita ha sido registrada!\nUn Asesor te atendera de forma presonalizada") + resumen = f"🗓️*Resumen de tu cita:*\nNombre: {data['nombre']}\nServicio: {data['servicio']}\nTelefono: {data['telefono']}" + + bot.send_message(message.chat.id, resumen, parse_mode='Markdown') + + +if __name__ == "__main__": + print("Bot ejecutándose...") + bot.infinity_polling() \ No newline at end of file diff --git a/proyecto/jorge_luis_castellanos/readme.txt b/proyecto/jorge_luis_castellanos/readme.txt new file mode 100644 index 0000000..611d11c --- /dev/null +++ b/proyecto/jorge_luis_castellanos/readme.txt @@ -0,0 +1,5 @@ +Bot de Telegram + +Este bot crea una cita para contacto automatico con la Api de Telegram para la empresa de bienes raices Terra Habitat +Fue desarrollado con la libreria de Telebot y Telegram +Como caracteristicas futuras, se espera implementar el mismo bot con flask y posiblemente con Whatsapp ya que es el principal canal de comunicacion \ No newline at end of file diff --git a/proyecto/jorge_luis_castellanos/requirements.txt b/proyecto/jorge_luis_castellanos/requirements.txt new file mode 100644 index 0000000..7ce90bd --- /dev/null +++ b/proyecto/jorge_luis_castellanos/requirements.txt @@ -0,0 +1,24 @@ +anyio==4.9.0 +blinker==1.9.0 +certifi==2025.7.14 +charset-normalizer==3.4.2 +click==8.2.1 +Flask==3.1.1 +h11==0.16.0 +httpcore==1.0.9 +httpx==0.28.1 +idna==3.10 +itsdangerous==2.2.0 +Jinja2==3.1.6 +mailjet-rest==1.5.1 +MarkupSafe==3.0.2 +pyTelegramBotAPI==4.27.0 +python-dotenv==1.1.1 +python-telegram-bot==22.2 +requests==2.32.4 +sniffio==1.3.1 +telebot==0.0.5 +telegram==0.0.1 +typing_extensions==4.14.1 +urllib3==2.5.0 +Werkzeug==3.1.3 diff --git a/proyecto/jorge_luis_castellanos/telebot_complete.db b/proyecto/jorge_luis_castellanos/telebot_complete.db new file mode 100644 index 0000000..f678dcb Binary files /dev/null and b/proyecto/jorge_luis_castellanos/telebot_complete.db differ diff --git a/proyecto/ronald_diaz/chat.db b/proyecto/ronald_diaz/chat.db new file mode 100644 index 0000000..bd57465 Binary files /dev/null and b/proyecto/ronald_diaz/chat.db differ diff --git a/proyecto/ronald_diaz/inicio.py b/proyecto/ronald_diaz/inicio.py new file mode 100644 index 0000000..6910947 --- /dev/null +++ b/proyecto/ronald_diaz/inicio.py @@ -0,0 +1,102 @@ +from flask import Flask, render_template, request, redirect, url_for +import sqlite3 +import os +from dotenv import load_dotenv +import google.generativeai as ai + +load_dotenv() +API = os.getenv("API_KEY") +ai.configure(api_key=API) + +preferred_models = [ + "gemini-2.5-flash", + "gemini-2.5-flash-latest", + "gemini-2.5-flash-002", + "gemini-1.5-flash", + "gemini-1.5-flash-latest", + "gemini-1.5-flash-002", +] + +model_to_use = None +for m in ai.list_models(): + if "generateContent" in m.supported_generation_methods: + for preferred in preferred_models: + if m.name == f"models/{preferred}": + model_to_use = m.name + break + if model_to_use: + break + +if not model_to_use: + raise Exception("No Gemini model available for generateContent") + +model = ai.GenerativeModel(model_to_use) +chat = model.start_chat() + +# --- Flask Setup --- +app = Flask(__name__) +DATABASE = 'chat.db' + +# --- Database Helper Functions --- +def init_db(): + conn = sqlite3.connect(DATABASE) + c = conn.cursor() + c.execute(''' + CREATE TABLE IF NOT EXISTS messages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_message TEXT NOT NULL, + bot_response TEXT NOT NULL, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP + ) + ''') + conn.commit() + conn.close() + +init_db() + +@app.route('/') +def index(): + conn = sqlite3.connect(DATABASE) + c = conn.cursor() + c.execute("SELECT user_message, bot_response, timestamp FROM messages ORDER BY id ASC") + chat_history = c.fetchall() + conn.close() + try: + promptInicial = "Actua como un experto en recetas de postres segun el nombre del postre que ingresen debes brindar informacion sobre la receta y preparacion, la respuesta debe ser en español, en cuanto a la preparación que que la explicacion sea bien corta y entendible. Si te preguntan sobre algo que no sea un postre debes presentar el siguiente mensaje: Solo respondo respuestas sobre postres y su preparación" + chat.send_message(promptInicial) + except Exception as e: + print(f"Error: {e}") + return render_template('index.html', chat_history=chat_history) + +@app.route('/send', methods=['POST']) +def send(): + user_message = request.form['message'] + try: + response = chat.send_message(user_message) + bot_response = response.text + except Exception as e: + bot_response = f"Error: {e}" + + conn = sqlite3.connect(DATABASE) + c = conn.cursor() + c.execute("INSERT INTO messages (user_message, bot_response) VALUES (?, ?)", (user_message, bot_response)) + conn.commit() + conn.close() + + return redirect(url_for('index')) + +@app.route('/clear') +def clear(): + conn = sqlite3.connect(DATABASE) + c = conn.cursor() + c.execute("DELETE FROM messages") + conn.commit() + conn.close() + return redirect(url_for('index')) + +@app.route('/acerca') +def acercaDE(): + return render_template("acerca.html") + +if __name__ == '__main__': + app.run(debug=True) diff --git a/proyecto/ronald_diaz/templates/acerca.html b/proyecto/ronald_diaz/templates/acerca.html new file mode 100644 index 0000000..47856ca --- /dev/null +++ b/proyecto/ronald_diaz/templates/acerca.html @@ -0,0 +1,67 @@ + + + + + Acerca de – PostresChat + + + + + + + + +
+
+

Acerca de PostresChat

+

+ PostresChat es un chatbot especializado en dulces y postres. + Diseñado para responder cualquier pregunta relacionada con la selección de ingredientes, técnicas de preparación, tiempos de horneado y decoración de postres. +

+

+ Ejemplos de temas que cubre: +

    +
  • Cómo hacer un bizcocho esponjoso de vainilla
  • +
  • Alternativas sin gluten o sin lácteos
  • +
  • Técnicas de baño de chocolate y glaseado
  • +
  • Decoración con glaseado real y fondant
  • +
+

+

+ Nota: Si le preguntas algo que no tenga que ver con postres o preparación de dulces, + PostresChat te indicará amablemente que solo puede responder consultas relacionadas a postres. +

+
+
+ + + + + + \ No newline at end of file diff --git a/proyecto/ronald_diaz/templates/index.html b/proyecto/ronald_diaz/templates/index.html new file mode 100644 index 0000000..46cfeac --- /dev/null +++ b/proyecto/ronald_diaz/templates/index.html @@ -0,0 +1,92 @@ + + + + + 🤖 Chatbot con Gemini + + + + + + + +
+
+
+ {% for user_msg, bot_msg, timestamp in chat_history %} +
+
Tú: {{ user_msg }}
+
{{ timestamp }}
+
+
+
Bot: {{ bot_msg }}
+
{{ timestamp }}
+
+ {% endfor %} +
+ +
+ + +
+
+
+ + + + \ No newline at end of file diff --git a/proyecto/valeria_ramos/app.py b/proyecto/valeria_ramos/app.py new file mode 100644 index 0000000..3852d3b --- /dev/null +++ b/proyecto/valeria_ramos/app.py @@ -0,0 +1,239 @@ +from telegram import ( + Update, InlineKeyboardButton, InlineKeyboardMarkup +) +from telegram.ext import ( + ApplicationBuilder, CommandHandler, CallbackQueryHandler, + MessageHandler, ContextTypes, filters, ConversationHandler +) +import requests +import os +import re +import sqlite3 +from datetime import datetime +from dotenv import load_dotenv + +# 📌 Cargar .env +load_dotenv() +BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") +MAILJET_API_KEY = os.getenv("MAILJET_API_KEY") +MAILJET_SECRET_KEY = os.getenv("MAILJET_SECRET_KEY") +MAILJET_URL = os.getenv("MAILJET_URL") +EMAIL_FROM = os.getenv("EMAIL_FROM") + +# 📌 Estados +MENU, DATOS, AUTORIZACION, CONFIRMAR = range(4) + +# 📌 Servicios de Bodega Palermo +SERVICIOS = { + "🍷 Vinos": 25, + "🥃 Licores": 30, + "🍺 Cervezas": 15, + "🍾 Espumantes": 40 +} + +# 📌 Base de datos +conn = sqlite3.connect("bodega_palermo.db", check_same_thread=False) +cursor = conn.cursor() +cursor.execute(""" +CREATE TABLE IF NOT EXISTS chat_data ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, + username TEXT, + servicio TEXT, + message_id INTEGER, + timestamp TEXT +) +""") +conn.commit() + +def guardar_interaccion(update: Update): + user = update.effective_user + username = user.username or "Sin username" + servicio = "" + message_id = None + + if update.callback_query: + servicio = update.callback_query.data + message_id = update.callback_query.message.message_id + elif update.message: + servicio = update.message.text + message_id = update.message.message_id + + timestamp = datetime.now().isoformat() + cursor.execute(""" + INSERT INTO chat_data (user_id, username, servicio, message_id, timestamp) + VALUES (?, ?, ?, ?, ?) + """, (user.id, username, servicio, message_id, timestamp)) + conn.commit() + +# 📌 Inicio con menú interactivo +async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): + mensaje = ( + "🍷 *Bienvenido a Bodega Palermo* 🍾\n\n" + "Selecciona el producto que deseas consultar por favor:" + ) + keyboard = [ + [InlineKeyboardButton(text=opcion, callback_data=opcion)] + for opcion in SERVICIOS.keys() + ] + reply_markup = InlineKeyboardMarkup(keyboard) + + await update.message.reply_text( + mensaje, + reply_markup=reply_markup, + parse_mode="Markdown" + ) + return MENU + +# 📌 Selección del producto +async def servicio_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): + query = update.callback_query + await query.answer() + servicio = query.data + context.user_data["servicio"] = servicio + + await query.message.reply_text( + f"📋 Has seleccionado *{servicio}*.\n\n" + f"Por favor, indícanos:\n1. Tu nombre completo\n2. Tu correo electrónico\n3. Detalles del pedido", + parse_mode="Markdown" + ) + guardar_interaccion(update) + return DATOS + +# 📌 Recolección de datos +async def recibir_datos(update: Update, context: ContextTypes.DEFAULT_TYPE): + texto = update.message.text.strip() + email = extraer_email(texto) + if not email: + await update.message.reply_text( + "❌ No detectamos un correo válido.\nPor favor escribe:\n`Nombre - correo@ejemplo.com - detalles del pedido`", + parse_mode="Markdown" + ) + return DATOS + + context.user_data["datos"] = texto + + await update.message.reply_text( + "🔐 ¿Autorizas a Bodega Palermo a usar tus datos para procesar tu pedido?", + reply_markup=InlineKeyboardMarkup([ + [InlineKeyboardButton("✅ Sí", callback_data="si")], + [InlineKeyboardButton("❌ No", callback_data="no")] + ]) + ) + guardar_interaccion(update) + return AUTORIZACION + +# 📌 Autorización +async def autorizacion_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): + query = update.callback_query + await query.answer() + respuesta = query.data.lower() + + if "si" in respuesta: + servicio = context.user_data["servicio"] + precio = SERVICIOS[servicio] + await query.message.reply_text( + f"💵 El precio estimado de *{servicio}* es de *${precio}* por unidad.\n\n¿Deseas confirmar tu pedido?", + parse_mode="Markdown", + reply_markup=InlineKeyboardMarkup([ + [InlineKeyboardButton("✅ Confirmar", callback_data="confirmar")], + [InlineKeyboardButton("❌ Cancelar", callback_data="cancelar")] + ]) + ) + guardar_interaccion(update) + return CONFIRMAR + else: + await query.message.reply_text( + "🚫 No podemos continuar sin tu autorización.\nUsa /start para iniciar de nuevo." + ) + return ConversationHandler.END + +# 📌 Confirmación +async def confirmar_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): + query = update.callback_query + await query.answer() + accion = query.data.lower() + + if "confirmar" in accion: + servicio = context.user_data["servicio"] + descripcion = context.user_data["datos"] + precio = SERVICIOS[servicio] + correo = extraer_email(descripcion) + + mensaje = ( + f"🍷 *Bodega Palermo* 🍾\n\n" + f"✅ *Producto:* {servicio}\n" + f"📝 *Detalles:* {descripcion}\n" + f"💵 *Precio estimado:* ${precio}\n\n" + "Nos pondremos en contacto contigo pronto. ¡Gracias por tu pedido!" + ) + + if correo: + enviado = enviar_mailjet(context, correo, f"Confirmación de pedido - Bodega Palermo", mensaje) + if enviado: + await query.message.reply_text("📧 Correo de confirmación enviado ✅") + else: + await query.message.reply_text("⚠️ Ocurrió un error al enviar el correo.") + else: + await query.message.reply_text("⚠️ Correo no detectado correctamente.") + + await query.message.reply_text("🍾 Si deseas realizar otro pedido, usa /start.") + guardar_interaccion(update) + return ConversationHandler.END + + else: + await query.message.reply_text( + "❌ Pedido cancelado. Usa /start para comenzar de nuevo cuando quieras." + ) + return ConversationHandler.END + +# 📌 Extraer correo +def extraer_email(texto): + match = re.search(r'[\w\.-]+@[\w\.-]+\.\w+', texto) + return match.group(0) if match else None + +# 📌 Enviar correo +def enviar_mailjet(context, destinatario, asunto, contenido): + data = { + "Messages": [ + { + "From": {"Email": EMAIL_FROM, "Name": "Bodega Palermo"}, + "To": [{"Email": destinatario}], + "Subject": asunto, + "TextPart": contenido + } + ] + } + try: + response = requests.post( + MAILJET_URL, + json=data, + auth=(MAILJET_API_KEY, MAILJET_SECRET_KEY) + ) + print(f"Mailjet: {response.status_code} - {response.text}") + return response.status_code == 200 + except Exception as e: + print(f"❌ Error: {e}") + return False + +# 📌 Main +def main(): + app = ApplicationBuilder().token(BOT_TOKEN).build() + + conv_handler = ConversationHandler( + entry_points=[CommandHandler("start", start)], + states={ + MENU: [CallbackQueryHandler(servicio_callback)], + DATOS: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_datos)], + AUTORIZACION: [CallbackQueryHandler(autorizacion_callback)], + CONFIRMAR: [CallbackQueryHandler(confirmar_callback)], + }, + fallbacks=[], + ) + + app.add_handler(conv_handler) + print("🍾 Bot Bodega Palermo en ejecución...") + app.run_polling() + +if __name__ == "__main__": + main() diff --git a/proyecto/valeria_ramos/bodega_palermo.db b/proyecto/valeria_ramos/bodega_palermo.db new file mode 100644 index 0000000..ad981c3 Binary files /dev/null and b/proyecto/valeria_ramos/bodega_palermo.db differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..734e6a5 Binary files /dev/null and b/requirements.txt differ