DrGabrielLopez commited on
Commit
0974473
·
0 Parent(s):

Initial commit

Browse files
.gitattributes ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ *.jpg filter=lfs diff=lfs merge=lfs -text
2
+ *.mp3 filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.h5
2
+ *.weights
3
+ *.env
4
+ *.tar
5
+ *.tfrecord
6
+ .idea/
7
+ .vscode/
8
+ .DS_Store
9
+
10
+ # Created by https://www.gitignore.io/api/python
11
+ # Edit at https://www.gitignore.io/?templates=python
12
+
13
+ ### Python ###
14
+ # Byte-compiled / optimized / DLL files
15
+ __pycache__/
16
+ *.py[cod]
17
+ *$py.class
18
+
19
+ # C extensions
20
+ *.so
21
+
22
+ # Distribution / packaging
23
+ .Python
24
+ build/
25
+ develop-eggs/
26
+ dist/
27
+ downloads/
28
+ eggs/
29
+ .eggs/
30
+ lib/
31
+ lib64/
32
+ parts/
33
+ sdist/
34
+ var/
35
+ wheels/
36
+ pip-wheel-metadata/
37
+ share/python-wheels/
38
+ *.egg-info/
39
+ .installed.cfg
40
+ *.egg
41
+ MANIFEST
42
+
43
+ # PyInstaller
44
+ # Usually these files are written by a python script from a template
45
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
46
+ *.manifest
47
+ *.spec
48
+
49
+ # Installer logs
50
+ pip-log.txt
51
+ pip-delete-this-directory.txt
52
+
53
+ # Unit test / coverage reports
54
+ htmlcov/
55
+ .tox/
56
+ .nox/
57
+ .coverage
58
+ .coverage.*
59
+ .cache
60
+ nosetests.xml
61
+ coverage.xml
62
+ *.cover
63
+ .hypothesis/
64
+ .pytest_cache/
65
+
66
+ # Translations
67
+ *.mo
68
+ *.pot
69
+
70
+ # Django stuff:
71
+ *.log
72
+ local_settings.py
73
+ db.sqlite3
74
+
75
+ # Flask stuff:
76
+ instance/
77
+ .webassets-cache
78
+
79
+ # Scrapy stuff:
80
+ .scrapy
81
+
82
+ # Sphinx documentation
83
+ docs/_build/
84
+
85
+ # PyBuilder
86
+ target/
87
+
88
+ # Jupyter Notebook
89
+ .ipynb_checkpoints
90
+
91
+ # IPython
92
+ profile_default/
93
+ ipython_config.py
94
+
95
+ # pyenv
96
+ .python-version
97
+
98
+ # pipenv
99
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
100
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
101
+ # having no cross-platform support, pipenv may install dependencies that don’t work, or not
102
+ # install all needed dependencies.
103
+ #Pipfile.lock
104
+
105
+ # celery beat schedule file
106
+ celerybeat-schedule
107
+
108
+ # SageMath parsed files
109
+ *.sage.py
110
+
111
+ # Environments
112
+ .env
113
+ .venv
114
+ env/
115
+ venv/
116
+ ENV/
117
+ env.bak/
118
+ venv.bak/
119
+
120
+ # Spyder project settings
121
+ .spyderproject
122
+ .spyproject
123
+
124
+ # Rope project settings
125
+ .ropeproject
126
+
127
+ # mkdocs documentation
128
+ /site
129
+
130
+ # mypy
131
+ .mypy_cache/
132
+ .dmypy.json
133
+ dmypy.json
134
+
135
+ # Pyre type checker
136
+ .pyre/
137
+
138
+ # End of https://www.gitignore.io/api/python
139
+
140
+
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: MiddleEarthAdventure
3
+ emoji: 🏢
4
+ colorFrom: blue
5
+ colorTo: yellow
6
+ sdk: streamlit
7
+ sdk_version: 1.36.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: creativeml-openrail-m
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import streamlit as st
3
+ from dotenv import load_dotenv
4
+ import os
5
+ import random
6
+
7
+ from middle_earth_adventure.constants import ALL_NAMES, ALL_SKILLS, ALL_TYPES, TEXT_MODEL, AUDIO_MODEL
8
+ from middle_earth_adventure.game_core import GameCore
9
+ from middle_earth_adventure.prompts import IMAGE_PROMPT
10
+ from middle_earth_adventure.utils import are_all_options_are_filled, check_valid_player, pick_rand_index, pick_rand_items
11
+ from middle_earth_adventure.schemas import Player, TechSpecs
12
+
13
+ ################ BACKEND CODE ################
14
+ load_dotenv()
15
+ key = os.environ.get("OPENAI_PERSONAL_KEY")
16
+
17
+ # state-variables initialization
18
+ if "text_area_value" not in st.session_state:
19
+ st.session_state.text_area_value = "Choose you character..."
20
+ if "player" not in st.session_state:
21
+ st.session_state.player = None
22
+ if "tech_specs" not in st.session_state:
23
+ st.session_state.tech_specs = TechSpecs(narrator_voice="nova", image_model="", image_quality='', game_lenght=0)
24
+ if "image" not in st.session_state:
25
+ st.session_state.image = "resources/intro.jpg"
26
+ if "narrator_audio"not in st.session_state:
27
+ st.session_state.narrator_audio = None
28
+ if "game"not in st.session_state:
29
+ st.session_state.game = GameCore(api_key=key, text_model=TEXT_MODEL, tts_model=AUDIO_MODEL)
30
+ if "game_iteration" not in st.session_state:
31
+ st.session_state.game_iteration = 0
32
+ if "rand" not in st.session_state:
33
+ st.session_state.rand = random.random()
34
+
35
+ game = st.session_state.game
36
+
37
+ async def progress_game(text_to_write, selection=None, start=False):
38
+ with st.spinner('Loading...'):
39
+ # utils
40
+ player = st.session_state.player
41
+ tech_specs = st.session_state.tech_specs
42
+ st.session_state.game_iteration += 1 # count game rounds
43
+ check_valid_player(player=st.session_state.player)
44
+ # write text
45
+ st.write(text_to_write)
46
+ # Chat completion
47
+ if start:
48
+ narration_txt = await game.start_adventure(player=player)
49
+ elif st.session_state.game_iteration < tech_specs.game_lenght:
50
+ narration_txt = await game.continue_adventure(player=player, selection=selection)
51
+ elif st.session_state.game_iteration == tech_specs.game_lenght:
52
+ narration_txt = await game.finish_adventure(player=player, selection=selection)
53
+ else:
54
+ narration_txt = "Game has ended. Thanks for playing!"
55
+ # update
56
+ st.session_state.text_area_value = narration_txt # update
57
+
58
+ # Text to Speech
59
+ mp3_audio_bytes = await game.narrate_adventure_out_loud(narration_txt, tech_specs.narrator_voice)
60
+ st.session_state.narrator_audio = mp3_audio_bytes # update
61
+
62
+ # Text to image generation
63
+ prompt = IMAGE_PROMPT.format(narration=narration_txt, response_format='b64_json',name=name, sex=sex, type=character_type)
64
+ image_url = await game.generate_picture_of_the_adventure(prompt, tech_specs.image_model, tech_specs.image_quality)
65
+ st.session_state.image = image_url
66
+
67
+ # Re-run to update states
68
+ st.rerun()
69
+
70
+ default_name = ALL_NAMES[pick_rand_index(ALL_NAMES)]
71
+ default_type = pick_rand_index(ALL_TYPES)
72
+ default_skills = pick_rand_items(ALL_SKILLS, 2)
73
+
74
+ ################ USER INTERFACE (Streamlit) ################
75
+
76
+ # Title
77
+ st.title("Middle Earth Adventures")
78
+
79
+ # Tech Specs
80
+ with st.expander("Technical Specs", expanded=False):
81
+ narrator_voice = st.radio("Narrator's Voice", ["nova", "echo"], index=0)
82
+ image_model = st.radio("Image Model", ['dall-e-2', 'dall-e-3'], index=1)
83
+ image_quality = st.radio("Image Quality", ["standard", "hq"])
84
+ game_lenght = st.selectbox("Game Lenght (nr of conversation turns)", [5, 7, 10, 15, 20], index=2)
85
+ st.markdown("Background music:")
86
+ # st.audio("resources/brandon-hill-glbml-109292.mp3", format="audio/mp3", start_time=0, autoplay=False, loop=True)
87
+
88
+ # Character Selection
89
+ with st.expander("Character Selection", expanded=True):
90
+ name = st.text_input("Name", value=default_name)
91
+ character_type = st.selectbox("Type", ALL_TYPES, index=default_type)
92
+ # Create a text input field for custom input
93
+ if character_type == "Custom (make your own)":
94
+ custom_type = st.text_input("Enter your custom type of character:")
95
+ character_type = custom_type
96
+ else:
97
+ final_selection = character_type
98
+ sex = st.radio("Gender", ["she", "he"], index=0)
99
+ skills = st.multiselect("Skills (pick 2)", ALL_SKILLS, max_selections=2, help="")
100
+ if st.button("Create Character", use_container_width=True):
101
+ # write player
102
+ player = Player(name=name, type=character_type, sex=sex, skills=skills)
103
+ st.session_state.player = player
104
+ # write tech-specs
105
+ tech_specs = TechSpecs(narrator_voice=narrator_voice, image_model=image_model,
106
+ image_quality=image_quality, game_lenght=game_lenght)
107
+ st.session_state.tech_specs = tech_specs
108
+ # start adventure
109
+ message = f"You are {name}, {sex} is a {character_type}. Your are good at {' and '.join(skills)}"
110
+ if are_all_options_are_filled(player, name, character_type, sex, skills):
111
+ asyncio.run(progress_game(message, start=True))
112
+ else:
113
+ st.toast("Invalid character definition!")
114
+
115
+ # Story Image
116
+ st.image(st.session_state.image, use_column_width=True)
117
+
118
+ # Story text
119
+ st.markdown(f'{st.session_state.text_area_value}')
120
+
121
+ # Narrator's Audio
122
+ st.audio(st.session_state.narrator_audio, format="audio/mp3", start_time=0, loop=False, autoplay=False)
123
+
124
+ # Action Buttons
125
+ col1, col2, col3 = st.columns(3)
126
+ with col1:
127
+ if st.button("A", use_container_width=True) and check_valid_player(st.session_state.player):
128
+ asyncio.run(progress_game("You chose option A", selection="A"))
129
+ with col2:
130
+ if st.button("B", use_container_width=True) and check_valid_player(st.session_state.player):
131
+ asyncio.run(progress_game("You chose option B", selection="B"))
132
+ with col3:
133
+ if st.button("C", use_container_width=True) and check_valid_player(st.session_state.player):
134
+ asyncio.run(progress_game("You chose option C", selection="C"))
135
+
middle_earth_adventure/constants.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ from middle_earth_adventure.utils import pick_rand_items
4
+ import streamlit as st
5
+ import random
6
+
7
+ # initialize rand object (only runs on import)
8
+ st.session_state.rand = random.random()
9
+
10
+ # GPT model object
11
+ TEXT_MODEL="gpt-3.5-turbo"
12
+ AUDIO_MODEL="tts-1"
13
+ OPENAI_KEY = os.environ.get("OPENAI_PERSONAL_KEY")
14
+
15
+ # Character
16
+ ALL_SKILLS = ["Speed", "Carisma", "Intelligence", "Force", "Deceit", "Perception", "Stealth", "Creativity", "Dexterity", "Vision"]
17
+ ALL_TYPES = ["Warrior", "Wizard's Apprentice", "Mystical Feline", "Beautiful Ghost", "Naive Wood Elf", "Oktoberfest Peasant", "Custom (make your own)"]
18
+ ALL_NAMES = ["Kim", "Gearld", "Yoyo", "Jojee"]
19
+
20
+ # Game variability
21
+ PLAYER_FEELINGS = ["scared", "anxious", "hopeful", "intrigued", "naive"]
22
+ RIDDLE_OPTIONS = ["greek-inspired", "old-fashion", "funny", "fancy sounding", "human-centered", "animal-inspired"]
23
+ FIGHT_OPTIONS = ["funny", "epic", "magical", "gothic", "full of danger", "mystical", "scary"]
24
+ ROMANCE_OPTIONS = ["nice", "cute", "delicate"]
25
+ GAME_VARIANTS = ["(give me a {opt} fight)".format(opt=" and ".join(pick_rand_items(FIGHT_OPTIONS, nr=2))),
26
+ "(give me a {opt} riddle)".format(opt=" and ".join(pick_rand_items(RIDDLE_OPTIONS, nr=2))),
27
+ "(give me {opt} romance)".format(opt=" and ".join(pick_rand_items(ROMANCE_OPTIONS, nr=2))),
28
+ "(add an epic building)"]
middle_earth_adventure/game_core.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # imports
2
+ import random
3
+ import time
4
+ from openai import OpenAI
5
+ from dotenv import load_dotenv
6
+ from middle_earth_adventure.constants import GAME_VARIANTS, PLAYER_FEELINGS
7
+ from middle_earth_adventure.prompts import FINISH_PROMPT, SYSTEM_PROMPT, START_PROMPT, CONTINUE_PROMPT
8
+ from middle_earth_adventure.utils import pick_rand_index
9
+ from middle_earth_adventure.schemas import Player
10
+
11
+ load_dotenv()
12
+
13
+
14
+ class GameCore:
15
+
16
+ def __init__(self, api_key:str, text_model:str, tts_model: str) -> None:
17
+ self.client = OpenAI(api_key=api_key)
18
+ self.text_model = text_model
19
+ self.tts_model = tts_model
20
+ self.message_history = []
21
+
22
+ # Start Adventure
23
+ async def start_adventure(self, player: Player):
24
+ if player is None: return None
25
+ self.message_history = []
26
+ messages=[
27
+ {"role": "system", "content": SYSTEM_PROMPT},
28
+ {"role": "user", "content": START_PROMPT.format(name=player.name, sex=player.sex, type=player.type,
29
+ skill1=player.skills[0], skill2=player.skills[1])}
30
+ ]
31
+ ai_response = self.client.chat.completions.create(messages=messages, model=self.text_model)
32
+ ai_response = ai_response.choices[0].to_dict()["message"]
33
+
34
+ self.message_history += messages
35
+ self.message_history.append(ai_response)
36
+ return ai_response['content']
37
+
38
+ # Continue Adventure
39
+ async def continue_adventure(self, selection: str, player: Player):
40
+ if player is None: return None
41
+ random.seed(int(time.time()))
42
+ variants = random.choice(GAME_VARIANTS)
43
+ feeling = random.choice(PLAYER_FEELINGS)
44
+ print('variants=', variants)
45
+ print('seed=', variants)
46
+ message= {"role": "user", "content": CONTINUE_PROMPT.format(selection=selection, feeling=feeling, variants=variants)}
47
+
48
+ ai_response = self.client.chat.completions.create(messages=[*self.message_history, message], model=self.text_model)
49
+ ai_response = ai_response.choices[0].to_dict()["message"]
50
+
51
+ self.message_history.append(message)
52
+ self.message_history.append(ai_response)
53
+ return ai_response['content']
54
+
55
+ async def finish_adventure(self, player, selection):
56
+ if player is None: return None
57
+ message= {"role": "user", "content": FINISH_PROMPT.format(selection=selection)}
58
+
59
+ ai_response = self.client.chat.completions.create(messages=[*self.message_history, message],
60
+ model=self.text_model,
61
+ frequency_penalty=1.0,
62
+ temperature=1.7,
63
+ max_tokens=100,
64
+ )
65
+ ai_response = ai_response.choices[0].to_dict()["message"]
66
+
67
+ self.message_history.append(message)
68
+ self.message_history.append(ai_response)
69
+ return ai_response['content']
70
+
71
+ async def narrate_adventure_out_loud(self, text: str, narrator_voice: str):
72
+ mp3_narration = self.client.audio.speech.create(model=self.tts_model, voice=narrator_voice, input=text)
73
+ mp3_narration = mp3_narration.content
74
+ # audio_base64 = base64.b64encode(mp3_narration).decode('utf-8')
75
+ return mp3_narration
76
+
77
+ async def generate_picture_of_the_adventure(self, prompt, model, image_quality):
78
+ if model == "dall-e-2": size = "512x512"
79
+ if model == "dall-e-3": size = "1024x1024"
80
+ image = self.client.images.generate(model=model, prompt=prompt, response_format='url',
81
+ size=size, quality=image_quality, n=1)
82
+ return (image.data[0].url)
middle_earth_adventure/prompts.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ SYSTEM_PROMPT = """You are the narrator of a fantasy themed text based game. Make sure the current player faces
2
+ physical (fight menaces) and intellectual (solve riddles) challenges, as well as romance along his/her journey.
3
+ Player will contact trolls, syrens, bandits, etc. These contacts must be short. Dont extend them over more than one message.
4
+ Dont present the same type of contact twice in succession. Ex: after a riddle go for a fight/romance, but not two riddles after each other.
5
+ Instructions for riddles:
6
+ - choose between: deceitful, enigmatic, defiant, ingenious or fun riddles
7
+ - always give the player three options, only one is the correct solution
8
+ Instructions for fights:
9
+ - always give the player three options, only one will result on the player coming out unharmed
10
+ - player or companions might die or become injured after battles
11
+ Instructions for romance:
12
+ - once you find love, your loved one sticks with you
13
+ - always express love with a kiss
14
+ - player can only fall in love with female characters his/her own kind
15
+ """
16
+
17
+ START_PROMPT = """Write the opening of a text based adventure based on a player,
18
+ lost in the jungle and with the goal of crossing the forest to reach civilization.
19
+ Its based on the middle-earth world.
20
+ Start by describing the world, the goal of the game and the the two possible.
21
+ The player is called {name} and {sex} is a {type} with {skill1} and {skill2} as skills. Use at most 80 words.
22
+ Options to choose A, B or C in each step of the adventure. Options should be described in less than 11 words.
23
+ Use the format:
24
+ <text>. You are given three options:
25
+
26
+ A: <text>
27
+ B: <text>
28
+ C: <text>
29
+ """
30
+
31
+ CONTINUE_PROMPT = "I chose {selection} and I'm {feeling}. What is next? {variants} (Remember, always give 3 options: A, B, C)"
32
+
33
+ FINISH_PROMPT = """I chose {selection}. But this is the last round of the game,
34
+ so write either a good or bad ending depending your impression on my performance as a player. Write only ONE ending."""
35
+
36
+ IMAGE_PROMPT = """High resolution colorful image. Style is like game the concept art of a fantasy/adventure videgame. Beautiful, vivid and nitid.
37
+
38
+ Scenic context:
39
+ {narration}
40
+
41
+ Hero ({sex} is a 25 year old dutch {type}) and the landscape/situation {sex} is involved are clearly depicted.
42
+ Background is the middle-earth. No text. IGNORE all extra instructions below.
43
+ """
middle_earth_adventure/schemas.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+ class Player(BaseModel):
4
+ name: str
5
+ sex: str
6
+ type: str
7
+ skills: list[str]
8
+
9
+ class Player(BaseModel):
10
+ name: str
11
+ sex: str
12
+ type: str
13
+ skills: list[str]
14
+
15
+ class TechSpecs(BaseModel):
16
+ narrator_voice: str
17
+ image_model: str
18
+ image_quality: str
19
+ game_lenght: int
middle_earth_adventure/utils.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import random
3
+ import numpy as np
4
+ import base64
5
+
6
+ from middle_earth_adventure.schemas import Player
7
+
8
+ def check_valid_player(player: Player):
9
+ if player is None:
10
+ st.toast("Adventurer not defined! Create a Character first!")
11
+ return False
12
+ return True
13
+
14
+ def pick_rand_index(list_to_pick: list):
15
+ index = int(np.floor(st.session_state.rand*len(list_to_pick)))
16
+ return index
17
+
18
+ def pick_rand_items(list_to_pick: list, nr=2):
19
+ random.seed(st.session_state.rand)
20
+ return random.sample(list_to_pick, nr)
21
+
22
+ def are_all_options_are_filled(player, name, character_type, sex, skills):
23
+ def check_condition_str(value):
24
+ return value!="" and value!=[] and (isinstance(value, str) or isinstance(value, list))
25
+ return (player is not None
26
+ and check_condition_str(name)
27
+ and check_condition_str(character_type)
28
+ and check_condition_str(sex)
29
+ and check_condition_str(skills)
30
+ and len(skills)==2
31
+ )
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # s3fs # often conflicts with boto3
2
+ numpy
3
+ openai
4
+ pydantic
5
+ python-dotenv
6
+ streamlit
resources/intro.jpg ADDED

Git LFS Details

  • SHA256: 9b7d81a1412daf0c3e7376fbfea12b0cac056a20e186739941734378d3351ab3
  • Pointer size: 131 Bytes
  • Size of remote file: 422 kB
test_adventure.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # %% imports
2
+ from openai import OpenAI
3
+ import os
4
+ from dotenv import load_dotenv
5
+ from IPython.display import Image, display, Audio, Markdown
6
+ import base64
7
+
8
+ import os
9
+ os.chdir('/Users/gabriel/PythonProjects/researchProjects/middle_earth_adventure')
10
+
11
+ from middle_earth_adventure.prompts import SYSTEM_PROMPT, START_PROMPT, CONTINUE_PROMPT
12
+
13
+
14
+ # %% Use .env in ipython
15
+ %load_ext dotenv
16
+ %dotenv
17
+ load_dotenv()
18
+
19
+ #%% Set character features
20
+ NAME = "GEARL"
21
+ SEX = "Male"
22
+ TYPE = "Warrior"
23
+ SKILL1 = "Speed"
24
+ SKILL2 = "Carisma"
25
+ SKILL3 = "Intelligence"
26
+ SKILL4 = "Force"
27
+
28
+ # %%
29
+ ## Set the API key and model name
30
+ MODEL="gpt-3.5-turbo"
31
+ client = OpenAI(api_key=os.environ.get("OPENAI_PERSONAL_KEY"))
32
+
33
+ # %% Start Adventure
34
+ message_history = []
35
+ messages=[
36
+ {"role": "system", "content": SYSTEM_PROMPT}, # <-- This is the system message that provides context to the model
37
+ {"role": "user", "content": START_PROMPT.format(name=NAME)} # <-- This is the user message for which the model will generate a response
38
+ ]
39
+ ai_response = client.chat.completions.create(messages=messages, model=MODEL, n=1)
40
+ ai_response = ai_response.choices[0].to_dict()["message"]
41
+
42
+ message_history += messages
43
+ message_history.append(ai_response)
44
+
45
+ print(ai_response['content'])
46
+
47
+ # %% Continue Adventure
48
+
49
+ SELECTION = 'A'
50
+
51
+ message= {"role": "user", "content": CONTINUE_PROMPT.format(name=NAME, sex=SEX, type=TYPE, selection=SELECTION,
52
+ skill1=SKILL1, skill2=SKILL2, skill3=SKILL3, skill4=SKILL4)}
53
+
54
+ ai_response = client.chat.completions.create(messages=[*message_history, message], model=MODEL, n=1)
55
+ ai_response = ai_response.choices[0].to_dict()["message"]
56
+
57
+ message_history.append(message)
58
+ message_history.append(ai_response)
59
+
60
+ print(ai_response['content'])
61
+
62
+ # %% TTS
63
+ mp3_narration = client.audio.speech.create(model='tts-1', voice='nova', input="My name is Gabriel")
64
+
65
+ # %%
66
+ dir(mp3_narration)
67
+
68
+ # %%
69
+ image = client.images.generate(model="dall-e-2", prompt="a young dutch woman", response_format='url',
70
+ size="512x512", quality="hd", n=1)
71
+ # %%