No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Aplicación de ejemplo utilizando modelos de OpenAI

5/24
Recursos

En el mundo de la programación y la inteligencia artificial, uno de los ejercicios más estimulantes e interactivos es la creación de pequeños juegos que ponen a prueba nuestras habilidades lógicas y de codificación. Más aún si involucran tecnologías avanzadas como el uso de APIs para integrar sistemas autónomos de decisión. En este caso, exploraremos cómo crear un juego en Python que emplea la API de OpenAI. Sumérgete en esta actividad práctica donde desarrollaremos un juego de adivinanzas para identificar animales de la selva. Prepárate para combinar tus habilidades de codificación con un poco de intuición natural sobre el mundo animal. ¡Vamos a comenzar!

Preparativos iniciales

Antes de sumergirnos en el código, es crucial tener todo listo en nuestro entorno de programación. Google Colaboratory es una excelente opción para desarrollar y probar rápidamente nuestros scripts gracias a su entorno basado en la nube. Debes asegurarte de tener la librería de OpenAI ya instalada e importada, así como tu API key configurada previamente. Esta preparación garantizará un flujo de trabajo sin interrupciones a medida que avanzamos en la creación del juego.

Configuración de OpenAI y elección aleatoria de animales

La API de OpenAI será nuestro centro de inteligencia artificial. Para interactuar con ella, es necesario configurarla y autenticarla usando tu clave API. Una vez hecho esto, incluiremos la librería random para añadir un factor sorpresa al juego: la selección aleatoria del animal sobre el que el jugador tendrá que adivinar. La selección aleatoria es un pilar de la interactividad en muchos juegos y añade un componente único a cada sesión de juego.

Desarrollo del juego

Creando pistas para el usuario

Con todo en su lugar, el primer paso es crear la función getClue, que no recibirá parámetros pero trabajará con una lista predefinida de animales. Tal lista podría incluir un elefante, león, jirafa, hipopótamo y mono. La función seleccionará uno de estos animales de forma aleatoria y proporcionará al usuario una pista inicial: "Este animal vive en la selva". Con ello, el usuario obtiene una dirección en la que iniciar su adivinanza.

Verificación de respuestas

Después de generar la pista, es crucial poder verificar si las suposiciones del usuario son correctas. Implementamos la función checkAnswer para comparar la entrada del usuario con la respuesta real. Un simple True o False simplificará el proceso de determinar si el juego continúa o termina con un acierto.

Generando pistas adicionales

Aquí es donde la API de OpenAI entra en juego a pleno rendimiento. Creamos una función giveProperties que solicitará al modelo de OpenAI, en este caso "Davinci", que nos de características adicionales del animal sin revelar su nombre. Es importante ser específico en las solicitudes al modelo para obtener pistas útiles y mantener la naturaleza desafiante del juego.

La función principal del juego

Finalmente, desarrollamos la función playGame que une todas las piezas. Esta función orquesta el flujo del juego desde la presentación de la pista inicial hasta la verificación de las respuestas y la solicitud de pistas adicionales. Es el corazón del juego, y su implementación adecuada es clave para una experiencia de usuario agradable y funcional.

En busca de la precisión

Un aspecto interesante del juego es la necesidad de una respuesta precisa. Errores comunes como omitir acentos pueden llevar a una respuesta incorrecta, por lo que la atención al detalle es importante. Este enfoque en la precisión ofrece una doble lección: por un lado, la importancia de la cuidadosa entrada de datos y, por otro, una oportunidad para enseñar acerca de la relevancia de la ortografía en la programación.

Mejoras y depuración

El juego que hemos descrito proporciona una base sobre la cual podemos construir y mejorar. Puedes ejecutar el código para identificar problemas y depurarlos. Una recomendación es enfocarte en mejorar el PROMPT para obtener un mejor rendimiento del modelo de OpenAI, lo que podría implicar aprender más sobre Prompt Engineering.

Ánimos para continuar aprendiendo

Cada reto en programación es una invitación a aprender y a pulir habilidades. No te detengas aquí. Hay muchos caminos abiertos a explorar, como refinar el juego que acabamos de crear o adentrarte en otros aspectos de la programación e inteligencia artificial. La constancia y la curiosidad serán tus mejores aliados en este apasionante viaje de aprendizaje continuo. ¡Adelante y mucha suerte!

Aportes 19

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Se puede reescribir la función check_answer para que sea más legible.

def check_answer(user_input, answer):
    return user_input == answer

Se puede ser un poco mas flexible dandole roles a modelos como gpt-3.5-turbo donde las respuestas pueden ir variando de acuerdo a un rango deterministico como es la temperatura:

def give_property(animal):
    messages = [
        {"role": "system", "content": "Eres un juego que suele deciir propiedades de un animal en forma de pistas, pero no debes decir nunca el nombre del animal"},
        {"role": "user", "content": "Dame un caracteristica del animal"},
        {"role": "assistant", "content": f"El animal que debes dar pistas es {animal}"},
        {"role": "user", "content": "En que animal estoy pensando?"},
    ]
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages,
        temperature=1,
    )

    return response.choices[0].message["content"]

Yo empece a jugar con los parametros frequency_penalty y presence_penalty. Me di cuenta que si el valor es muy alto la pista es muy facil y si es muy bajo usa terminos mas especificos a caracteristicas del animal. Incluso habian casos con valores altos que en la misma caracteristica del animal daba la respuesta.
Esto se debe a la definicion de uso de ambas variables pero sigue siendo algo interesante.

Como aporte, curiosidad o forma alternativa de responder el código.

Desde python 3.8 en adeltante se implemento el operador walrus en español morza.

:=

El cuál tiene como función justamente poder asignar Y preguntar algo en una sola expresión.

Normalmente hacemos algo parecido a esto:

edad = 18
if edad >= 18:
    ....

Creamos una variable, le asignamos un valor y preguntamos algo.

Con walrus podriamos hacer:

if (edad := 18) >= 18:

Y justamente en este código del juego, queda muy bien el operador walrus
Podemos cambiar:

def play_game():
  prompt, answer = get_clue()
  print(prompt)
  while True:
    user_input = input('Ingresa tu respuesta:')
    if check_answer(user_input,answer):
      print('Correcto! La respuesta era:', answer)
      break
    else:
      print('Respuesta incorrecta. Intentalo de nuevo')
      print(give_property(answer))

Por:

def play_game():
    # Empezamos con nuestro animal aleatorio y primer pista genérica
    first_clue, real_animal = get_base_clue()
    print(first_clue)
    # Mientras la respuesta del usuario sea diferente al verdadero animal
    while (user_input := input("Ingresa tu respuesta: ")) != real_animal:
        # Le decimos que se equivocó
        print('Respuesta incorrecta. Intentalo de nuevo')
        # Y le damos una nueva pista
        new_clue = get_new_clue(real_animal)
        print(new_clue)
    # Si salimos del ciclo while es porque el usuario ha acertado
    print('Correcto! La respuesta era:', real_animal)

Nota: he modificado el nombre de las variables para aumentar la legibilidad del código.

Ahora cuentan con una herramienta más de Python 😃

Te gustó?

No olvides visitar mis notas personales de esta clase:

Apuntes personales

Saludos, Gabriel Ichcanziho.

Revisando en la documentacion, Completion ya aparece como un metodo legacy, y ChatCompletion es el metodo con el que ellos buscan reemplazarlo, ChatCompletion fomenta la conversacion por turnos y la especificacion de roles, les dejo un ejemplo (lo tomo de la documentaicon):

import openai

openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Who won the world series in 2020?"},
        {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
        {"role": "user", "content": "Where was it played?"}
    ]
)

les dejo el link de la documentacion

Comparto mis cambios del código. Hice otro objeto de Completion para que me diera los 5 animales de forma aleatoria, luego los paso a un list y limpio los strings.

También le doy como primera pista la cantidad de letras del animal y comparo la respuesta poniendo todo en minúscula

def get_clue(): # Elige un animal al azar y comienza con un propmt inicial del juego
    animals = openai.Completion.create(
        engine = 'text-davinci-003',
        prompt = "Dame una lista de 5 animales diferentes separados por espacios no comas",
        max_tokens = 60
    )
    words = list(animals.choices[0].text.split(" "))
    words[0] = words[0].replace('\n\n', '')

    random_word = random.choice(words)
    prompt = 'Adivina la palabra que estoy pensando. Es un animal de {} letras.'.format(len(random_word)) 
    return prompt, random_word

def check_answer(user_input, answer):
    return user_input.lower() == answer.lower()

def give_propetry(animal):
    response = openai.Completion.create(
        engine = 'text-davinci-003',
        prompt = 'Dame una característica del animal {}, pero jamás digas el nombre del animal. Un ejemplo incorrecto sería: El león tiene melena'.format(animal),
        max_tokens = 100
    )
    return response.choices[0].text

def play_game():
    prompt, answer = get_clue()
    print(prompt)
    while True:
        user_input = input('Ingresa tu respuesta:   ')
        if check_answer(user_input, answer):
            print("Correcto!. Adivinaste, la respuesta era {}".format(answer))
            break
        else:
            print("Respuesta incorrecta. No es la solución inténtalo denuevo. Te daré otra pista:   ")
            print(give_propetry(answer))


play_game()

En mi caso decidí cambiar el juego para adivinar Pokémons en vez de animales, para ello cambié primero la función get_clue para obtener una lista de los Pokémon de la primera generación:

def get_clue():
    url = "https://pokeapi.co/api/v2/pokemon/?limit=151"  # Limit set to 151 for Generation I Pokémon

    response = requests.get(url)
    if response.status_code == 200:
        pokemons = response.json()["results"]
    else:
        print("Failed to fetch Pokémon data. Status code:", response.status_code)
        
    random_pokemon = random.choice(pokemons)
    prompt = "It is a first generation Pokémon"
    return prompt, random_pokemon["name"]

Adicionalmente, cambié el prompt de la función get_answer de la siguiente forma:

def give_hint(pokemon):
    response = openai.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "You are a game that gives the user hints about a pokemon it is trying to guess but you never give the name of the pokemon, also you try to give different hints every time, the pokemon the user is trying to guess is: " + pokemon},
            {"role": "user", "content" : "Give me a feature of the pokemon"},
        ],
        max_tokens=50,
        temperature=0.9,
    )
    return response.choices[0].message.content

Y finalmente, cambie la función play para poner un límite de intentos y evitar un uso desmedido de la API:

def play():
    prompt, pokemon = get_clue()
    print(prompt)
    tries = 0
    while tries < 7:
        tries += 1
        answer = input("Answer: ")
        if check_answer(answer, pokemon):
            print("Correct!")
            break
        else:
            print("Incorrect!")
            print(give_hint(pokemon))

Desde el principio dice que es mono 😕

Yo le cambié ciertas cosas a la funcion de give\_property(), por que a mi juicio estaba dando la misma pista siempre, pero con distintas palabras. Funciona ahora un poco mejor al respecto: ```python def give_property(animal): response = openai.chat.completions.create( model = 'gpt-4o-mini', messages = [ {'role': 'system', 'content': 'Eres un juego que suele decir propiedades de un animal en forma de pistas, pero no debes decir nunca el nombre del animal. Procura no repetir propiedades del animal que ya has dicho antes.'}, {'role': 'user', 'content':'Dame una característica del tipo animal '+animal+', pero jamás digas el nombre del animal'} ], max_tokens=100, temperature=1, frequency_penalty=2, presence_penalty=2) return response.choices[0].message.content ```
Este ejemplo Ignore los acentos (como "León" vs. "leon") y es insensible a las mayúsculas/minúsculas. En Python se debe instalar la librería unidecode para los acentos. ```js import openai import random import unidecode """ Se debe instalar la librería unidecode para que convierte cualquier letra con acento en su versión básica (sin acento). pip install unidecode """ # Clave API openai.api_key = APIkey.apikey # Modelo model = "gpt-4o-mini" def normaliza_textos(text): # Eliminar acentos y convertir a minúsculas text = text.lower() # Convertir todo a minúsculas text = unidecode.unidecode(text) # Eliminar acentos return text def listado(): lista = ['León', 'Cocodrilo', 'Hipopótamo', 'Jirafa', 'Tigre', 'Leopardo'] animal = random.choice(lista) animal_nomalizado = normaliza_textos(animal) prompt = 'Adivina en que animal de la selva estoy pensando.' return prompt, animal, animal_nomalizado def valida_respuesta(resp_usuario, resp_IA): if resp_usuario == resp_IA: return True return False def pista_animal(animal): response = openai.chat.completions.create( model = model, messages = [ {"role": "system", "content": 'Dame una característica del tipo animal ' + animal + ', pero jamás digas el nombre del animal'}, ], max_tokens = 100 ) return response.choices[0].message.content def jugar(): prompt, resp_IA, resp_normalizada = listado() print(prompt) while True: resp_usuario = normaliza_textos(input('Ingresa tu respuesta: ')) if valida_respuesta(resp_usuario, resp_normalizada): print(f'Repuesta correcta. El animal es {resp_IA}') break else: print('Intenta nuevamente') print(pista_animal(resp_IA)) # Controlar la ejecución del código. if __name__ == '__main__': jugar() ```
Este código funciona en terminal con fecha de 18 de Febrero del 2024 `from openai import OpenAIimport random` `client = OpenAI()` `def get_clue(): words = ['elefante', 'león', 'jirafa', 'hipopótamo', 'mono'] random_word = random.choice(words) prompt = 'Adivina la palabra que estoy pensando. Es un animal que vive en la selva.' return prompt, random_word` `def check_answer(user_input, answer): if user_input == answer: return True return False` `def give_property(animal): response = client.chat.completions.create( model= 'gpt-4', messages = [ {"role": "user", "content" :'Dame una caracteristica del tipo animal ' + animal + ', pero jamás digas el nombre del animal'}, ], max_tokens = 100) return response.choices[0].message.content` `def play_game(): prompt, answer = get_clue() print(prompt) while True: user_input = input('Ingresa tu respuesta:') if check_answer(user_input,answer): print('Correcto! La respuesta era:', answer) break else: print('Respuesta incorrecta. Intentalo de nuevo') print(give_property(answer))` `play_game()`
les comparto lo que me funcionó mejor: `response = client.chat.completions.create(` `model='gpt-3.5-turbo',` ` messages=[` ` ` ` {"role":"system", "content":"eres un juego que suele decir propiedades o caracteristicas de un animal en forma de pistas, la regla del juego es no decir nunca el nombre del animal"},` ` {"role":"user", "content":"Dame caracteristicas de un animal "+ animal},` ` ` ` ` ` ` ` ],` ` max_tokens = 100,` `)`
para empezar poner tu pantalla verde ahi como una inexperta basta 5 segundos se puede pausar la pantalla y me tapa el codigo en el que demuestras pesimo
Reescribi el código utilizando gpt-3.5-turbo y además le agregue un user input para evitar que constantemente repita la misma pista. ```python messages = \[ {"role": "system", "content": "Eres un juego que suele decir propiedades de un animal en forma de pistas, pero no debes decir nunca el nombre del animal"}, {"role": "system", "content": "Siempre debes empezar las pistas con el formato: '-> La pista es: '"}, ] def give\_property(animal): messages.extend(\[{"role": "system", "content": f"El animal que debes dar pistas es {animal}"}, {"role": "user", "content": "Dame un caracteristica del animal"}, {"role": "assistant", "content": "En que animal estoy pensando?"}]) response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=messages, temperature=1, ) return response.choices\[0].message\["content"] def add\_user\_answer(): messages.append({"role": "user", "content": "Dame otra caracteristica del animal"},) ``` Cada vez que el usuario se equivoca llamo a `add_user_answer()`
!!!!ME SALE ESTE ERROR AYUDA ES DEL SERVIDOR O ME CONFUNDI EN EL CODIGO? Adivina la palabra que estoy pensando. es un animal que vive en la selva INGRESA TU RESPUESTAmono sigue intentando \--------------------------------------------------------------------------- APIError Traceback (most recent call last) [\<ipython-input-7-9ada982fd12c>](https://localhost:8080/#) in \<cell line: 1>() \----> 1 principal() 6 frames[/usr/local/lib/python3.10/dist-packages/openai/api\_requestor.py](https://localhost:8080/#) in \_interpret\_response\_line(self, rbody, rcode, rheaders, stream) 773 stream\_error = stream and "error" in resp.data 774 if stream\_error or not 200 <= rcode < 300: \--> 775 raise self.handle\_error\_response( 776 rbody, rcode, resp.data, rheaders, stream\_error=stream\_error 777 ) APIError: Internal server error { "error": { "message": "Internal server error", "type": "auth\_subrequest\_error", "param": null, "code": "internal\_error" } } 500 {'error': {'message': 'Internal server error', 'type': 'auth\_subrequest\_error', 'param': None, 'code': 'internal\_error'}} {'Date': 'Fri, 20 Oct 2023 00:21:16 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '166', 'Connection': 'keep-alive', 'vary': 'Origin', 'x-request-id': '54890d6539e1049cca1e226c9028ce71', 'strict-transport-security': 'max-age=15724800; includeSubDomains', 'CF-Cache-Status': 'DYNAMIC', 'Server': 'cloudflare', 'CF-RAY': '818d1968294453cf-ATL', 'alt-svc': 'h3=":443"; ma=86400'}
* Estuve chequeando la docu y recomiendan usar ChatCompletion. * Para omitir el uso de acentos en la validación de la respuesta uso la libreria unicodedata * Para omitir mayúsculas convierto la respuesta del desafío y la del usuario a minúsculas * Al usar ChatCompletion se pasan los mensajes usando roles. En este caso el sistema recibe una serie de instrucciones de lo que debe hacer y le agregué la respuesta del usuario para que la valide el modelo * Está bueno jugar con el tema de la temperatura. En mi caso me parece que tarda más en dar la respuesta cuando se aproxima a uno * ```python import openai import os from dotenv import load_dotenv import random import unicodedata load_dotenv() API_KEY = os.getenv("OPEN_AI_TOKEN") openai.api_key = API_KEY def get_clue(): animals = ["Cocodrilo", "Mono", "Delfín", "Tiranosaurio", "Pez", "Pájaro", "Gato", "Perro", "Conejo", "Ratón", "Elefante", "Jirafa", "Cebra", "León", "Tigre", "Oso", "Puercoespín", "Canguro"] random_animal = random.choice(animals) prompt = f"Adivina el animal que estoy pensando... " return prompt, random_animal def remove_accents(input_str): nfkd_form = unicodedata.normalize('NFKD', input_str) return ''.join([c for c in nfkd_form if not unicodedata.combining(c)]) def check_answer(user_input, answer): return remove_accents(user_input.lower()) == remove_accents(answer.lower()) def give_property(animal, input_user): response = openai.ChatCompletion.create( model = "gpt-3.5-turbo", messages = [ {"role": "system", "content": "Juego de adivinar el animal, debes indicar pistas del animal sin mencionar su nombre"}, {"role": "system", "content": f"El animal que debes dar pistas es {animal}"}, {'role': 'user', 'content': f"creo que la respuesta es {input_user}"}, {"role": "system", "content": "Si la respuesta del usuario es incorrecta, proporciona otra pista sobre el animal. Valida que si la respuesta del usuario se apeoxima a la respuesta correcta y hazlo saber"}, ], temperature = 1, ) return response['choices'][0]['message']['content'] def main(): prompt, answer = get_clue() print(prompt) while True: user_input = input("Ingresa tu respuesta: ") if check_answer(user_input, answer): print("¡Correcto!") break else: print("Incorrecto, intenta de nuevo") pista = give_property(answer, user_input) print(pista) main() ```import openaiimport osfrom dotenv import load\_dotenvimport randomimport unicodedata load\_dotenv()API\_KEY = os.getenv("OPEN\_AI\_TOKEN")openai.api\_key = API\_KEY def get\_clue():    animals = \["Cocodrilo", "Mono", "Delfín", "Tiranosaurio", "Pez", "Pájaro", "Gato", "Perro", "Conejo", "Ratón", "Elefante", "Jirafa", "Cebra", "León", "Tigre", "Oso", "Puercoespín", "Canguro"]    random\_animal = random.choice(animals)    prompt = f"Adivina el animal que estoy pensando... "    return prompt, random\_animal def remove\_accents(input\_str):    nfkd\_form = unicodedata.normalize('NFKD', input\_str)    return ''.join(\[c for c in nfkd\_form if not unicodedata.combining(c)]) def check\_answer(user\_input, answer):    return remove\_accents(user\_input.lower()) == remove\_accents(answer.lower()) def give\_property(animal, input\_user):    response = openai.ChatCompletion.create(        model = "gpt-3.5-turbo",        messages = \[            {"role": "system", "content": "Juego de adivinar el animal, debes indicar pistas del animal sin mencionar su nombre"},            {"role": "system", "content": f"El animal que debes dar pistas es {animal}"},            {'role': 'user', 'content': f"creo que la respuesta es {input\_user}"},            {"role": "system", "content": "Si la respuesta del usuario es incorrecta, proporciona otra pista sobre el animal. Valida que si la respuesta del usuario se apeoxima a la respuesta correcta y hazlo saber"},        ],        temperature = 1,    )    return response\['choices']\[0]\['message']\['content'] def main():    prompt, answer = get\_clue()    print(prompt)        while True:        user\_input = input("Ingresa tu respuesta: ")        if check\_answer(user\_input, answer):            print("¡Correcto!")            break        else:            print("Incorrecto, intenta de nuevo")                pista = give\_property(answer, user\_input)                     print(pista)            main()

w8, si es la libreria random la que esta eligiendo la palabra con

random_word = random.choice(words)

entonces OpenAI no está eligiendo nada. Me parece importante aclarar esa parte por si hay alguien que desconozca sobre el lenguaje.
Creo que estaria chevere si corrigen el contenido de esta clase, que realmente siento que está bastante enredada en su explicación.

Creo que se puede mejorar la función get_clue() porque tiene 2 responsabilidades: elegir un animal y escribir un primer prompt.

Únicamente para fines de aprendizaje modifiqué la función check_answer para que funcionara con la API de OpenAI y compara sin tener en cuenta acentos o mayúsculas. Comprendo que probablemente no sea lo más optimo, pero lo hice para experimentar con la API

def check_answer(user_input, answer):
  response = openai.Completion.create(
      engine = 'text-davinci-003',
      prompt = f'''
Compara 2 palabras y si son iguales responde solo con un "True" en caso contrario responde solo con "False".
Ejemplo:
Q: palabras a comparar: agua, coca
A: False

Q: palabras a comparar {user_input}: , {answer}
A:
''',
      max_tokens = 100
  )
  if response.choices[0].text == "True":
    return True
  return False

Tambien se modificó el prompt de la función give_property ya que en ocasiones mencionaba al animal

def give_property(animal):
  response = openai.Completion.create(
      engine = 'text-davinci-003',
      prompt = 'Estás jugando a adivinar animales, debes dar una característica del animal, pero sin mencionar nunca que animal es\n'
      +'\nReglas: jamás decir el nombre del animal, decir características del animal\n'
      + 'Dame una característica de: '+ animal,
      max_tokens = 100
  )
  return response.choices[0].text

Resultados: