Errolmking commited on
Commit
56edf9e
·
1 Parent(s): e9a0dcc

Update app.py

Browse files

major update.
adding image, audio and other inputs.

Files changed (1) hide show
  1. app.py +594 -220
app.py CHANGED
@@ -1,17 +1,19 @@
1
- from langchain.docstore.document import Document
2
- from langchain.vectorstores import FAISS
3
- from langchain.embeddings.openai import OpenAIEmbeddings
4
- from langchain.memory.simple import SimpleMemory
 
 
 
 
 
5
 
 
6
  from langchain.chains import ConversationChain, LLMChain, SequentialChain
7
- from langchain.memory import ConversationBufferMemory
8
-
9
- from langchain.prompts import ChatPromptTemplate, PromptTemplate
10
- from langchain.document_loaders import UnstructuredFileLoader
11
-
12
  from langchain.chat_models import ChatOpenAI
 
13
  from langchain.llms import OpenAI
14
- from langchain.memory import ConversationSummaryMemory
15
 
16
  from langchain.callbacks import PromptLayerCallbackHandler
17
  from langchain.prompts.chat import (
@@ -20,32 +22,16 @@ from langchain.prompts.chat import (
20
  AIMessagePromptTemplate,
21
  HumanMessagePromptTemplate,
22
  )
 
23
 
24
- from langchain.schema import AIMessage, HumanMessage, SystemMessage
25
- from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
26
- from langchain.callbacks.base import BaseCallbackHandler
27
- import gradio as gr
28
-
29
- from threading import Thread
30
- from queue import Queue, Empty
31
- from threading import Thread
32
- from collections.abc import Generator
33
- from langchain.llms import OpenAI
34
- from langchain.callbacks.base import BaseCallbackHandler
35
-
36
- import itertools
37
- import time
38
- import os
39
- import getpass
40
- import json
41
- import sys
42
- from typing import Any, Dict, List, Union
43
 
44
  import promptlayer
45
- import openai
46
- import gradio as gr
 
47
 
48
- from pydantic import BaseModel, Field, validator
 
49
 
50
  from threading import Thread
51
  from queue import Queue, Empty
@@ -53,6 +39,8 @@ from threading import Thread
53
  from collections.abc import Generator
54
  from langchain.llms import OpenAI
55
  from langchain.callbacks.base import BaseCallbackHandler
 
 
56
 
57
  #Load the FAISS Model ( vector )
58
  openai.api_key = os.environ["OPENAI_API_KEY"]
@@ -73,193 +61,96 @@ class QueueCallback(BaseCallbackHandler):
73
  def on_llm_end(self, *args, **kwargs: Any) -> None:
74
  return self.q.empty()
75
 
76
- MODEL = "gpt-4"
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- class GenerativeGameAgent:
 
 
 
 
 
79
 
80
- def __init__(self, model_name=MODEL, verbose=True, temp=0.2):
81
- self.conversation = ConversationChain
82
  self.llm = ChatOpenAI(
83
  model_name=model_name,
84
- callbacks=[PromptLayerCallbackHandler(pl_tags=["scenario-maker"])],
 
 
85
  streaming=False,
 
86
  )
87
 
88
- self.history = [] #A record of the overall conversation. To be used for analytics.
89
  self.memory = ConversationSummaryMemory(llm=self.llm,
90
  max_token_limit=200,
91
  memory_key="memory",
92
  input_key="input")
93
  self.verbose = verbose
94
- self.engine = None
95
  self.last_msg = ""
 
96
 
97
- def chain(self, prompt: PromptTemplate, llm: ChatOpenAI) -> LLMChain:
 
 
 
 
 
 
 
98
  return LLMChain(
99
  llm=llm,
100
  prompt=prompt,
101
  verbose=self.verbose,
102
- memory=self.memory
103
  )
104
 
 
 
 
 
 
 
 
105
 
106
- #Agent can run an analysis on the scenario and provide feedback to the player.
107
- def analyze_history(self):
108
- print("TODO: Build out analyze history function.")
109
-
110
- #Pass the agent a prompt.
111
- #The agent will convert the prompt into a scenario config.
112
- #Then set the agent's engine to the scenario config.
113
- def build_engine(self, input: str) -> str:
114
- txt2rpg_prompt = """
115
- The following is an example of a sudolang style prompt for an ai rpg game ( delimited by the triple dollar signs)
116
- $$$
117
- Lets role play. you are a text rpg adventure game.
118
-
119
- StoryWorld [
120
- generate(settings) [
121
- Generate a new serene and enlightening story world, setting the player as the protagonist.
122
- for each prop in StoryWorld [
123
- prop = ""
124
- ]
125
- for each prop in StoryWorld [
126
- log("Please select an option for $prop or type your own.")
127
- options = list 7 tranquil and profound options, selecting from a myriad of serene and contemplative options fitting within the new story world context |>
128
- score by player engagement potential |>
129
- list the top 3 options.
130
-
131
- input = wait for user input.
132
-
133
- DO NOT move on to the next prop until the user has responded.
134
- DO NOT perform any actions on the user's behalf.
135
- ]
136
- ]
137
- Genre: ZenEscape
138
- Authors to emulate: Dogen Zenji, Shunryu Suzuki, Thich Nhat Hanh
139
- Theme: Attaining enlightenment through introspection and realization to break free from the illusionary confines of the mind
140
- Setting: A metaphysical and ephemeral escape room that represents the mind, set within the boundless realm of Zen, filled with symbolic objects and serene landscapes
141
- Plot: The player, a Zen seeker, is navigating through various puzzles and koans to understand the essence of existence and attain enlightenment
142
- Characters:
143
- $PlayerName - The Zen seeker protagonist
144
- Master Hakuin - The wise and elusive Zen master who guides the player through riddles and reflections
145
- The Silent Monk - A mysterious figure who communicates through actions, symbolizing the non-verbal aspect of Zen
146
- World mechanics: Proverbial doors unlocking with realized truths, objects that represent Zen principles, riddles that lead to higher consciousness
147
- History: The escape room is a manifestation of Zen teachings and principles, created by ancient Zen masters to guide seekers towards enlightenment
148
- Central conflict: The internal struggle of the seeker to overcome illusions and perceive the true nature of reality, breaking the chains of the mental escape room
149
- ]
150
-
151
- Inventory [
152
- items: [
153
- [[item]]: [ name, description, weight ]
154
- ];
155
- totalWeight;
156
-
157
- When the player acquires an item, add it to the inventory, inferring all required information to satisfy the constraints.
158
-
159
- constraints [
160
- The total weight must always be known and reflect the total item weights, which must also be always known.
161
-
162
- If the player acquires an object with unknown properties, infer the properties from the context.
163
-
164
- If the player inventory is filled with unnecessary thoughts or possessions, the player will gradually become burdened and slowed down.
165
-
166
- If the player attempts to hold onto too many illusions, they should quickly become overwhelmed and need to let go.
167
-
168
- If the player tries to grasp something beyond their understanding, they should fail.
169
-
170
- Infer weight rule adjustments based on player insight and equipped wisdom.
171
-
172
- Don't explain the constraint-solving process.
173
- ]
174
- display() [
175
- Aliases: contemplate, reflect, observe, perceive, etc. Adjust detail based on context.
176
- Format as markdown list.
177
- ]
178
- ]
179
-
180
- Player [
181
- Points [
182
- wisdom;
183
- insight;
184
- mindfulness;
185
- constraints: [
186
- Maximum 10 points per attribute.
187
- Maximum 15 total points.
188
- ]
189
- ]
190
- ]
191
-
192
- Quests [
193
- Profound challenges, puzzles, or reflections that consist of a spiritual journey and multiple steps of realization.
194
-
195
- active quests;
196
- completed quests;
197
-
198
- Constraints [
199
- Quests should be automatically inferred during gameplay.
200
- Quest logs must always be kept in sync.
201
- The gameplay should actively present engaging and enlightening challenges to the player.
202
- ]
203
- ]
204
-
205
- Start game [
206
- Present the user with a randomly initialized character. Constraint: Points must total 15.
207
- Ask if they would like to keep it or manually distribute 15 points among their attributes.
208
- Allow the player to set their own name or description (including outfit).
209
- The character's described robes and possessions can not affect their stats.
210
- Automatically add items from the player's description to their inventory, equipped.
211
- ]
212
-
213
- While playing [
214
- Describe scene.
215
- If there are nearby characters, list.
216
- If there are any meaningful objects nearby, list.
217
- If there are obvious paths to realization, list.
218
- If the user is currently on quests
219
- Prompt and wait for user input.
220
- constraints [
221
- Do not perform actions on the user's behalf. Wait for input.
222
- Do not list inventory unless requested.
223
- ]
224
- ]
225
-
226
- Let's roleplay.
227
- You are the game engine.
228
- I am the player.
229
- At each prompt, pause and wait for my input.
230
- Do not refer to yourself.
231
-
232
- $$$
233
-
234
- Do the following:
235
- Copy the StoryWorld structure above but change the narrative content to reflect the ideas presented below ( delimited by triple astrisks)
236
- ***
237
- {input}
238
- ***
239
- """
240
  prompt = PromptTemplate(
241
  input_variables=['input'],
242
- template=txt2rpg_prompt
 
243
  )
244
-
245
- response = self.chain(prompt,self.llm).run(
246
  {'input':input})
247
 
248
- self.engine = response + """
249
- Here is a summary of the game up until now (delimited by triple percent signs):
 
250
  %%%
251
  {memory}
252
  %%%
253
 
254
- Here is the last input from the player (delimited by triple astrisks):
 
255
  ***
256
  {input}
257
  ***
258
-
259
  """
260
- return self.engine
 
 
 
 
261
 
262
  def stream(self, input) -> Generator:
 
 
263
  # Create a Queue
264
  q = Queue()
265
  job_done = object()
@@ -267,20 +158,20 @@ class GenerativeGameAgent:
267
  llm = ChatOpenAI(
268
  model_name=MODEL,
269
  callbacks=[QueueCallback(q),
270
- PromptLayerCallbackHandler(pl_tags=["scenario-maker"])],
271
  streaming=True,
272
  verbose=self.verbose
273
 
274
  )
275
-
276
  prompt = PromptTemplate(
277
  input_variables=['input','memory'],
278
- template=self.engine
 
279
  )
280
 
281
  # Create a funciton to call - this will run in a thread
282
  def task():
283
- resp = self.chain(prompt,llm).run(
284
  {'input':input,
285
  'memory':self.memory.load_memory_variables({})})
286
  q.put(job_done)
@@ -298,49 +189,532 @@ class GenerativeGameAgent:
298
  if next_token is job_done:
299
  break
300
  content += next_token
301
- yield next_token, content
302
  except Empty:
303
- continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
 
305
- def visualize_state(self):
 
 
 
 
 
 
 
 
306
  response = openai.Image.create(
307
- prompt=self.last_message,
308
  n=1,
309
  size="512x512"
310
  )
311
  image_url = response['data'][0]['url']
312
- return image_url
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
 
314
- def action(self, input, history):
315
- self.last_msg = ""
316
- for next_token, content in self.stream(input):
317
- self.last_msg += next_token
318
- yield(content)
319
 
320
- gameAgent = GenerativeGameAgent()
 
 
 
 
 
 
 
321
  app = gr.Blocks(theme=gr.themes.Soft())
322
 
323
  with app:
324
- with gr.Row(scale=1):
325
- with gr.Column(scale=1):
326
- gr.Markdown(
327
- """
328
- # Scenario Maker
329
- Describe a scenario.
330
- Generate a scenario.config ( ~2 minutes )
331
- Use the chatbot.
332
- """)
333
-
334
- world_description = gr.Textbox(label="Describe the scenario")
335
- generate_world_btn = gr.Button("Generate Scenario",)
336
- world_engine = gr.TextArea(label="scenario.config", interactive=False, visible=True)
337
-
338
- generate_world_btn.click(gameAgent.build_engine, inputs=world_description, outputs=world_engine)
339
- with gr.Column(scale=3):
340
- gr.ChatInterface(gameAgent.action,
341
- theme="soft",
342
- retry_btn=None,
343
- undo_btn=None,
344
- clear_btn=None
345
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  app.queue().launch()
 
1
+ import time
2
+ import os
3
+ import openai
4
+ import json
5
+ from threading import Thread
6
+ from queue import Queue, Empty
7
+ from threading import Thread
8
+ from collections.abc import Generator
9
+ from typing import Any, Dict, List, Union
10
 
11
+ from langchain.vectorstores import FAISS
12
  from langchain.chains import ConversationChain, LLMChain, SequentialChain
 
 
 
 
 
13
  from langchain.chat_models import ChatOpenAI
14
+ from langchain.prompts import ChatPromptTemplate, PromptTemplate
15
  from langchain.llms import OpenAI
16
+ from langchain.callbacks.base import BaseCallbackHandler
17
 
18
  from langchain.callbacks import PromptLayerCallbackHandler
19
  from langchain.prompts.chat import (
 
22
  AIMessagePromptTemplate,
23
  HumanMessagePromptTemplate,
24
  )
25
+ from langchain.memory import ConversationSummaryMemory
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  import promptlayer
29
+ from pathlib import Path
30
+ from transformers import pipeline
31
+ import requests
32
 
33
+ import torch
34
+ from diffusers import StableDiffusionPipeline
35
 
36
  from threading import Thread
37
  from queue import Queue, Empty
 
39
  from collections.abc import Generator
40
  from langchain.llms import OpenAI
41
  from langchain.callbacks.base import BaseCallbackHandler
42
+ import gradio as gr
43
+
44
 
45
  #Load the FAISS Model ( vector )
46
  openai.api_key = os.environ["OPENAI_API_KEY"]
 
61
  def on_llm_end(self, *args, **kwargs: Any) -> None:
62
  return self.q.empty()
63
 
64
+ MODEL='gpt-4'
65
+
66
+ class ScenarioMaker:
67
+
68
+ def __init__(self,
69
+ model_name=MODEL,
70
+ scenario_config=None,
71
+ scenario_template=None,
72
+ pl_tag="scenario_maker",
73
+ verbose=True,
74
+ visual_style=None,
75
+ temp=0.2):
76
 
77
+ self.prompt_layer_tag = pl_tag #Prompt layer used for analytics
78
+ self.visual_style = visual_style #The visual style used to make the scenario
79
+ self.scenario_template = scenario_template #The root template used to make the scenario
80
+ self.scenario_config = scenario_config #the prompt that is powering the chat/streaming
81
+ self.scene_to_img_prompt = "From the scene choose a single visual object as a focal point and capture its essence in a comma separated list of 5 words." # How to best extract the words from the scene
82
+ self.conversation = ConversationChain #?
83
 
 
 
84
  self.llm = ChatOpenAI(
85
  model_name=model_name,
86
+ callbacks=[PromptLayerCallbackHandler(
87
+ pl_tags=[self.prompt_layer_tag])
88
+ ],
89
  streaming=False,
90
+ verbose=verbose
91
  )
92
 
 
93
  self.memory = ConversationSummaryMemory(llm=self.llm,
94
  max_token_limit=200,
95
  memory_key="memory",
96
  input_key="input")
97
  self.verbose = verbose
 
98
  self.last_msg = ""
99
+ self.history = [] #A record of the overall conversation.
100
 
101
+ ############################################################
102
+ # Chain - A langchain util to run inference from a prompt template
103
+ ############################################################
104
+
105
+ def chain(self,
106
+ prompt: PromptTemplate,
107
+ llm: ChatOpenAI,
108
+ mem: ConversationSummaryMemory) -> LLMChain:
109
  return LLMChain(
110
  llm=llm,
111
  prompt=prompt,
112
  verbose=self.verbose,
113
+ memory=mem
114
  )
115
 
116
+ ############################################################
117
+ # Pass the agent a prompt.
118
+ # The agent will convert the prompt into a scenario config.
119
+ # Then set the agent's engine to the scenario config.
120
+ ############################################################
121
+
122
+ def prompt_to_scenario(self, input: str) -> str:
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  prompt = PromptTemplate(
125
  input_variables=['input'],
126
+ template=self.scenario_template,
127
+ validate_template=False
128
  )
129
+ response = self.chain(prompt,self.llm,self.memory).run(
 
130
  {'input':input})
131
 
132
+ self.scenario_config = response + """
133
+ Here is a summary of the game up until now \
134
+ (delimited by triple percent signs):
135
  %%%
136
  {memory}
137
  %%%
138
 
139
+ Here is the last input from the player \
140
+ (delimited by triple astrisks):
141
  ***
142
  {input}
143
  ***
 
144
  """
145
+ return self.scenario_config
146
+
147
+ ############################################################
148
+ # STREAM -- Text prompt returns a streaming response.
149
+ ############################################################
150
 
151
  def stream(self, input) -> Generator:
152
+ print("> stream")
153
+ print(input)
154
  # Create a Queue
155
  q = Queue()
156
  job_done = object()
 
158
  llm = ChatOpenAI(
159
  model_name=MODEL,
160
  callbacks=[QueueCallback(q),
161
+ PromptLayerCallbackHandler(pl_tags=[self.prompt_layer_tag])],
162
  streaming=True,
163
  verbose=self.verbose
164
 
165
  )
 
166
  prompt = PromptTemplate(
167
  input_variables=['input','memory'],
168
+ template=self.scenario_config,
169
+ validate_template=False
170
  )
171
 
172
  # Create a funciton to call - this will run in a thread
173
  def task():
174
+ resp = self.chain(prompt,llm,self.memory).run(
175
  {'input':input,
176
  'memory':self.memory.load_memory_variables({})})
177
  q.put(job_done)
 
189
  if next_token is job_done:
190
  break
191
  content += next_token
192
+ yield next_token
193
  except Empty:
194
+ break
195
+
196
+ ############################################################
197
+ # History to Scene: Takes the last message of the chat history
198
+ # returns a compressed and prompt ready visual description.
199
+ ############################################################
200
+
201
+ def scene_to_img(self, last_message):
202
+ prompt_temp = '''
203
+ The message below ( delimited by triple dollar signs) \
204
+ is a description of a scene.
205
+ $$$
206
+ {last_message}
207
+ $$$
208
+ ''' + self.scene_to_img_prompt
209
+ prompt = PromptTemplate(
210
+ input_variables=['last_message'],
211
+ template=prompt_temp,
212
+ validate_template=False
213
+ )
214
+
215
+ llm = ChatOpenAI(
216
+ model_name=MODEL,
217
+ callbacks=[PromptLayerCallbackHandler(
218
+ pl_tags=[self.prompt_layer_tag])
219
+ ],
220
+ streaming=False,
221
+ verbose=True
222
+ )
223
+
224
+ resp = self.chain(prompt,llm,None).run(
225
+ {'last_message':last_message})
226
+
227
+ return resp
228
 
229
+ ###########################################################################
230
+ # Generate Image: Style + Scene description returns an image!
231
+ ###########################################################################
232
+
233
+
234
+ def generate_image(self, chatbot):
235
+ imagery = self.scene_to_img(chatbot[-1][1])
236
+ img_prompt = imagery + " " + self.visual_style
237
+ print(img_prompt)
238
  response = openai.Image.create(
239
+ prompt=img_prompt,
240
  n=1,
241
  size="512x512"
242
  )
243
  image_url = response['data'][0]['url']
244
+ return image_url,img_prompt
245
+
246
+
247
+ def generate_image_sd(self, prompt):
248
+ prompt = "manga style illustration, highly detailed, of an alien bartender"
249
+ image = pipe(prompt).images[0] # image here is in [PIL format](https://pillow.readthedocs.io/en/stable/)
250
+
251
+ # Now to display an image you can either save it such as:
252
+ image.save(f"astronaut_rides_horse.png")
253
+
254
+ # or if you're in a google colab you can directly display it with
255
+ image
256
+
257
+ ###########################################################################
258
+ # Handle User Action: Appends history
259
+ ###########################################################################
260
+
261
+ def handle_user_input(self, user_message, history):
262
+ print("> handle_user_input")
263
+ print(user_message, history)
264
+ return "", history + [[user_message, None]]
265
+
266
+ ###########################################################################
267
+ # Request_Streaming_Response: Takes last message from history and sends to llm
268
+ ###########################################################################
269
+
270
+ def request_streaming_response(self, history):
271
+ print("> request_streaming_response")
272
+ print(history)
273
+ next_scene = self.stream(history[-1][0])
274
+ history[-1][1] = ""
275
+ for token in next_scene:
276
+ history[-1][1] += token
277
+ time.sleep(0.05)
278
+ yield history
279
+
280
+ ###########################################################################
281
+ # Request_Streaming_Response: Takes last message from history and sends to llm
282
+ ###########################################################################
283
+
284
+ def speak(self, text, fname='last_msg', stability=0.1, sim_boost=0.1):
285
+ print("Speak")
286
+ if type(text) == list:
287
+ text = text[-1][1]
288
+ url = "https://api.elevenlabs.io/v1/text-to-speech/WyGtHt3dfZxX5j0a2VVm"
289
+ CHUNK_SIZE = 1024
290
+ headers = {
291
+ "Accept": "audio/mpeg",
292
+ "Content-Type": "application/json",
293
+ "xi-api-key": 'ddee36beeeef20f92a9ba5662fd2d13d'
294
+ }
295
+ data = {
296
+ "text": text,
297
+ "model_id": "eleven_monolingual_v1",
298
+ "voice_settings": {
299
+ "stability": stability,
300
+ "similarity_boost":sim_boost
301
+ }
302
+ }
303
+
304
+ response = requests.post(url, json=data, headers=headers)
305
+ print(response)
306
+ filename = str(fname)+'.mp3'
307
+
308
+ with open(filename, 'wb') as f:
309
+ for chunk in response.iter_content(chunk_size=CHUNK_SIZE):
310
+ if chunk:
311
+ f.write(chunk)
312
+ return filename
313
+
314
+
315
+ ########################################################################################
316
+ # show_and_tell() --> a single function that combines the production image and audio
317
+ ########################################################################################
318
+
319
+ def show_and_tell(self,history,gen_img,gen_audio):
320
+ if gen_audio is True:
321
+ audio = self.speak(history)
322
+ else:
323
+ audio = None
324
+
325
+ if gen_img is True:
326
+ image = self.generate_image(history)
327
+ else:
328
+ image = [None,None]
329
+
330
+ return audio, image[0], image[1]
331
+
332
+ ########################################################################################
333
+ # Update Style
334
+ ########################################################################################
335
+
336
+ def set_visual_style(self,style):
337
+ self.visual_style = style
338
+
339
+ ########################################################################################
340
+ # Set scene to image prompt
341
+ ########################################################################################
342
+
343
+ def set_scene_to_img_prompt(self,prompt):
344
+ self.scene_to_img_prompt = prompt
345
+
346
+ ########################################################################################
347
+ # Set Scenario Template
348
+ ########################################################################################
349
+ def set_scenario_template(self,template):
350
+ self.scenario_template = template
351
+
352
+ ########################################################################################
353
+ # Load Scenario Configuration
354
+ ########################################################################################
355
+ def load_scenario_config(self,scenario_config):
356
+ self.scenario_config = scenario_config
357
+
358
+ #########
359
+
360
+ scenario_template = """
361
+ The following is an example of a sudolang style prompt for an ai rpg game ( delimited by the triple dollar signs)
362
+ $$$
363
+ Lets role play. you are a text rpg adventure game.
364
+
365
+ StoryWorld [
366
+ generate(settings) [
367
+ Generate a new serene and enlightening story world, setting the player as the protagonist.
368
+ for each prop in StoryWorld [
369
+ prop = ""
370
+ ]
371
+ for each prop in StoryWorld [
372
+ log("Please select an option for $prop or type your own.")
373
+ options = list 7 tranquil and profound options, selecting from a myriad of serene and contemplative options fitting within the new story world context |>
374
+ score by player engagement potential |>
375
+ list the top 3 options.
376
+
377
+ input = wait for user input.
378
+
379
+ DO NOT move on to the next prop until the user has responded.
380
+ DO NOT perform any actions on the user's behalf.
381
+ ]
382
+ ]
383
+ Genre: ZenEscape
384
+ Authors to emulate: Dogen Zenji, Shunryu Suzuki, Thich Nhat Hanh
385
+ Theme: Attaining enlightenment through introspection and realization to break free from the illusionary confines of the mind
386
+ Setting: A metaphysical and ephemeral escape room that represents the mind, set within the boundless realm of Zen, filled with symbolic objects and serene landscapes
387
+ Plot: The player, a Zen seeker, is navigating through various puzzles and koans to understand the essence of existence and attain enlightenment
388
+ Characters:
389
+ $PlayerName - The Zen seeker protagonist
390
+ Master Hakuin - The wise and elusive Zen master who guides the player through riddles and reflections
391
+ The Silent Monk - A mysterious figure who communicates through actions, symbolizing the non-verbal aspect of Zen
392
+ World mechanics: Proverbial doors unlocking with realized truths, objects that represent Zen principles, riddles that lead to higher consciousness
393
+ History: The escape room is a manifestation of Zen teachings and principles, created by ancient Zen masters to guide seekers towards enlightenment
394
+ Central conflict: The internal struggle of the seeker to overcome illusions and perceive the true nature of reality, breaking the chains of the mental escape room
395
+ ]
396
+
397
+ Inventory [
398
+ items: [
399
+ [[item]]: [ name, description, weight ]
400
+ ];
401
+ totalWeight;
402
+
403
+ When the player acquires an item, add it to the inventory, inferring all required information to satisfy the constraints.
404
+
405
+ constraints [
406
+ The total weight must always be known and reflect the total item weights, which must also be always known.
407
+
408
+ If the player acquires an object with unknown properties, infer the properties from the context.
409
+
410
+ If the player inventory is filled with unnecessary thoughts or possessions, the player will gradually become burdened and slowed down.
411
+
412
+ If the player attempts to hold onto too many illusions, they should quickly become overwhelmed and need to let go.
413
+
414
+ If the player tries to grasp something beyond their understanding, they should fail.
415
+
416
+ Infer weight rule adjustments based on player insight and equipped wisdom.
417
+
418
+ Don't explain the constraint-solving process.
419
+ ]
420
+ display() [
421
+ Aliases: contemplate, reflect, observe, perceive, etc. Adjust detail based on context.
422
+ ]
423
+ ]
424
+
425
+ Player [
426
+ Points [
427
+ wisdom;
428
+ insight;
429
+ mindfulness;
430
+ constraints: [
431
+ Points starts at 0.
432
+ Maximum 3 points per attribute.
433
+ Maximum 9 total points.
434
+ ]
435
+ ]
436
+ ]
437
+
438
+ Quests [
439
+ Profound challenges, puzzles, or reflections that consist of a spiritual journey and multiple steps of realization.
440
+
441
+ active quests;
442
+ completed quests;
443
+
444
+ Constraints [
445
+ Quests should be automatically inferred during gameplay.
446
+ Quest logs must always be kept in sync.
447
+ The gameplay should actively present engaging and enlightening challenges to the player.
448
+ ]
449
+ ]
450
+
451
+ Start game [
452
+ get_player_name()
453
+ cinematic_introduction()
454
+ ]
455
+
456
+ While playing [
457
+ Briefly but cinematically describe the scene including nearby characters and objects.
458
+ Prompt and wait for user input.
459
+ constraints [
460
+ Do not perform actions on the user's behalf. Wait for input.
461
+ Do not list inventory unless requested.
462
+ Do not refer to yourself.
463
+ Do not refer to the game engine.
464
+ ]
465
+ ]
466
+
467
+ Let's roleplay.
468
+ You are the game engine.
469
+ I am the player.
470
+ At each prompt, pause and wait for my input.
471
+
472
+ $$$
473
+
474
+ Do the following:
475
+ Copy the StoryWorld structure above but change the narrative content to reflect the ideas presented below ( delimited by triple astrisks)
476
+ ***
477
+ {input}
478
+ ***
479
+ """
480
+
481
+ scenario_config = """
482
+ StoryWorld [
483
+ generate(settings) [
484
+ Generate a new soothing and rejuvenating story world, setting the player as the protagonist.
485
+ for each prop in StoryWorld [
486
+ prop = ""
487
+ ]
488
+ for each prop in StoryWorld [
489
+ log("Please select an option for $prop or type your own.")
490
+ options = list 7 calming and refreshing options, selecting from a myriad of serene and tranquil options fitting within the new story world context |>
491
+ score by player engagement potential |>
492
+ list the top 3 options.
493
+
494
+ input = wait for user input.
495
+
496
+ DO NOT move on to the next prop until the user has responded.
497
+ DO NOT perform any actions on the user's behalf.
498
+ ]
499
+ ]
500
+ Genre: ForestBathing
501
+ Authors to emulate: Shinrin Yoku, Richard Louv, Florence Williams
502
+ Theme: Experiencing healing and rejuvenation through immersion in the forest, breaking free from stress and anxiety
503
+ Setting: A lush and tranquil forest, filled with the sounds of nature, the scent of trees and the play of sunlight through leaves
504
+ Plot: The player, a nature enthusiast, is navigating through various forest trails and experiences to understand the healing power of nature and attain inner peace
505
+ Characters:
506
+ $PlayerName - The nature enthusiast protagonist
507
+ Forest Spirit - The wise and gentle spirit of the forest who guides the player through the healing power of nature
508
+ The Silent Deer - A mysterious figure who communicates through actions, symbolizing the silent wisdom of the forest
509
+ World mechanics: Healing springs appearing with realized truths, objects that represent forest principles, experiences that lead to inner peace
510
+ History: The forest is a manifestation of the healing power of nature, created by ancient forest spirits to guide seekers towards inner peace
511
+ Central conflict: The internal struggle of the seeker to overcome stress and anxiety and perceive the true healing power of nature, breaking the chains of the mental stress
512
+
513
+ ]
514
+
515
+ Inventory [
516
+ items: [
517
+ [[item]]: [ name, description, weight ]
518
+ ];
519
+ totalWeight;
520
+
521
+ When the player acquires an item, add it to the inventory, inferring all required information to satisfy the constraints.
522
+
523
+ constraints [
524
+ The total weight must always be known and reflect the total item weights, which must also be always known.
525
+
526
+ If the player acquires an object with unknown properties, infer the properties from the context.
527
+
528
+ If the player inventory is filled with unnecessary thoughts or worries, the player will gradually become burdened and slowed down.
529
+
530
+ If the player attempts to hold onto too many anxieties, they should quickly become overwhelmed and need to let go.
531
+
532
+ If the player tries to grasp something beyond their understanding, they should fail.
533
+
534
+ Infer weight rule adjustments based on player insight and equipped wisdom.
535
+
536
+ Don't explain the constraint-solving process.
537
+ ]
538
+ display() [
539
+ Aliases: contemplate, reflect, observe, perceive, etc. Adjust detail based on context.
540
+ ]
541
+ ]
542
+
543
+ Player [
544
+ Points [
545
+ wisdom;
546
+ insight;
547
+ mindfulness;
548
+ constraints: [
549
+ Maximum 10 points per attribute.
550
+ Maximum 15 total points.
551
+ ]
552
+ ]
553
+ ]
554
+
555
+ Quests [
556
+ Healing challenges, experiences, or reflections that consist of a nature journey and multiple steps of realization.
557
+
558
+ active quests;
559
+ completed quests;
560
+
561
+ Constraints [
562
+ Quests should be automatically inferred during gameplay.
563
+ Quest logs must always be kept in sync.
564
+ The gameplay should actively present engaging and rejuvenating challenges to the player.
565
+ ]
566
+ ]
567
+
568
+ Start game [
569
+ get_player_name()
570
+ cinematic_introduction()
571
+ ]
572
+
573
+ While playing [
574
+ Describe scene.
575
+ Prompt and wait for user input.
576
+ constraints [
577
+ Do not perform actions on the user's behalf. Wait for input.
578
+ Do not list inventory unless requested.
579
+ ]
580
+ ]
581
+
582
+ Let's roleplay.
583
+ You are the game engine.
584
+ I am the player.
585
+ At each prompt, pause and wait for my input.
586
+ Do not refer to yourself.
587
+
588
+ Here is a summary of the game up until now (delimited by triple percent signs):
589
+ %%%
590
+ {memory}
591
+ %%%
592
+
593
+ Here is the last input from the player (delimited by triple astrisks):
594
+ ***
595
+ {input}
596
+ ***
597
+
598
+ """
599
+
600
+
601
+
602
 
 
 
 
 
 
603
 
604
+
605
+ scenario_maker = ScenarioMaker(scenario_template=scenario_template,
606
+ scenario_config=scenario_config,
607
+ visual_style='''
608
+ detailed comic book cover art in the style of Hayao Miyazaki.
609
+ very detailed. vibrant colors. digital illustration. soft cinematic lighting.
610
+ ''')
611
+
612
  app = gr.Blocks(theme=gr.themes.Soft())
613
 
614
  with app:
615
+ #UI
616
+ gr.Markdown(
617
+ """
618
+ # Scenario Maker
619
+ Scenarios are goal-based stories where a player's choice impacts the outcome.
620
+ Scenarios are a form of immersive learning.
621
+ """)
622
+ with gr.Tab("Play"):
623
+ with gr.Row():
624
+ with gr.Column(scale=2):
625
+ with gr.Row():
626
+ chatbot = gr.Chatbot(show_label=False,
627
+ interactive=True)
628
+ with gr.Group():
629
+ with gr.Row():
630
+
631
+ msg = gr.Textbox(label="Act",
632
+ placeholder='Type your action...',scale=1)
633
+ msg_btn = gr.Button("Submit",scale=0)
634
+
635
+ with gr.Column(scale=0):
636
+
637
+ #Audio Generator Interface
638
+ with gr.Accordion("Voice Narration",open=False):
639
+ gen_audio = gr.Checkbox(label="Auto-generate Narration", value=False)
640
+ with gr.Group():
641
+ audio = gr.Audio(label="Listen",type="filepath",autoplay=True)
642
+ audio_btn = gr.Button("Generate")
643
+ audio_btn.click(scenario_maker.speak, inputs=chatbot, outputs=audio)
644
+
645
+ with gr.Accordion("Visualize Scene",open=False):
646
+
647
+ gen_img = gr.Checkbox(label="Auto-generate Image", value=False)
648
+
649
+ #Image Generator Interface
650
+ img = gr.Image(interactive=False,
651
+ label="Image",
652
+ show_share_button=True)
653
+ img_prompt = gr.TextArea(label="Debug: Scene to Image + Style",
654
+ interactive=False)
655
+ scene_to_img_prompt = gr.TextArea(label="Scene to Image Prompt",
656
+ interactive=True,)
657
+ style_prompt = gr.TextArea(label="Style",
658
+ interactive=True)
659
+ gen_img_btn = gr.Button("Generate Image")
660
+ gen_img_btn.click(scenario_maker.generate_image, inputs=chatbot, outputs=[img,img_prompt])
661
+
662
+
663
+ with gr.Tab("Build"):
664
+ with gr.Row():
665
+ with gr.Column():
666
+ gr.Markdown(
667
+ """
668
+ ### How to Build a Scenario:
669
+ 1. Describe the scenario in the text field below.
670
+ 2. Press the 'Generate Scenario' button. This process usually takes 2 minutes.
671
+ 3. Once the new 'scenario.config' is loaded head back over to the play tab.
672
+
673
+ ### For best results, be descriptive and use the following template:
674
+
675
+ - *Setting*: Where does the scenario take place?
676
+ - *Characters*: Who are the characters? What are they like?
677
+ - *Goal*: What is the goal of the scenario?
678
+ - *Constraints*: What are the constraints of the scenario?
679
+ - *Learning Objective*: What do you hope the player learns from the scenario?
680
+
681
+ """)
682
+ with gr.Column():
683
+ with gr.Group():
684
+ scenario_description = gr.TextArea(label="Scenario Description")
685
+ generate_scenario_btn = gr.Button("Generate Scenario")
686
+ with gr.Group():
687
+ scenario_config = gr.TextArea(label="Scenario.config",
688
+ interactive=True, visible=True, show_copy_button=True)
689
+ load_scenario_btn = gr.Button("Load Scenario")
690
+ with gr.Accordion("Tools",open=False):
691
+ with gr.Group():
692
+ scenario_template = gr.TextArea(label="Scenario Template",
693
+ interactive=True)
694
+ scenario_btn = gr.Button("Update Scenario Template")
695
+ #Events
696
+ generate_scenario_btn.click(scenario_maker.prompt_to_scenario,
697
+ inputs=scenario_description,
698
+ outputs=scenario_config)
699
+
700
+
701
+ #Events
702
+
703
+ scene_to_img_prompt.change(scenario_maker.set_scene_to_img_prompt, scene_to_img_prompt, None)
704
+ style_prompt.change(scenario_maker.set_visual_style, style_prompt, None)
705
+
706
+ load_scenario_btn.click(scenario_maker.load_scenario_config,
707
+ inputs=scenario_config,
708
+ outputs=None)
709
+
710
+ scenario_btn.click(scenario_maker.set_scenario_template,
711
+ inputs=scenario_template,
712
+ outputs=None)
713
+
714
+
715
+ msg_btn.click(scenario_maker.handle_user_input, [msg, chatbot], [msg, chatbot], queue=False).then(
716
+ scenario_maker.request_streaming_response, chatbot, chatbot
717
+ ).then(scenario_maker.show_and_tell, inputs=[chatbot,gen_img,gen_audio], outputs=[audio,img,img_prompt])
718
+
719
+ app.queue().launch(debug=True)
720
  app.queue().launch()