AIWordleImage / app.py
jonathang's picture
app.py
4e31db8 verified
import os
import json
import time
import enum
import uuid
import base64
import requests
import structlog
import gradio as gr
import random
import functools
logger = structlog.getLogger()
replicate_api_key = os.environ.get('REPLICATE_KEY')
# Everyone gets the same order of words
random.seed(42)
with open('five_letter_words.txt') as f:
words = f.read().splitlines()
random.shuffle(words)
random.seed()
class Image:
@classmethod
def create(cls, prompt, n=1, response_format="url", model="fofr", size="256x256"):
logger.info(f'requesting Image with prompt={prompt}, n={n}, response_format={response_format}, model={model}, size={size}...')
width, height = size.split('x')
width, height = int(width), int(height)
resp = requests.post(
"https://api.replicate.com/v1/predictions",
headers={"Content-Type": "application/json", "Authorization": f"Token {replicate_api_key}"},
json={"version": "a83d4056c205f4f62ae2d19f73b04881db59ce8b81154d314dd34ab7babaa0f1", "input": {
"prompt": prompt,
"width": width, "height": height,
"num_images": n,
}},
)
resp = resp.json()
sleeps = 0
while resp.get("status", "fail").lower() not in {"fail", "succeeded"}:
if sleeps >= 10:
raise Exception('Error generating image', resp)
logger.info(f"Sleeping 1...")
time.sleep(1)
sleeps += 1
resp = requests.get(f"https://api.replicate.com/v1/predictions/{resp['id']}", headers={"Content-Type": "application/json", "Authorization": f"Token {replicate_api_key}"})
resp = resp.json()
logger.info('received Image...')
url = resp['output'][0]
# Get the MIME type of the image (e.g., 'image/jpeg', 'image/png')
mime_type = f"image/{url.rsplit('.', 1)[-1]}"
# Encode to base64 and format as a data URI
return f"data:{mime_type};base64," + base64.b64encode(requests.get(url).content).decode()
@functools.cache
def get_image(word_num, guess_num):
prompt = words[word_num]
return Image.create(prompt)
def display_images_base64(image_strings):
# Start of the HTML string
html = '<html><body><div style="display: flex; flex-wrap: wrap;">'
# Template for an individual image
img_template = '<img src="{}" style="width: 30%; margin: 1%;" />'
# Loop through the list of image strings and append each to the HTML string
for img_str in image_strings:
html += img_template.format(img_str)
# Close the div and body tags
html += '</div></body></html>'
return html
def guess_word(word_num, guess, history=None):
word_num = abs(word_num) % len(words)
target = words[word_num]
guess = guess.lower()
feedback = []
if history is None:
history = {}
if word_num not in history:
history[word_num] = {
'guess': [],
'image': [],
}
if len(guess) != len(target):
feedback_str = "Guess must be {} letters long".format(len(target))
else:
for i, char in enumerate(guess):
if char == target[i]:
feedback.append('🟩') # Green for correct position
elif char in target:
feedback.append('🟨') # Yellow for correct letter, wrong position
else:
feedback.append('⬛') # Black for incorrect letter
feedback_str = "".join(feedback)
# Update and return the history with the current guess feedback
history[word_num]['guess'].append(f"{guess}: {feedback_str}")
# Get and update the image history
new_image = get_image(word_num, len(history[word_num]['guess']) + 1)
history[word_num]['image'].append(new_image)
return feedback_str, '\n'.join(history[word_num]['guess']), display_images_base64(history[word_num]['image']), history
interface = gr.Interface(fn=guess_word,
inputs=[
gr.Number(value=random.randint(0, 100_000), label='Word number (Cannot be empty)'),
gr.Textbox(lines=1, label="Enter your guess (Cannot be empty)"),
gr.State()],
outputs=["text", gr.Textbox(label="Guess History", interactive=False, lines=10), gr.HTML(label="Guess Images"), gr.State()],
title="Wordle with Gradio",
description="A simple Wordle clone with guess history. Try to guess the word 'python'!",
allow_flagging="never")
interface.launch()