Spaces:
Paused
Paused
File size: 9,364 Bytes
a293444 77b6f68 a293444 4e357cc a293444 77b6f68 a293444 77b6f68 a293444 4e357cc a293444 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
import json
import os
import random
import google.generativeai as genai
import gradio as gr
from jinja2 import Environment, FileSystemLoader
GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
genai.configure(api_key=GOOGLE_API_KEY)
model = genai.GenerativeModel("gemini-1.5-flash-latest",
generation_config={"response_mime_type": "application/json"})
def merge_games(clues, num_merges=10):
"""Generates around 10 merges of words from the given clues.
Args:
clues: A list of clues, where each clue is a list containing the words, the answer, and the explanation.
num_merges: The approximate number of merges to generate (default: 10).
Returns:
A list of tuples, where each tuple contains the merged words and the indices of the selected rows.
"""
merged = []
while len(merged) < num_merges:
num_rows = random.choice([3, 4])
selected_rows = random.sample(range(len(clues)), num_rows)
words_list = [word for row in [clues[i][0] for i in selected_rows] for word in row]
if len(words_list) in [8, 9]:
merged.append((words_list, selected_rows))
return merged
example_clues = [
(['ARROW', 'TIE', 'HONOR'], 'BOW', 'such as a bow and arrow, a bow tie, or a bow as a sign of honor'),
(['DOG', 'TREE'], 'BARK', 'such as the sound a dog makes, or a tree is made of bark'),
(['MONEY', 'RIVER', 'ROB', 'BLOOD'], 'CRIME', 'such as money being stolen, a river being a potential crime scene, '
'robbery, or blood being a result of a violent crime'),
(['BEEF', 'TURKEY', 'FIELD', 'GRASS'], 'GROUND',
'such as ground beef, a turkey being a ground-dwelling bird, a field or grass being a type of ground'),
(['BANK', 'GUITAR', 'LIBRARY'], 'NOTE',
'such as a bank note, a musical note on a guitar, or a note being a written comment in a library book'),
(['ROOM', 'PIANO', 'TYPEWRITER'], 'KEYS', 'such as a room key, piano keys, or typewriter keys'),
(['TRAFFIC', 'RADAR', 'PHONE'], 'SIGNAL', 'such as traffic signals, radar signals, or phone signals'),
(['FENCE', 'PICTURE', 'COOKIE'], 'FRAME',
'such as a frame around a yard, a picture frame, or a cookie cutter being a type of frame'),
(['YARN', 'VIOLIN', 'DRESS'], 'STRING', 'strings like material, instrument, clothing fastener'),
(['JUMP', 'FLOWER', 'CLOCK'], 'SPRING',
'such as jumping, flowers blooming in the spring, or a clock having a sprint component'),
(['SPY', 'KNIFE'], 'WAR',
'Both relate to aspects of war, such as spies being involved in war or knives being used as weapons'),
(['STADIUM', 'SHOE', 'FIELD'], 'SPORT', 'Sports like venues, equipment, playing surfaces'),
(['TEACHER', 'CLUB'], 'SCHOOL',
'such as a teacher being a school staff member or a club being a type of school organization'),
(['CYCLE', 'ARMY', 'COURT', 'FEES'], 'CHARGE', 'charges like electricity, battle, legal, payments'),
(['FRUIT', 'MUSIC', 'TRAFFIC', 'STUCK'], 'JAM',
'Jams such as fruit jam, a music jam session, traffic jam, or being stuck in a jam'),
(['POLICE', 'DOG', 'THIEF'], 'CRIME',
'such as police investigating crimes, dogs being used to detect crimes, or a thief committing a crime'),
(['ARCTIC', 'SHUT', 'STAMP'], 'SEAL',
'such as the Arctic being home to seals, or shutting a seal on an envelope, or a stamp being a type of seal'),
]
example_groupings = []
merges = merge_games(example_clues, 5)
for merged_words, indices in merges:
groups = [{
"words": example_clues[i][0],
"clue": example_clues[i][1],
"explanation": example_clues[i][2]
} for i in indices]
example_groupings.append((merged_words, json.dumps(groups, separators=(',', ':'))))
def render_jinja2_template(template, system_prompt, history, query):
env = Environment(loader=FileSystemLoader('.'))
template = env.from_string(template)
return template.render(system_prompt=system_prompt, history=history, query=query)
def group_words(words):
template = '''
{% for example in history %}
INPUT:
{{ example[0] }}
OUTPUT:
{{ example[1] }}
{% endfor %}
INPUT:
{{ query }}
OUTPUT:
{{ system }}
Groups = {'words': list[str], 'clue': str, 'explanation': str}
Return: Groups
'''
grouping_system_prompt = ("You are an assistant for the game Codenames. Your task is to help players by grouping a "
"given group of secrets into 3 to 4 groups of 2 to 4 words. Each group should consist of secrets that "
"share a common theme or other word connections such as homonym, hypernyms or synonyms. Avoid clues that are not too generic or not unique enough to be guessed easily")
prompt = render_jinja2_template(template, grouping_system_prompt, example_groupings, words)
# print(prompt)
raw_response = model.generate_content(
prompt,
generation_config={'top_k': 3, 'temperature': 1.1})
response = json.loads(raw_response.text)
print("Grouping words:", words)
print("Got groupings: ", json.dumps(response, indent=4))
return response
def generate_clues(group):
template = '''
{% for example in history %}
INPUT:
{{ example[0] }}
OUTPUT:
{ 'clue':{{ example[1] }}, 'explanation':{{ example[2] }} }
{% endfor %}
INPUT:
{{ query }}
OUTPUT:
{{ system }}
Clue = {'clue': str, 'explanation': str}
Return: Clue
'''
clue_system_prompt = ("You are a codenames game companion. Your task is to give a single word clue related to "
"a given group of words. You will only respond with a single word clue. The clue can be a common theme or other word connections such as homonym, hypernyms or synonyms. Avoid clues that are not too generic or not unique enough to be guessed easily")
prompt = render_jinja2_template(template, clue_system_prompt, example_clues, group)
raw_response = model.generate_content(
prompt,
generation_config={'top_k': 3, 'temperature': 1.1})
response = json.loads(raw_response.text)
print("Generating clues for: ", group)
print("Got clue: ", json.dumps(response, indent=4))
return response
def process_image(img):
raw_response = model.generate_content(['Identify the words in this game of Codenames. Provide only a list of '
'words. Provide the words in capital letters only. Group these words into '
'6 or 8 groups that can be guessed together using a single word clue in '
'the game of codenames. Give a response as json of the form: {"Game": '
'<list of words in the game>}', img], stream=True)
raw_response.resolve()
response = json.loads(raw_response.text)
words = response['Game']
return gr.update(choices=words, value=words)
with gr.Blocks() as demo:
gr.Markdown("# *Codenames* clue generator")
gr.Markdown("Provide a list of words to generate a clue")
with gr.Row():
game_image = gr.Image(type="pil")
word_list_input = gr.Dropdown(label="Detected words",
choices=[],
multiselect=True,
interactive=True)
with gr.Row():
detect_words_button = gr.Button("Detect Words")
group_words_button = gr.Button("Group Words")
dropdowns, buttons, outputs = [], [], []
for i in range(4):
with gr.Row():
group_input = gr.Dropdown(label=f"Group {i + 1}",
choices=[],
allow_custom_value=True,
multiselect=True,
interactive=True)
clue_button = gr.Button("Generate Clue", size='sm')
clue_output = gr.Textbox(label=f"Clue {i + 1}")
dropdowns.append(group_input)
buttons.append(clue_button)
outputs.append(clue_output)
def pad_or_truncate(lst, n=4):
# Ensure the length of the list is at most n
truncated_lst = lst[:n]
return truncated_lst + (n - len(truncated_lst)) * [None]
def group_words_callback(words):
groups = group_words(words)
groups = pad_or_truncate(groups, 4)
print("Got groups: ", groups, type(groups))
return [gr.update(value=groups[i]["words"], choices=words, info=groups[i]["explanation"]) for i in range(4)]
def generate_clues_callback(group):
print("Generating clues: ", group)
g = generate_clues(group)
return gr.update(value=g['clue'], info=g['explanation'])
detect_words_button.click(fn=process_image,
inputs=game_image,
outputs=[word_list_input])
group_words_button.click(fn=group_words_callback,
inputs=word_list_input,
outputs=dropdowns)
for i in range(4):
buttons[i].click(generate_clues_callback, inputs=dropdowns[i], outputs=outputs[i])
demo.launch(share=True, debug=True)
|