|
# ========================================================== |
|
# Proyecto: Auto Práctica con API de OpenAI ChatGPT vía MicroPython |
|
# Dispositivo: PIMORONI BADGER 2040 W |
|
# Lenguaje: MicroPython + Python (Flask) |
|
# Autor: Juan Carmona Valdez |
|
# Fecha: Noviembre 2025 |
|
# Descripción: |
|
# Conecta la PIMORONI BADGER 2040 W con un servidor Flask |
|
# que utiliza la API de OpenAI ChatGPT para procesar una historia. |
|
# El flujo de datos se realiza mediante solicitudes HTTP POST, |
|
# permitiendo comunicación bidireccional crea una historia |
|
# ofrece 3 opciones para continuar. |
|
# ========================================================== |
|
|
|
import badger2040 |
|
from badger2040 import WIDTH, HEIGHT |
|
import urequests |
|
import ujson |
|
import time |
|
from WIFI_CONFIG import SSID, PSK, COUNTRY |
|
|
|
# ====== Configuración Badger ====== |
|
display = badger2040.Badger2040() |
|
display.led(128) |
|
display.set_update_speed(badger2040.UPDATE_FAST) |
|
|
|
LINE_HEIGHT = 16 |
|
TEXT_SIZE = 1 |
|
|
|
# ====== Conexión WiFi ====== |
|
display.set_pen(15) |
|
display.clear() |
|
display.set_pen(0) |
|
display.text("Conectando WiFi...", 10, 40, WIDTH) |
|
display.update() |
|
|
|
import network |
|
wlan = network.WLAN(network.STA_IF) |
|
wlan.active(True) |
|
wlan.connect(SSID, PSK) |
|
while not wlan.isconnected(): |
|
time.sleep(0.5) |
|
|
|
net = wlan.ifconfig() |
|
|
|
display.clear() |
|
display.set_pen(0) |
|
display.rectangle(0, 0, WIDTH, 20) |
|
display.set_pen(15) |
|
display.text("Stories", 3, 4) |
|
display.set_pen(0) |
|
display.text("> LOCAL IP: {}".format(net[0]), 0, 35 + int(LINE_HEIGHT / 2), WIDTH) |
|
display.update() |
|
time.sleep(1) |
|
|
|
# ====== Servidor ====== |
|
SERVER_URL = "http://172.16.4.29:5001/story" |
|
|
|
# ====== Variables de scroll ====== |
|
scroll_offset = 0 |
|
page_lines = [] |
|
|
|
def parsear_historia(texto): |
|
if not texto: |
|
return ["Error: historia vacía"] |
|
|
|
lines = [] |
|
|
|
# Extraer HISTORIA |
|
inicio = texto.find("### HISTORIA:") |
|
fin = texto.find("### OPCIONES:") |
|
if inicio == -1: |
|
inicio = 0 |
|
else: |
|
inicio += len("### HISTORIA:") |
|
if fin == -1: |
|
fin = len(texto) |
|
historia = texto[inicio:fin].strip().replace("\r", "").split("\n") |
|
|
|
# Limitar longitud de cada línea |
|
max_chars = 50 |
|
for linea in historia: |
|
while len(linea) > max_chars: |
|
lines.append(linea[:max_chars]) |
|
linea = linea[max_chars:] |
|
lines.append(linea) |
|
|
|
# Extraer OPCIONES |
|
inicio_op = texto.find("### OPCIONES:") |
|
if inicio_op != -1: |
|
opciones = texto[inicio_op + len("### OPCIONES:"):].strip().replace("\r", "").split("\n") |
|
lines.append("") # separación visual |
|
for opcion in opciones: |
|
while len(opcion) > max_chars: |
|
lines.append(opcion[:max_chars]) |
|
opcion = opcion[max_chars:] |
|
lines.append(opcion) |
|
|
|
return lines |
|
|
|
|
|
def mostrar_texto_scroll(lines, offset): |
|
display.set_pen(15) |
|
display.rectangle(0, 20, WIDTH, HEIGHT-20) # limpiar área de texto |
|
display.set_pen(0) |
|
y = 25 |
|
for i in range(offset, min(offset + (HEIGHT//LINE_HEIGHT), len(lines))): |
|
display.text(lines[i], 5, y, WIDTH, TEXT_SIZE) |
|
y += LINE_HEIGHT |
|
display.update() |
|
|
|
def pedir_historia(historia, eleccion): |
|
data = { |
|
"historia": historia if historia else "", |
|
"eleccion": eleccion if eleccion else "" |
|
} |
|
|
|
try: |
|
r = urequests.post(SERVER_URL, json=data) |
|
r_json = r.json() |
|
r.close() |
|
return r_json.get("respuesta", "") |
|
except Exception as e: |
|
print("ERROR EN POST:", e) |
|
return "" |
|
|
|
|
|
# ====== Primera historia ====== |
|
historia_actual = pedir_historia("<historia_nueva>", "0") |
|
page_lines = parsear_historia(historia_actual) |
|
scroll_offset = 0 |
|
mostrar_texto_scroll(page_lines, scroll_offset) |
|
|
|
# ====== Loop principal ====== |
|
prev_a = prev_b = prev_c = False |
|
while True: |
|
# Lectura botones |
|
a = display.pressed(badger2040.BUTTON_A) |
|
b = display.pressed(badger2040.BUTTON_B) |
|
c = display.pressed(badger2040.BUTTON_C) |
|
up = display.pressed(badger2040.BUTTON_UP) |
|
down = display.pressed(badger2040.BUTTON_DOWN) |
|
|
|
# ====== Scroll ====== |
|
if up: |
|
scroll_offset = max(0, scroll_offset - 1) |
|
mostrar_texto_scroll(page_lines, scroll_offset) |
|
if down: |
|
scroll_offset = min(len(page_lines) - (HEIGHT//LINE_HEIGHT), scroll_offset + 1) |
|
mostrar_texto_scroll(page_lines, scroll_offset) |
|
|
|
# ====== Elecciones ====== |
|
if a and not prev_a: |
|
historia_actual = pedir_historia("<historia_actual>", "1") |
|
page_lines = parsear_historia(historia_actual) |
|
scroll_offset = 0 |
|
mostrar_texto_scroll(page_lines, scroll_offset) |
|
if b and not prev_b: |
|
historia_actual = pedir_historia("<historia_actual>", "2") |
|
page_lines = parsear_historia(historia_actual) |
|
scroll_offset = 0 |
|
mostrar_texto_scroll(page_lines, scroll_offset) |
|
if c and not prev_c: |
|
historia_actual = pedir_historia("<historia_actual>", "3") |
|
page_lines = parsear_historia(historia_actual) |
|
scroll_offset = 0 |
|
mostrar_texto_scroll(page_lines, scroll_offset) |
|
|
|
prev_a, prev_b, prev_c = a, b, c |
|
time.sleep(0.1) |
|
|