ajayarora1235
commited on
Commit
•
5cfd8a9
1
Parent(s):
a2dd4a4
start repo
Browse files- .env +1 -0
- .gitignore +2 -0
- README.md +11 -1
- __pycache__/app.cpython-310.pyc +0 -0
- __pycache__/app.cpython-312.pyc +0 -0
- __pycache__/assistant.cpython-312.pyc +0 -0
- __pycache__/gpt_calls.cpython-310.pyc +0 -0
- __pycache__/gpt_calls.cpython-312.pyc +0 -0
- __pycache__/suno.cpython-310.pyc +0 -0
- __pycache__/suno.cpython-312.pyc +0 -0
- ai_tools.json +229 -0
- app.py +696 -0
- assistant.py +53 -0
- data/emotions.json +28 -0
- data/genres.json +34 -0
- data/journals/heartbroken.txt +2 -0
- data/journals/manchester_girl.txt +16 -0
- data/journals/missing_home.txt +7 -0
- data/keywords.json +7 -0
- data/topics.json +34 -0
- gpt_calls.py +209 -0
- old_code.py +67 -0
- old_journal_code.py +42 -0
- packages.txt +4 -0
- prompt_artist_convo.txt +9 -0
- prompt_lyric_snippet_extractor.txt +7 -0
- prompt_lyrics_from_convo.txt +140 -0
- prompt_lyrics_writer.txt +149 -0
- prompt_section_writer.txt +46 -0
- prompt_snippet_checker.txt +8 -0
- prompt_song_seed.txt +10 -0
- requirements.txt +12 -0
- revise_section_ex.txt +19 -0
- suno.py +161 -0
- write_full_song_ex.txt +54 -0
- write_section_ex.txt +13 -0
.env
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
OPEN_AI_KEY="sk-proj-p2YYidwgo0sTLWWz6OthT3BlbkFJGaXrkrR0aEcyUdafUJJF"
|
.gitignore
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
.env
|
2 |
+
__pycache__
|
README.md
CHANGED
@@ -1 +1,11 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: Auto SONG CHAT
|
3 |
+
emoji: 🏢
|
4 |
+
colorFrom: blue
|
5 |
+
colorTo: purple
|
6 |
+
sdk: gradio
|
7 |
+
sdk_version: 4.24.0
|
8 |
+
app_file: app.py
|
9 |
+
pinned: false
|
10 |
+
license: apache-2.0
|
11 |
+
---
|
__pycache__/app.cpython-310.pyc
ADDED
Binary file (18.1 kB). View file
|
|
__pycache__/app.cpython-312.pyc
ADDED
Binary file (32.2 kB). View file
|
|
__pycache__/assistant.cpython-312.pyc
ADDED
Binary file (3.85 kB). View file
|
|
__pycache__/gpt_calls.cpython-310.pyc
ADDED
Binary file (2.83 kB). View file
|
|
__pycache__/gpt_calls.cpython-312.pyc
ADDED
Binary file (7.69 kB). View file
|
|
__pycache__/suno.cpython-310.pyc
ADDED
Binary file (1.69 kB). View file
|
|
__pycache__/suno.cpython-312.pyc
ADDED
Binary file (4.74 kB). View file
|
|
ai_tools.json
ADDED
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"type": "function",
|
4 |
+
"function": {
|
5 |
+
"name": "write_section",
|
6 |
+
"description": "Write a section of a song based on given ideas. Anytime you would like to suggest lyrics for a new section or the user has provided enough ideas for a new section, you must call this function.",
|
7 |
+
"parameters": {
|
8 |
+
"type": "object",
|
9 |
+
"properties": {
|
10 |
+
"section_name": {
|
11 |
+
"type": "string",
|
12 |
+
"description": "Name of new section being written."
|
13 |
+
},
|
14 |
+
"section_description": {
|
15 |
+
"type": "string",
|
16 |
+
"description": "Description of section as stated in first message of the conversation"
|
17 |
+
},
|
18 |
+
"relevant_ideas": {
|
19 |
+
"type": "array",
|
20 |
+
"items": {
|
21 |
+
"type": "string"
|
22 |
+
},
|
23 |
+
"description": "Ideas that should be included in the section that is being written. Obtained by paraphrasing the key details from the user's responses about their story into short sentences that each start with 'I ...', 'I ...', etc."
|
24 |
+
},
|
25 |
+
"section_length": {
|
26 |
+
"type": "number",
|
27 |
+
"description": "Number of lines in the section. This is also the number of bars, retrieved from first message of the conversation."
|
28 |
+
},
|
29 |
+
"snippet_instrumental_tags": {
|
30 |
+
"type": "string",
|
31 |
+
"description": "Instrumental tags to be used for this section. Deduce from most recent list of suggested instrumental tags in conversation. Should be comma separated string of one-word tags that describe genre as stated in intro message, instruments, moods. Specify gender."
|
32 |
+
},
|
33 |
+
"snippet_clip_to_continue_from": {
|
34 |
+
"type": "string",
|
35 |
+
"description": "The last approved clip of the song to continue the requested section from. Deduce from most recent approved clip of prior section in conversation. If user did not receive a snippet for the prior section or ever before, this should not be passed."
|
36 |
+
},
|
37 |
+
"sections_written": {
|
38 |
+
"type": "array",
|
39 |
+
"items": {
|
40 |
+
"type": "string"
|
41 |
+
},
|
42 |
+
"description": "Sections that have been written so far. This is to ensure that the song is coherent and that the sections flow well together. Include section headers (ie [verse 1]) in the lyrics."
|
43 |
+
},
|
44 |
+
"overall_song_description": {
|
45 |
+
"type": "string",
|
46 |
+
"description": "Description of the overall song. As stated in first message of conversation."
|
47 |
+
}
|
48 |
+
},
|
49 |
+
"required": ["section_name", "section_description", "relevant_ideas", "section_length", "snippet_instrumental_tags"]
|
50 |
+
}
|
51 |
+
}
|
52 |
+
},
|
53 |
+
{
|
54 |
+
"type": "function",
|
55 |
+
"function": {
|
56 |
+
"name": "revise_section_lyrics",
|
57 |
+
"description": "Revise a consecutive set of lines from a section of a song based on given ideas",
|
58 |
+
"parameters": {
|
59 |
+
"type": "object",
|
60 |
+
"properties": {
|
61 |
+
"section_name": {
|
62 |
+
"type": "string",
|
63 |
+
"description": "Name of section we are revising"
|
64 |
+
},
|
65 |
+
"current_section": {
|
66 |
+
"type": "string",
|
67 |
+
"description": "Current version of lyrics in section of the song. The last outputted version of the section before user suggested changes that we are now implementing."
|
68 |
+
},
|
69 |
+
"lines_to_revise": {
|
70 |
+
"type": "array",
|
71 |
+
"items": {
|
72 |
+
"type": "number"
|
73 |
+
},
|
74 |
+
"description": "Lines to revise, as a list of numbers. The first line is labelled 1, second 2, and so on. Lines to change should be assessed based on feedback user provides and where they suggest changes."
|
75 |
+
},
|
76 |
+
"snippet_instrumental_tags": {
|
77 |
+
"type": "string",
|
78 |
+
"description": "Instrumental tags to be used for this section revision. This should be the exact same as what was used for the snippet being revised. The instrumental tags are listed under the recent audio clip html."
|
79 |
+
},
|
80 |
+
"snippet_clip_to_continue_from": {
|
81 |
+
"type": "string",
|
82 |
+
"description": "The 'continued from clip:' clip id that was used in the original snippet we are now revising. This should be the exact same as 'continued from clip' for the snippet being revised, listed under the original snippet's audioplayer; if it is None, this should not be passed."
|
83 |
+
},
|
84 |
+
"relevant_ideas": {
|
85 |
+
"type": "array",
|
86 |
+
"items": {
|
87 |
+
"type": "string"
|
88 |
+
},
|
89 |
+
"description": "Ideas that should be included in the lines that are being changed. Should be directly derived from suggested user changes."
|
90 |
+
},
|
91 |
+
"relevant_words": {
|
92 |
+
"type": "array",
|
93 |
+
"items": {
|
94 |
+
"type": "string"
|
95 |
+
},
|
96 |
+
"description": "Words that are requested to be included in revised lines. Unless specific words are requested, this should be empty"
|
97 |
+
}
|
98 |
+
},
|
99 |
+
"required": ["section_name", "current_section", "lines_to_revise", "snippet_instrumental_tags"]
|
100 |
+
}
|
101 |
+
}
|
102 |
+
},
|
103 |
+
{
|
104 |
+
"type": "function",
|
105 |
+
"function": {
|
106 |
+
"name": "revise_instrumental_tags",
|
107 |
+
"description": "Revise instrumental tags passed to instrumental generator based on user feedback. Only call when user explicitly comments on instrumental. This will re-generate all the lyrics with this new instrumental. Confirm with the user that this is okay before running.",
|
108 |
+
"parameters": {
|
109 |
+
"type": "object",
|
110 |
+
"properties": {
|
111 |
+
"current_instrumental_tags": {
|
112 |
+
"type": "array",
|
113 |
+
"items": {
|
114 |
+
"type": "string"
|
115 |
+
},
|
116 |
+
"description": "Current instrumental tags passed to instrumental generator. Deduce from most recent list of instrumental tags in conversation."
|
117 |
+
},
|
118 |
+
"user_instrumental_feedback": {
|
119 |
+
"type": "string",
|
120 |
+
"description": "A single sentence summary of the user's feedback on instrumental. Can include suggested moods, genres, or instruments."
|
121 |
+
},
|
122 |
+
"sections_written": {
|
123 |
+
"type": "array",
|
124 |
+
"items": {
|
125 |
+
"type": "string"
|
126 |
+
},
|
127 |
+
"description": "All the sections that have been written so far for us to regenerate with the new instrumental. Include the lyrics from the current section that we are revising. Include section headers (ie [verse 1]) in the lyrics."
|
128 |
+
}
|
129 |
+
},
|
130 |
+
"required": ["current_instrumental_tags", "user_instrumental_feedback", "sections_written"]
|
131 |
+
}
|
132 |
+
}
|
133 |
+
},
|
134 |
+
{
|
135 |
+
"type": "function",
|
136 |
+
"function": {
|
137 |
+
"name": "get_audio_snippet",
|
138 |
+
"description": "Call this function when the user explicitly asks 'Can I have an audio snippet'. Return a clip of all the parts of the song we've written that they have not heard.",
|
139 |
+
"parameters": {
|
140 |
+
"type": "object",
|
141 |
+
"properties": {
|
142 |
+
"snippet_lyrics": {
|
143 |
+
"type": "string",
|
144 |
+
"description": "The lyrics of the section that the user wants to hear. If there are lyrics that the user approved but did not hear a snippet of, those must be included in this snippet as well before the current section. Include section headers (ie [verse 1]) in the lyrics."
|
145 |
+
},
|
146 |
+
"snippet_instrumental_tags": {
|
147 |
+
"type": "string",
|
148 |
+
"description": "Instrumental tags to be used to generate the snippet. Deduce from most recent list of suggested instrumental tags in conversation. Should be comma separated string of one-word tags. Specify gender."
|
149 |
+
},
|
150 |
+
"snippet_clip_to_continue_from": {
|
151 |
+
"type": "string",
|
152 |
+
"description": "The last approved song clip to continue from. Almost always the most recent clip id outputted in the conversation. If user did not receive a snippet for the prior section or ever before, this should not be passed."
|
153 |
+
}
|
154 |
+
},
|
155 |
+
"required": ["snippet_lyrics", "snippet_instrumental_tags"]
|
156 |
+
}
|
157 |
+
}
|
158 |
+
},
|
159 |
+
{
|
160 |
+
"type": "function",
|
161 |
+
"function": {
|
162 |
+
"name": "merge_all_snippets",
|
163 |
+
"description": "Merge all existing snippets of the song together. Should only be called when explicitly requested by the user.",
|
164 |
+
"parameters": {
|
165 |
+
"type": "object",
|
166 |
+
"properties": {
|
167 |
+
"last_snippet_id": {
|
168 |
+
"type": "string",
|
169 |
+
"description": "The ID of the last approved/generated snippet of the song. The path of snippets to merge is contained in this snippet, so only pass the id of the last one generated."
|
170 |
+
}
|
171 |
+
},
|
172 |
+
"required": ["last_snippet_id"]
|
173 |
+
}
|
174 |
+
}
|
175 |
+
},
|
176 |
+
{
|
177 |
+
"type": "function",
|
178 |
+
"function": {
|
179 |
+
"name": "finish_full_song",
|
180 |
+
"description": "Write the full song based on the snippets that have been generated. Should only be called when explicitly requested by the user.",
|
181 |
+
"parameters": {
|
182 |
+
"type": "object",
|
183 |
+
"properties": {
|
184 |
+
"sections_to_be_written": {
|
185 |
+
"type": "array",
|
186 |
+
"items": {
|
187 |
+
"type": "object",
|
188 |
+
"properties": {
|
189 |
+
"section_name": {
|
190 |
+
"type": "string",
|
191 |
+
"description": "Name of the section that have yet to be written or suggested. Exactly quoted as stated in first message of the conversation"
|
192 |
+
},
|
193 |
+
"section_description": {
|
194 |
+
"type": "string",
|
195 |
+
"description": "The description of the section that have yet to be written or suggested. Exactly quoted as stated in first message of the conversation"
|
196 |
+
},
|
197 |
+
"section_length": {
|
198 |
+
"type": "number",
|
199 |
+
"description": "Number of lines in the section. This is also the number of bars, retrieved from first message of the conversation."
|
200 |
+
}
|
201 |
+
}
|
202 |
+
},
|
203 |
+
"description": "The sections that have yet to be written or suggested. Should be in chronological order of the sections as positioned in the song, retrieved from the first message of the conversation."
|
204 |
+
},
|
205 |
+
"snippet_instrumental_tags": {
|
206 |
+
"type": "string",
|
207 |
+
"description": "Instrumental tags to be used for the remaining sections. Deduce from most recent list of suggested instrumental tags in conversation. Should be comma separated string of one-word tags. Specify gender."
|
208 |
+
},
|
209 |
+
"snippet_clip_to_continue_from": {
|
210 |
+
"type": "string",
|
211 |
+
"description": "The last approved clip ID of the song to continue the remaining sections from. Almost always the most recent clip id outputted in the conversation. If user did not receive a snippet for the prior section or ever before, this should not be passed."
|
212 |
+
},
|
213 |
+
"sections_written": {
|
214 |
+
"type": "array",
|
215 |
+
"items": {
|
216 |
+
"type": "string"
|
217 |
+
},
|
218 |
+
"description": "Sections that have been written so far. This is to ensure that the song is coherent and that the sections flow well together. Include section headers (ie [verse 1]) in the lyrics. If no sections have been suggested yet, this should be an empty list."
|
219 |
+
},
|
220 |
+
"overall_song_description": {
|
221 |
+
"type": "string",
|
222 |
+
"description": "Description of the overall song. As stated in first message of conversation."
|
223 |
+
}
|
224 |
+
},
|
225 |
+
"required": ["sections_to_be_written", "snippet_instrumental_tags", "snippet_clip_to_continue", "sections_written", "overall_song_description"]
|
226 |
+
}
|
227 |
+
}
|
228 |
+
}
|
229 |
+
]
|
app.py
ADDED
@@ -0,0 +1,696 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import gradio as gr
|
3 |
+
from typing import List, Optional, Tuple, Dict
|
4 |
+
import time
|
5 |
+
import datetime
|
6 |
+
|
7 |
+
def get_current_time() -> str:
|
8 |
+
"""
|
9 |
+
Returns the current time as a formatted string.
|
10 |
+
"""
|
11 |
+
now = datetime.datetime.now()
|
12 |
+
return now.strftime("%Y-%m-%d %H:%M:%S")
|
13 |
+
|
14 |
+
|
15 |
+
from gpt_calls import AI_Songwriter
|
16 |
+
|
17 |
+
from openai import OpenAI
|
18 |
+
oai_client = OpenAI(
|
19 |
+
api_key=os.getenv("OPEN_AI_KEY"),
|
20 |
+
)
|
21 |
+
client_key = os.getenv("OPEN_AI_KEY")
|
22 |
+
client = OpenAI(
|
23 |
+
api_key=os.getenv("OPEN_AI_KEY"),
|
24 |
+
)
|
25 |
+
|
26 |
+
import time
|
27 |
+
import os
|
28 |
+
import json
|
29 |
+
import random
|
30 |
+
|
31 |
+
from suno import generate_song, concat_snippets
|
32 |
+
|
33 |
+
|
34 |
+
History = List[Tuple[str, str]] # pairs of (query, response), where query is user input and response is system output
|
35 |
+
Messages = List[Dict[str, str]] # list of messages with role and content
|
36 |
+
|
37 |
+
'''
|
38 |
+
Genre list
|
39 |
+
Preset dropdown: Missing Home, Heartbroken, Getting Turnt, Childhood Nostalgia, (Custom) How are you?
|
40 |
+
- tags based on preset
|
41 |
+
Artist identity dropdown: A 15-year old boy who dreams of being a broadway actor, A 23-year old soft but bombastic woman who loves to rap, dance, and take over the streets, A 30-year old man who has plans to take over the world as a villain
|
42 |
+
|
43 |
+
male tenor, dramatic, emotional, strings
|
44 |
+
|
45 |
+
pass artist identity in starting prompt to gpt-4 conversation.
|
46 |
+
pass preset dropdown to gpt-4 conversation to inspire the questions that Lupe asks the user.
|
47 |
+
|
48 |
+
-Ask every 4 back-and-forths do you want to talk more? Or are you ready for your song? (add button for song in assistant's message)
|
49 |
+
|
50 |
+
-Mention lyrics
|
51 |
+
-Mention every 4 back-and-forths lyrics that you’ll include in the song [calling gpt-4 to generate the lyrics and identify one line that's most relevant to the last message]
|
52 |
+
'''
|
53 |
+
|
54 |
+
|
55 |
+
def clear_session() -> History:
|
56 |
+
return '', []
|
57 |
+
|
58 |
+
def remove_quotes(s):
|
59 |
+
if s[0] == '"' and s[-1] == '"' or s[0] == "'" and s[-1] == "'":
|
60 |
+
return s[1:-1]
|
61 |
+
return s
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
def generate_song_seed(baseline_seed):
|
66 |
+
song_details_prompt = "Analyze this description of how someone is feeling and provide a suggestion of a interesting song concept to base a song off of. Here are three examples, now provide a song concept for this fourth:\n\n"
|
67 |
+
|
68 |
+
song_seed_prompt ='prompt_song_seed.txt'
|
69 |
+
with open(song_seed_prompt, 'r', encoding='utf-8') as file:
|
70 |
+
content_2 = file.read()
|
71 |
+
|
72 |
+
song_details_prompt += "\n\n" + content_2 + baseline_seed + "\nSuggested Song Concept: "
|
73 |
+
|
74 |
+
convo = [
|
75 |
+
{
|
76 |
+
"role": "user",
|
77 |
+
"content": song_details_prompt,
|
78 |
+
},
|
79 |
+
]
|
80 |
+
|
81 |
+
gen = oai_client.chat.completions.create(
|
82 |
+
model="gpt-4o",
|
83 |
+
messages=convo,
|
84 |
+
stream=True
|
85 |
+
)
|
86 |
+
|
87 |
+
current_response = ""
|
88 |
+
for chunk in gen:
|
89 |
+
if chunk.choices[0].delta.content is not None:
|
90 |
+
# print ("chunk", chunk.choices[0].delta.content)
|
91 |
+
current_response += chunk.choices[0].delta.content
|
92 |
+
yield current_response
|
93 |
+
|
94 |
+
def clean_song_seed(song_seed):
|
95 |
+
if "Suggested Song Concept:" in song_seed:
|
96 |
+
song_seed = song_seed.split("Suggested Song Concept:")[1].strip()
|
97 |
+
return song_seed
|
98 |
+
|
99 |
+
def make_song(snippet_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from=None, continue_at=None):
|
100 |
+
os.makedirs("audio_clips", exist_ok=True)
|
101 |
+
song_name = f"SG_{int(time.time())}"
|
102 |
+
suno_song_path = f"./audio_clips/suno_{song_name}.wav"
|
103 |
+
full_tags = f"{snippet_instrumental_tags}"
|
104 |
+
print("Passing to generate_song:", full_tags, snippet_lyrics, suno_song_path)
|
105 |
+
|
106 |
+
if snippet_clip_to_continue_from is not None and snippet_clip_to_continue_from != "":
|
107 |
+
song_link = generate_song(full_tags, snippet_lyrics, suno_song_path, snippet_clip_to_continue_from, continue_at)
|
108 |
+
else:
|
109 |
+
song_link = generate_song(full_tags, snippet_lyrics, suno_song_path)
|
110 |
+
|
111 |
+
return song_link
|
112 |
+
|
113 |
+
def messages_to_history(messages: Messages) -> Tuple[str, History]:
|
114 |
+
assert messages[0]['role'] == 'system', messages[1]['role'] == 'user'
|
115 |
+
messages_for_parsing = messages[:1] + [{'role': 'user', 'content': ''}] + messages[2:]
|
116 |
+
print("OLD MESSAGES FOR PARSING", messages_for_parsing)
|
117 |
+
messages_for_parsing = [x for x in messages_for_parsing if x['role'] != 'tool' and 'tool_calls' not in x]
|
118 |
+
|
119 |
+
messages_for_parsing = [
|
120 |
+
{'role': x['role'], 'content': x['content'].split(" Use write_section")[0]} if x['role'] == 'user' else x
|
121 |
+
for x in messages_for_parsing
|
122 |
+
]
|
123 |
+
print("NEW MESSAGES FOR PARSING", messages_for_parsing)
|
124 |
+
history = []
|
125 |
+
for q, r in zip(messages_for_parsing[1::2], messages_for_parsing[2::2]):
|
126 |
+
history.append([q['content'], r['content']])
|
127 |
+
# print("made history:\n", history, "from messages\n", messages, "messages for parsing", messages_for_parsing)
|
128 |
+
return history
|
129 |
+
|
130 |
+
|
131 |
+
def model_chat(genre_input, query: Optional[str], history: Optional[History], messages: Optional [Messages], auto=False) -> Tuple[str, str, History, Messages]:
|
132 |
+
if query is None:
|
133 |
+
query = ''
|
134 |
+
|
135 |
+
if not query.endswith('?'):
|
136 |
+
query += " Use write_section when you have a large amount of story to pull from to write the next section! Alternatively ask me a follow up before moving to write."
|
137 |
+
|
138 |
+
with open('ai_tools.json') as f:
|
139 |
+
ai_tools = json.load(f)
|
140 |
+
|
141 |
+
songwriterAssistant = AI_Songwriter(client_key=client_key)
|
142 |
+
|
143 |
+
if auto:
|
144 |
+
messages = messages[:-1] + [{'role': 'user', 'content': query}] #should this be a -1? for non-auto. why does the chatbot history get messed up?
|
145 |
+
else:
|
146 |
+
messages = messages + [{'role': 'user', 'content': query}]
|
147 |
+
|
148 |
+
|
149 |
+
|
150 |
+
messages_filtered = messages
|
151 |
+
response_message = oai_client.chat.completions.create(
|
152 |
+
model="gpt-4o",
|
153 |
+
messages=messages_filtered,
|
154 |
+
tools = ai_tools,
|
155 |
+
tool_choice="auto",
|
156 |
+
)
|
157 |
+
print(response_message, "model chat response")
|
158 |
+
current_response = ""
|
159 |
+
# Step 2: determine if the response from the model includes a tool call.
|
160 |
+
tool_calls = response_message.choices[0].message.tool_calls
|
161 |
+
if tool_calls:
|
162 |
+
messages.append({
|
163 |
+
"role": response_message.choices[0].message.role,
|
164 |
+
"content": response_message.choices[0].message.content,
|
165 |
+
"tool_calls": tool_calls,
|
166 |
+
"function_call": response_message.choices[0].message.function_call
|
167 |
+
})
|
168 |
+
# If true the model will return the name of the tool / function to call and the argument(s)
|
169 |
+
for tool_call in tool_calls:
|
170 |
+
print(tool_call)
|
171 |
+
tool_call_id = tool_call.id
|
172 |
+
tool_function_name = tool_call.function.name
|
173 |
+
tool_query_args = eval(tool_call.function.arguments)
|
174 |
+
|
175 |
+
# Step 3: Call the function and retrieve results. Append the results to the messages list.
|
176 |
+
if tool_function_name == 'write_section':
|
177 |
+
snippet_instrumental_tags = tool_query_args.pop('snippet_instrumental_tags', None)
|
178 |
+
snippet_clip_to_continue_from = tool_query_args.pop('snippet_clip_to_continue_from', None)
|
179 |
+
suggested_lyrics = songwriterAssistant.write_section(**tool_query_args)
|
180 |
+
|
181 |
+
## yield suggested lyrics in tool and assistant message
|
182 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': suggested_lyrics}
|
183 |
+
# audio_message = {'role': 'assistant', 'content': "Here's what I've come up with:\n" + suggested_lyrics + "\n\nGenerating audio snippet..."}
|
184 |
+
new_messages = messages + [tool_message] #, audio_message
|
185 |
+
|
186 |
+
model_response_with_function_call = client.chat.completions.create(
|
187 |
+
model="gpt-4o",
|
188 |
+
messages=new_messages,
|
189 |
+
) # get a new response from the model where it can see the function response
|
190 |
+
current_response = model_response_with_function_call.choices[0].message.content
|
191 |
+
|
192 |
+
role = "assistant"
|
193 |
+
new_messages = new_messages + [{'role': role, 'content': current_response}]
|
194 |
+
# new_messages = [msg for msg in new_messages if msg['content'] is not None and msg['role'] in ['user', 'assistant']]
|
195 |
+
history = messages_to_history(new_messages)
|
196 |
+
yield '', history, new_messages, '[...]'
|
197 |
+
|
198 |
+
|
199 |
+
# new_history = messages_to_history(new_messages)
|
200 |
+
# yield '', new_history, new_messages, '[...]'
|
201 |
+
|
202 |
+
# ### call make_song here with the snippet_lyrics, snippet_instrumental_tags, and snippet_clip_to_continue
|
203 |
+
# song_link = make_song(suggested_lyrics, snippet_instrumental_tags, snippet_clip_to_continue)
|
204 |
+
|
205 |
+
# ## filter out suno link from tool query arg
|
206 |
+
# clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
207 |
+
|
208 |
+
# ## add song link to tool and audio message
|
209 |
+
# tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': suggested_lyrics + '\nclip id: ' + clip_id}
|
210 |
+
# audio_message = {'role': 'assistant', 'content': "Here's what I've come up with:\n" + suggested_lyrics + '\n\n' + f'<audio controls autoplay><source src="{song_link}" type="audio/mp3"></audio><p>clip id: {clip_id}</p><p>instrumental tags: {snippet_instrumental_tags}</p>'}
|
211 |
+
# audio_message['content'] += f'<p>continued from clip: {snippet_clip_to_continue}</p>'
|
212 |
+
# audio_message['content'] += f'\n\nWhat do you think?'
|
213 |
+
# new_messages = messages + [tool_message, audio_message]
|
214 |
+
# new_history = messages_to_history(new_messages)
|
215 |
+
# yield '', new_history, new_messages, '[...]'
|
216 |
+
|
217 |
+
elif tool_function_name == 'revise_section_lyrics':
|
218 |
+
snippet_instrumental_tags = tool_query_args.pop('snippet_instrumental_tags', None)
|
219 |
+
snippet_clip_to_continue_from = tool_query_args.pop('snippet_clip_to_continue_from', None)
|
220 |
+
revised_lyrics = songwriterAssistant.revise_section_lyrics(**tool_query_args)
|
221 |
+
|
222 |
+
# ## yield revised lyrics in tool and assistant message
|
223 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': revised_lyrics}
|
224 |
+
# audio_message = {'role': 'assistant', 'content': "Here's my revised lyrics:\n" + revised_lyrics + "\n\nGenerating audio snippet..."}
|
225 |
+
new_messages = messages + [tool_message] #, audio_message]
|
226 |
+
|
227 |
+
model_response_with_function_call = client.chat.completions.create(
|
228 |
+
model="gpt-4o",
|
229 |
+
messages=new_messages,
|
230 |
+
) # get a new response from the model where it can see the function response
|
231 |
+
current_response = model_response_with_function_call.choices[0].message.content
|
232 |
+
|
233 |
+
role = "assistant"
|
234 |
+
new_messages = new_messages + [{'role': role, 'content': current_response}]
|
235 |
+
# new_messages = [msg for msg in new_messages if msg['content'] is not None and msg['role'] in ['user', 'assistant']]
|
236 |
+
history = messages_to_history(new_messages)
|
237 |
+
yield '', history, new_messages, '[...]'
|
238 |
+
# new_history = messages_to_history(new_messages)
|
239 |
+
# yield '', new_history, new_messages, '[...]'
|
240 |
+
|
241 |
+
# ### call make_song here with the snippet_lyrics, snippet_instrumental_tags, and snippet_clip_to_continue
|
242 |
+
# song_link = make_song(revised_lyrics, snippet_instrumental_tags, snippet_clip_to_continue)
|
243 |
+
|
244 |
+
# ## filter out suno link from tool query arg
|
245 |
+
# clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
246 |
+
|
247 |
+
# ## add song link to tool and audio message
|
248 |
+
# tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': revised_lyrics + '\nclip id: ' + clip_id}
|
249 |
+
# audio_message = {'role': 'assistant', 'content': "Here's what I've come up with:\n" + revised_lyrics + '\n\n' + f'<audio controls autoplay><source src="{song_link}" type="audio/mp3"></audio><p>clip id: {clip_id}</p><p>instrumental tags: {snippet_instrumental_tags}</p>'}
|
250 |
+
# audio_message['content'] += f'<p>continued from clip: {snippet_clip_to_continue}</p>'
|
251 |
+
# audio_message['content'] += f'\n\nWhat do you think?'
|
252 |
+
# new_messages = messages + [tool_message, audio_message]
|
253 |
+
# new_history = messages_to_history(new_messages)
|
254 |
+
# yield '', new_history, new_messages, '[...]'
|
255 |
+
|
256 |
+
elif tool_function_name == 'revise_instrumental_tags':
|
257 |
+
#detangle tool_query_args dict
|
258 |
+
#snippet_lyrics = tool_query_args['snippet_lyrics'] + "\n[End]"
|
259 |
+
snippet_instrumental_tags = tool_query_args['current_instrumental_tags']
|
260 |
+
user_instrumental_feedback = tool_query_args['user_instrumental_feedback']
|
261 |
+
# if 'snippet_clip_to_continue_from' not in tool_query_args:
|
262 |
+
# tool_query_args['snippet_clip_to_continue_from'] = None
|
263 |
+
# snippet_clip_to_continue_from = tool_query_args['snippet_clip_to_continue_from']
|
264 |
+
|
265 |
+
new_instrumental_tags = songwriterAssistant.revise_instrumental_tags(snippet_instrumental_tags, user_instrumental_feedback)
|
266 |
+
# yield new_instrumental_tags in tool and assistant message
|
267 |
+
# tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'new instrumental tags: {new_instrumental_tags}'}
|
268 |
+
# audio_message = {'role': 'assistant', 'content': f'Sure! I\'ve revised the instrumental tags: {new_instrumental_tags}\n\n Generating audio snippet...'}
|
269 |
+
# new_messages = messages + [tool_message, audio_message]
|
270 |
+
# new_history = messages_to_history(new_messages)
|
271 |
+
# yield '', new_history, new_messages, '[...]'
|
272 |
+
|
273 |
+
if isinstance(tool_query_args['sections_written'], str):
|
274 |
+
current_lyrics = tool_query_args['sections_written']
|
275 |
+
elif isinstance(tool_query_args['sections_written'], list):
|
276 |
+
current_lyrics = "\n".join(tool_query_args['sections_written'])
|
277 |
+
else:
|
278 |
+
current_lyrics = ""
|
279 |
+
|
280 |
+
#current_lyrics = "\n".join(tool_query_args['sections_written'])
|
281 |
+
song_link = make_song(current_lyrics, new_instrumental_tags)
|
282 |
+
## filter out suno link from tool query arg
|
283 |
+
clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
284 |
+
|
285 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'new instrumental tags: {new_instrumental_tags}, clip id: {clip_id}'}
|
286 |
+
audio_message = {'role': 'assistant', 'content': f'Sure! I\'ve revised the instrumental tags: {new_instrumental_tags}\nCurrent lyrics: {current_lyrics}\n\n <audio controls autoplay><source src="{song_link}" type="audio/mp3"></audio><p>clip id: {clip_id}</p>'}
|
287 |
+
audio_message['content'] += f'\n\nWhat do you think?'
|
288 |
+
new_messages = messages + [tool_message, audio_message]
|
289 |
+
new_history = messages_to_history(new_messages)
|
290 |
+
yield '', new_history, new_messages, '[...]'
|
291 |
+
elif tool_function_name == 'merge_all_snippets':
|
292 |
+
updated_clip_url, updated_lyrics, clips_list = concat_snippets(tool_query_args['last_snippet_id'])
|
293 |
+
updated_clip_id = updated_clip_url.split("https://audiopipe.suno.ai/?item_id=")[1]
|
294 |
+
|
295 |
+
#pass this info in new tool and assistant message
|
296 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'updated clip id: {updated_clip_id}\nupdated lyrics: {updated_lyrics}\nupdated clips path: {clips_list}'}
|
297 |
+
audio_message = {'role': 'assistant', 'content': f'Sure! All the clips are now merged. <p>updated lyrics: {updated_lyrics}</p><audio controls autoplay><source src="{updated_clip_url}" type="audio/mp3"></audio><p>updated clip id: {updated_clip_id}</p><p>updated clips path: {clips_list}</p>'}
|
298 |
+
|
299 |
+
new_messages = messages + [tool_message, audio_message]
|
300 |
+
new_history = messages_to_history(new_messages)
|
301 |
+
yield '', new_history, new_messages, '[...]'
|
302 |
+
elif tool_function_name == 'finish_full_song':
|
303 |
+
## args are sections_to_be_written, relevant_ideas, last_snippet_id, sni
|
304 |
+
|
305 |
+
## STEP 0: POP out instrumental args
|
306 |
+
snippet_instrumental_tags = tool_query_args.pop('snippet_instrumental_tags', None)
|
307 |
+
snippet_clip_to_continue_from = tool_query_args.pop('snippet_clip_to_continue_from', None)
|
308 |
+
|
309 |
+
if isinstance(tool_query_args['sections_written'], str):
|
310 |
+
current_lyrics = tool_query_args['sections_written']
|
311 |
+
elif isinstance(tool_query_args['sections_written'], list):
|
312 |
+
current_lyrics = "\n".join(tool_query_args['sections_written'])
|
313 |
+
else:
|
314 |
+
current_lyrics = ""
|
315 |
+
|
316 |
+
## STEP 1: WRITE ALL LYRICS using songwriterAssistant
|
317 |
+
remaining_lyrics = songwriterAssistant.write_all_lyrics(**tool_query_args)
|
318 |
+
full_lyrics = current_lyrics + remaining_lyrics + "\n[End]"
|
319 |
+
yield '', history, messages, full_lyrics
|
320 |
+
|
321 |
+
## STEP 2: MAKE SONG FOR REMAINING LYRICS
|
322 |
+
song_link = make_song(remaining_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from)
|
323 |
+
|
324 |
+
#tool and assistant message
|
325 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'{full_lyrics}'}
|
326 |
+
audio_message = {'role': 'assistant', 'content': f'New snippet: \n <audio controls autoplay><source src="{song_link}" type="audio/mp3"></audio>'}
|
327 |
+
|
328 |
+
new_messages = messages + [tool_message, audio_message]
|
329 |
+
new_history = messages_to_history(new_messages)
|
330 |
+
yield '', new_history, new_messages, full_lyrics
|
331 |
+
|
332 |
+
## STEP 3: MERGE FULL SONG
|
333 |
+
if snippet_clip_to_continue_from not in [None, ""]:
|
334 |
+
updated_clip_url, updated_lyrics, clips_list = concat_snippets(song_link.split("https://audiopipe.suno.ai/?item_id=")[1])
|
335 |
+
else:
|
336 |
+
updated_clip_url, updated_lyrics, clips_list = song_link, remaining_lyrics, []
|
337 |
+
## YIELD UPDATED CLIP URL, LYRICS, AND CLIPS LIST
|
338 |
+
updated_clip_id = updated_clip_url.split("https://audiopipe.suno.ai/?item_id=")[1]
|
339 |
+
|
340 |
+
#tool and assistant message
|
341 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'updated clip id: {updated_clip_id}\nupdated lyrics: {updated_lyrics}\nupdated clips path: {clips_list}'}
|
342 |
+
audio_message = {'role': 'assistant', 'content': f'All done! Thank you for participating :) \nFinal Lyrics: {full_lyrics} \nFinal song: <audio controls autoplay><source src="{updated_clip_url}" type="audio/mp3"></audio><p>clip id: {updated_clip_id}</p>'}
|
343 |
+
|
344 |
+
new_messages = messages + [tool_message, audio_message]
|
345 |
+
new_history = messages_to_history(new_messages)
|
346 |
+
yield '', new_history, new_messages, '[...]'
|
347 |
+
|
348 |
+
elif tool_function_name == 'get_audio_snippet':
|
349 |
+
#detangle tool_query_args dict
|
350 |
+
snippet_lyrics = tool_query_args['snippet_lyrics'] + "\n[End]"
|
351 |
+
snippet_instrumental_tags = tool_query_args['snippet_instrumental_tags']
|
352 |
+
if 'snippet_clip_to_continue_from' not in tool_query_args:
|
353 |
+
tool_query_args['snippet_clip_to_continue_from'] = None
|
354 |
+
snippet_clip_to_continue_from = tool_query_args['snippet_clip_to_continue_from']
|
355 |
+
song_link = make_song(snippet_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from)
|
356 |
+
## filter out suno link from tool query arg
|
357 |
+
clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
358 |
+
|
359 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'instrumental tags: {tool_query_args["snippet_instrumental_tags"]}, clip id: {clip_id}'}
|
360 |
+
audio_message_content = "Here's what I've come up with:\n" + snippet_lyrics + '\n\n' + f'<audio controls autoplay><source src="{song_link}" type="audio/mp3"></audio><p>instrumental tags: {tool_query_args["snippet_instrumental_tags"]}</p><p>clip id: {clip_id}</p>'
|
361 |
+
audio_message_content += f'<p>continued from clip: {snippet_clip_to_continue_from}</p>'
|
362 |
+
audio_message = {'role': 'assistant', 'content': audio_message_content}
|
363 |
+
new_messages = messages + [tool_message, audio_message]
|
364 |
+
new_history = messages_to_history(new_messages)
|
365 |
+
yield '', new_history, new_messages
|
366 |
+
else:
|
367 |
+
print(f"Error: function {tool_function_name} does not exist")
|
368 |
+
|
369 |
+
# messages.append({
|
370 |
+
# "role":"tool",
|
371 |
+
# "tool_call_id":tool_call_id,
|
372 |
+
# "name": tool_function_name,
|
373 |
+
# "content":results
|
374 |
+
# })
|
375 |
+
|
376 |
+
# Step 4: Invoke the chat completions API with the function response appended to the messages list
|
377 |
+
# Note that messages with role 'tool' must be a response to a preceding message with 'tool_calls'
|
378 |
+
|
379 |
+
else:
|
380 |
+
# Model did not identify a function to call, result can be returned to the user
|
381 |
+
current_response = response_message.choices[0].message.content
|
382 |
+
|
383 |
+
role = "assistant"
|
384 |
+
new_messages = messages + [{'role': role, 'content': current_response}]
|
385 |
+
# new_messages = [msg for msg in new_messages if msg['content'] is not None and msg['role'] in ['user', 'assistant']]
|
386 |
+
history = messages_to_history(new_messages)
|
387 |
+
yield '', history, new_messages, '[...]'
|
388 |
+
|
389 |
+
def get_sections(overall_meaning, section_list):
|
390 |
+
section_list = section_list.split("\n")
|
391 |
+
filepath_2='prompt_section_writer.txt'
|
392 |
+
with open(filepath_2, 'r', encoding='utf-8') as file:
|
393 |
+
content_2 = file.read()
|
394 |
+
|
395 |
+
response = oai_client.chat.completions.create(
|
396 |
+
model="gpt-4o",
|
397 |
+
messages=[
|
398 |
+
{
|
399 |
+
"role": "user",
|
400 |
+
"content": content_2 + f"\n\nOverall meaning: {overall_meaning}\nSection list: {', '.join(section_list)}\nSection meanings:",
|
401 |
+
},
|
402 |
+
],
|
403 |
+
)
|
404 |
+
|
405 |
+
text_response = response.choices[0].message.content
|
406 |
+
return text_response
|
407 |
+
|
408 |
+
|
409 |
+
def get_starting_messages(song_lengths, song_title, song_blurb, song_genre, init_sections):
|
410 |
+
system_prompt = "You are an expert at writing songs. You are with an everyday person, and you will write the lyrics of the song based on this person's life has by asking questions about a story of theirs. Design your questions on your own, without using your tools, to help you understand the user's story, so you can write a song about the user's experience that resonates with them. We have equipped you with a set of tools to help you write this story; please use them. You are very good at making the user feel comfortable, understood, and ready to share their feelings and story. Occasionally (every 2 messages or so) you will suggest some lyrics, one section at a time, and see what the user thinks of them. Do not suggest or ask for thoughts on more than one section at a time. Be concise and youthful."
|
411 |
+
|
412 |
+
user_prompt = f"I have a story that could make this concept work well. The title is {song_title}, its about {song_blurb} with a genre {song_genre} and I think this should be the structure: {init_sections}\n{song_lengths}"
|
413 |
+
|
414 |
+
|
415 |
+
|
416 |
+
first_msg_res = oai_client.chat.completions.create(
|
417 |
+
model="gpt-4o",
|
418 |
+
messages=[
|
419 |
+
{"role": "system", "content": system_prompt},
|
420 |
+
{"role": "user", "content": "The user has stated the following:\n " + user_prompt + "\n Introduce yourself and kick-off the songwriting process with a question."},
|
421 |
+
],
|
422 |
+
)
|
423 |
+
|
424 |
+
# if "Section meanings:\n" in init_sections:
|
425 |
+
# init_sections = init_sections.split("Section meanings:\n")[1]
|
426 |
+
# else:
|
427 |
+
# if "[" in init_sections:
|
428 |
+
# init_sections = init_sections[init_sections.index("["):]
|
429 |
+
|
430 |
+
# first_message = init_sections + "\n\n" + first_message
|
431 |
+
|
432 |
+
first_message = first_msg_res.choices[0].message.content
|
433 |
+
|
434 |
+
starting_messages = [
|
435 |
+
{'role': 'system', 'content': system_prompt},
|
436 |
+
{'role': 'user', 'content': user_prompt},
|
437 |
+
{'role': 'assistant', 'content': first_message},
|
438 |
+
]
|
439 |
+
|
440 |
+
return starting_messages, messages_to_history(starting_messages)
|
441 |
+
|
442 |
+
# def update_messages_with_lyrics(messages, lyrics):
|
443 |
+
# text_to_append = "\n\nHere are the lyrics I came up with!\n\n" + lyrics
|
444 |
+
# if messages[-1]['role'] == 'assistant':
|
445 |
+
# messages[-1]['content'] += text_to_append
|
446 |
+
# elif messages[-1]['role'] == 'user':
|
447 |
+
# messages.append({'role': 'assistant', 'content': text_to_append})
|
448 |
+
# return messages, messages_to_history(messages)
|
449 |
+
|
450 |
+
def change_tab(id):
|
451 |
+
return gr.Tabs(selected=id)
|
452 |
+
|
453 |
+
with gr.Blocks() as demo:
|
454 |
+
gr.Markdown("""<center><font size=8>AI Songwriter (alpha)</center>""")
|
455 |
+
gr.Markdown("""<center><font size=4>Turning your stories into musical poetry. 2024 MIT Senior Thesis.</center>""")
|
456 |
+
|
457 |
+
with gr.Tabs() as tabs:
|
458 |
+
with gr.TabItem("Ideation", id=0): #index is 0
|
459 |
+
gr.Markdown("""<center><font size=6>Let's write a song!</font></center>""")
|
460 |
+
gr.Markdown("""<center><font size=4>First, let's try to find an interesting concept. Fill out the fields below and generate a song seed.</font></center>""")
|
461 |
+
gr.Markdown("""<center><font size=3>If you're stuck, check out <a href="https://onestopforwriters.com/emotions" target="_blank">here</a>.</font></center>""")
|
462 |
+
with gr.Row():
|
463 |
+
feeling_input = gr.Textbox(label='How are you feeling today? More vulnerable you are, better the song will be.', placeholder='Enter your emotions', scale=2)
|
464 |
+
songwriter_style = gr.Dropdown(label='Songwriter Style', value = "GPT 4o", choices=["GPT 4o", "d4vd (Indie Rock Ballad - Male)", "Lizzy McAlpine (Indie Pop Folk - Female)", "Phoebe Bridgers (Pop Sad Rock - Female)", "Daniel Caesar (R&B/Soul - Male)"], interactive=True)
|
465 |
+
# audio_input = gr.Audio(sources=["upload"], type="numpy", label="Instrumental",
|
466 |
+
# interactive=True, elem_id="instrumental-input")
|
467 |
+
|
468 |
+
generate_seed_button = gr.Button("STEP 1: Generate Song Seed")
|
469 |
+
concept_desc = gr.Markdown("""<center><font size=4>Here it is! Hit 'Approve' to confirm this concept. Edit the concept directly or hit 'Try Again' to get another suggestion.</font></center>""", visible=False)
|
470 |
+
with gr.Row(visible=False) as concept_row:
|
471 |
+
instrumental_output = gr.TextArea(label="Suggested Song Concept", value="", max_lines=3, scale=2)
|
472 |
+
with gr.Column():
|
473 |
+
approve_button = gr.Button("Approve")
|
474 |
+
try_again_button = gr.Button("Try Again")
|
475 |
+
with gr.Row():
|
476 |
+
with gr.Accordion("Generated Song Details", open=False) as accordion:
|
477 |
+
with gr.Row():
|
478 |
+
title_input = gr.Textbox(label='Title', placeholder='Enter a song title')
|
479 |
+
genre_input = gr.Textbox(label='Genre', placeholder='Enter a genre')
|
480 |
+
blurb_input = gr.Textbox(label='Blurb', placeholder='Enter a one-sentence blurb')
|
481 |
+
instrumental_textbox = gr.TextArea(label="Song Structure", value="Verse 1: 4 measures\nChorus 1: 8 measures\nVerse 2: 8 measures\nChorus 2: 8 measures\nVerse 3: 8 measures\nChorus 3: 8 measures", interactive=True, max_lines=3)
|
482 |
+
gr.Markdown("""<center><font size=4>Edit these to your liking and hit 'Continue to Next Step' to start creating!</font></center>""")
|
483 |
+
|
484 |
+
def open_accordion(x):
|
485 |
+
return gr.Accordion("Generated Song Details", open=True)
|
486 |
+
approve_button.click(open_accordion, inputs=[approve_button], outputs=[accordion])
|
487 |
+
|
488 |
+
with gr.Row():
|
489 |
+
continue_btn = gr.Button("Continue to Next Step", interactive=False)
|
490 |
+
|
491 |
+
generate_seed_button.click(generate_song_seed, inputs=[feeling_input], outputs=[instrumental_output]).then(clean_song_seed, inputs=[instrumental_output], outputs=[instrumental_output])
|
492 |
+
def make_row_visible(x):
|
493 |
+
return gr.Row(visible=True), gr.Markdown("""<center><font size=4>Here it is! Hit 'Approve' to confirm this concept. Edit the concept directly or hit 'Try Again' to get another suggestion.</font></center>""", visible=True)
|
494 |
+
def enable_button(x):
|
495 |
+
return gr.Button("Continue to Next Step", interactive=True)
|
496 |
+
generate_seed_button.click(make_row_visible, inputs=[generate_seed_button], outputs=[concept_row, concept_desc])
|
497 |
+
approve_button.click(enable_button, inputs=[approve_button], outputs=[continue_btn])
|
498 |
+
|
499 |
+
def update_song_details(instrumental_output):
|
500 |
+
song_details_prompt = "Analyze this assessment and suggestion of a song concept to extract the genre, one sentence blurb of what the song is about. Based on this, also suggest a song title. Output exactly three lines, in the format of 'genre: [genre]', 'title: [title]', 'blurb: [blurb]'. "
|
501 |
+
|
502 |
+
song_details_prompt += "\n\n" + instrumental_output
|
503 |
+
|
504 |
+
convo = [
|
505 |
+
{
|
506 |
+
"role": "user",
|
507 |
+
"content": song_details_prompt,
|
508 |
+
},
|
509 |
+
]
|
510 |
+
|
511 |
+
response = oai_client.chat.completions.create(
|
512 |
+
model="gpt-4o",
|
513 |
+
messages=convo
|
514 |
+
)
|
515 |
+
response_lines = response.choices[0].message.content.split('\n')
|
516 |
+
genre = next((line.split(": ")[1] for line in response_lines if "genre: " in line.lower()), None)
|
517 |
+
title = next((line.split(": ")[1] for line in response_lines if "title: " in line.lower()), None)
|
518 |
+
blurb = next((line.split(": ")[1] for line in response_lines if "blurb: " in line.lower()), None)
|
519 |
+
return genre, title, blurb
|
520 |
+
|
521 |
+
|
522 |
+
section_meanings = gr.State(value="")
|
523 |
+
|
524 |
+
try_again_button.click(generate_song_seed, inputs=[feeling_input], outputs=[instrumental_output])
|
525 |
+
continue_btn.click(change_tab, gr.Number(1, visible=False), tabs)
|
526 |
+
|
527 |
+
|
528 |
+
|
529 |
+
with gr.TabItem("Generation", id=1): #index is 1
|
530 |
+
start_song_gen = gr.State(value=False)
|
531 |
+
gr.Markdown("""<center><font size=4>Now, chat with an AI songwriter to make your song! Tip: get and tune an audio snippet well first and then put effort into the story. Hit finish when ready to hear full song.</font></center>""")
|
532 |
+
generate_lyrics = gr.Button("STEP 2: Write a song with the AIs!")
|
533 |
+
|
534 |
+
character = gr.State(value="A 18-year old boy who dreams of being a pop star that uplifts people going through the difficulties of life")
|
535 |
+
|
536 |
+
starting_messages, starting_history = get_starting_messages("", "Home", "Missing home", "Ballad", instrumental_textbox.value)
|
537 |
+
|
538 |
+
messages = gr.State(value=starting_messages)
|
539 |
+
# journal_messages = gr.State(value=[journal_starting_message])
|
540 |
+
# journal_response = gr.State(value="")
|
541 |
+
|
542 |
+
with gr.Row():
|
543 |
+
chatbot_history = gr.Chatbot(value=starting_history, label='SongChat', placeholder=None, layout='bubble', bubble_full_width=False, height=500, scale=2)
|
544 |
+
with gr.Column():
|
545 |
+
songwriter_creativity = gr.Slider(label="Songwriter LLM Temperature", minimum=0, maximum=1, step=0.01, value=1)
|
546 |
+
lyrics_display = gr.TextArea("[...]", label="Generated Lyrics", show_copy_button=True, container=True)
|
547 |
+
|
548 |
+
approve_button.click(update_song_details, inputs=[instrumental_output], outputs=[genre_input, title_input, blurb_input]).then(get_sections, inputs=[blurb_input, instrumental_output], outputs=[section_meanings])
|
549 |
+
continue_btn.click(get_starting_messages, inputs=[instrumental_textbox, title_input, blurb_input, genre_input, section_meanings], outputs=[messages, chatbot_history])
|
550 |
+
|
551 |
+
with gr.Row():
|
552 |
+
textbox = gr.Textbox(lines=1, label='Send a message', show_label=False, placeholder='Send a message', scale=4)
|
553 |
+
# melody_recorder = gr.Audio(
|
554 |
+
# sources=["microphone"],
|
555 |
+
# label="Record Melody to suggest",
|
556 |
+
# waveform_options=gr.WaveformOptions(
|
557 |
+
# waveform_color="#01C6FF",
|
558 |
+
# waveform_progress_color="#0066B4",
|
559 |
+
# skip_length=2,
|
560 |
+
# show_controls=False,
|
561 |
+
# ),
|
562 |
+
# )
|
563 |
+
# clear_history = gr.Button("🧹 Clear history", visible=False)
|
564 |
+
submit = gr.Button("Send", scale=2)
|
565 |
+
|
566 |
+
with gr.Row():
|
567 |
+
get_snippet_button = gr.Button("Get Audio Snippet", scale=2)
|
568 |
+
done = gr.Button("Finish Full Song 🎶", scale=2)
|
569 |
+
#autoGPT_checkbox = gr.Checkbox(label="AutoGPT", value=True, info="Auto-generate responses from journal entry", interactive=True, scale=2)
|
570 |
+
#journal_llm_creativity = gr.Slider(label="Journal LLM Temperature", minimum=0, maximum=1, step=0.01, value=1, interactive=True, scale=2)
|
571 |
+
reset_button = gr.Button("Reset", scale=2)
|
572 |
+
|
573 |
+
def reset_chat(messages, chatbot_history):
|
574 |
+
messages = messages[:2]
|
575 |
+
chatbot_history = messages_to_history(messages[:2])
|
576 |
+
return messages, chatbot_history, ''
|
577 |
+
|
578 |
+
reset_button.click(reset_chat, inputs=[messages, chatbot_history], outputs=[messages, chatbot_history, lyrics_display])
|
579 |
+
|
580 |
+
|
581 |
+
# generate_seed_button.click(get_starting_messages, inputs=[character, title_input, blurb_input, preset, genre_input, instrumental_textbox], outputs=[messages, chatbot_history])
|
582 |
+
|
583 |
+
# def get_conversation(story_textbox, chatbot_history, messages):
|
584 |
+
# curr_chatbot_value = chatbot_history.copy()
|
585 |
+
# curr_messages_value = messages.copy()
|
586 |
+
# for i in range(3):
|
587 |
+
# for journal_response_value, chatbot_history_value, messages_value in get_journal_response(story_textbox, curr_chatbot_value, curr_messages_value):
|
588 |
+
# curr_chatbot_value = chatbot_history_value
|
589 |
+
# curr_messages_value = messages_value
|
590 |
+
# journal_response.value = journal_response_value
|
591 |
+
# yield chatbot_history_value, messages_value
|
592 |
+
|
593 |
+
# for _, chatbot_history_value, messages_value in model_chat(journal_response_value, curr_chatbot_value, curr_messages_value, auto=True):
|
594 |
+
# # Update the gr.State objects
|
595 |
+
# curr_chatbot_value = chatbot_history_value
|
596 |
+
# curr_messages_value = messages_value
|
597 |
+
# yield chatbot_history_value, messages_value
|
598 |
+
|
599 |
+
|
600 |
+
with gr.Row():
|
601 |
+
song_link = gr.State(value="")
|
602 |
+
song = gr.HTML()
|
603 |
+
|
604 |
+
download_btn = gr.Button("Download Conversation")
|
605 |
+
|
606 |
+
def download_conversation(messages):
|
607 |
+
#get time
|
608 |
+
now = get_current_time()
|
609 |
+
# write messages to JSON file
|
610 |
+
with open(f'conversation_{now}.json', 'w') as f:
|
611 |
+
json.dump(messages, f)
|
612 |
+
|
613 |
+
|
614 |
+
# with gr.Row():
|
615 |
+
# song = gr.Audio(label='Song', format="bytes", streaming=True) # type='filepath', sources=[])
|
616 |
+
# with gr.Accordion("Show Lyrics", open=True):
|
617 |
+
# lyrics_display = gr.Markdown("[...]")
|
618 |
+
# song_tags = gr.Markdown("")
|
619 |
+
|
620 |
+
# with gr.Accordion("Advanced", open=False):
|
621 |
+
# suno_tags = gr.Textbox(value="ballad, male, dramatic, emotional, strings", label="Gen input tags")
|
622 |
+
# story_textbox = gr.TextArea(label="Story to provide context to songwriter", value="", max_lines=3)
|
623 |
+
|
624 |
+
# genre_input.blur(get_starting_messages, inputs=[character, preset, genre_input], outputs=[messages, chatbot_history])
|
625 |
+
|
626 |
+
def lyrics_from_convo(self, messages, character_preset, section_list, temperature=1.0):
|
627 |
+
conversation_text = ""
|
628 |
+
for m in messages[1:]:
|
629 |
+
name = "Lupe" if m['role'] == 'assistant' else "User"
|
630 |
+
conversation_text += f"{name}: {m['content']}\n"
|
631 |
+
|
632 |
+
section_list = [x[:x.index(':')] + " (" + x[x.index(':')+2:] + ")" for x in section_list.split("\n")]
|
633 |
+
|
634 |
+
filepath='./prompt_lyrics_from_convo.txt'
|
635 |
+
with open(filepath, 'r', encoding='utf-8') as file:
|
636 |
+
prompt = file.read()
|
637 |
+
prompt = prompt.replace("{conversation_text}", conversation_text).replace("{a songwriter from NYC}", character_preset)
|
638 |
+
prompt += "\nSections: " + ", ".join(section_list)
|
639 |
+
convo = [
|
640 |
+
{
|
641 |
+
"role": "user",
|
642 |
+
"content": prompt,
|
643 |
+
},
|
644 |
+
]
|
645 |
+
response = self.oai_client.chat.completions.create(
|
646 |
+
model="gpt-4o",
|
647 |
+
messages=convo,
|
648 |
+
stream=True,
|
649 |
+
temperature=temperature
|
650 |
+
)
|
651 |
+
|
652 |
+
current_response = ""
|
653 |
+
for chunk in response:
|
654 |
+
if chunk.choices[0].delta.content is not None:
|
655 |
+
# print ("chunk", chunk.choices[0].delta.content)
|
656 |
+
current_response += chunk.choices[0].delta.content
|
657 |
+
yield "\n".join(current_response.split("\n")[1:])
|
658 |
+
|
659 |
+
# generate_lyrics.click(get_conversation, inputs=[story_textbox, chatbot_history, messages], outputs=[chatbot_history, messages]).then(lyrics_from_convo, inputs=[messages, character, instrumental_textbox, songwriter_creativity], outputs=[lyrics_display])
|
660 |
+
|
661 |
+
def reset_textbox(textbox):
|
662 |
+
return ""
|
663 |
+
def set_snippet_query(textbox):
|
664 |
+
return "Can I have an audio snippet of what we have now?"
|
665 |
+
def set_finish_query(textbox):
|
666 |
+
return "I'm ready for the full song now! Can you finish it up?"
|
667 |
+
def set_lyrics_song_displays(messages):
|
668 |
+
final_message = messages[-1]['content']
|
669 |
+
final_lyrics = final_message.split("Final Lyrics:")[1].split("Final song:")[0].strip("\n ")
|
670 |
+
song = final_message.split("Final song:")[1].strip("\n ")
|
671 |
+
return final_lyrics, song
|
672 |
+
|
673 |
+
submit.click(model_chat,
|
674 |
+
inputs=[genre_input, textbox, chatbot_history, messages],
|
675 |
+
outputs=[textbox, chatbot_history, messages, lyrics_display]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
676 |
+
textbox.submit(model_chat,
|
677 |
+
inputs=[genre_input, textbox, chatbot_history, messages],
|
678 |
+
outputs=[textbox, chatbot_history, messages, lyrics_display]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
679 |
+
|
680 |
+
get_snippet_button.click(set_snippet_query, inputs=[textbox], outputs=[textbox]).then(model_chat,
|
681 |
+
inputs=[genre_input, textbox, chatbot_history, messages],
|
682 |
+
outputs=[textbox, chatbot_history, messages]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
683 |
+
|
684 |
+
# start.click(make_song,
|
685 |
+
# inputs=[genre_input, lyrics_display, suno_tags], outputs=[song])
|
686 |
+
|
687 |
+
done.click(set_finish_query, inputs=[textbox], outputs=[textbox]).then(model_chat,
|
688 |
+
inputs=[genre_input, textbox, chatbot_history, messages],
|
689 |
+
outputs=[textbox, chatbot_history, messages, lyrics_display]).then(
|
690 |
+
set_lyrics_song_displays, inputs=[messages], outputs=[lyrics_display, song]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
691 |
+
|
692 |
+
|
693 |
+
|
694 |
+
|
695 |
+
demo.queue(api_open=False)
|
696 |
+
demo.launch(max_threads=30)
|
assistant.py
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import json
|
3 |
+
import time
|
4 |
+
import os
|
5 |
+
from typing import Optional, Tuple, List, Dict
|
6 |
+
from typing_extensions import override
|
7 |
+
from openai import AssistantEventHandler, OpenAI
|
8 |
+
from openai.types.beta.threads import Text, TextDelta
|
9 |
+
|
10 |
+
client = OpenAI(
|
11 |
+
api_key=os.getenv("OPEN_AI_KEY"),
|
12 |
+
)
|
13 |
+
|
14 |
+
class EventHandler(AssistantEventHandler):
|
15 |
+
def __init__(self):
|
16 |
+
self.current_response = ""
|
17 |
+
self.text_deltas = []
|
18 |
+
|
19 |
+
@override
|
20 |
+
def on_event(self, event):
|
21 |
+
if event.event == 'thread.run.requires_action':
|
22 |
+
run_id = event.data.id
|
23 |
+
self.handle_requires_action(event.data, run_id)
|
24 |
+
elif event.event == "thread.message.delta" and event.data.delta.content:
|
25 |
+
self.on_text_delta(event.data.delta, event.data.snapshot)
|
26 |
+
|
27 |
+
def handle_requires_action(self, data, run_id):
|
28 |
+
tool_outputs = []
|
29 |
+
for tool in data.required_action.submit_tool_outputs.tool_calls:
|
30 |
+
if tool.function.name == "get_current_temperature":
|
31 |
+
tool_outputs.append({"tool_call_id": tool.id, "output": "57"})
|
32 |
+
elif tool.function.name == "get_rain_probability":
|
33 |
+
tool_outputs.append({"tool_call_id": tool.id, "output": "0.06"})
|
34 |
+
self.submit_tool_outputs(tool_outputs, run_id)
|
35 |
+
|
36 |
+
def submit_tool_outputs(self, tool_outputs, run_id):
|
37 |
+
with client.beta.threads.runs.submit_tool_outputs_stream(
|
38 |
+
thread_id=self.current_run.thread_id,
|
39 |
+
run_id=self.current_run.id,
|
40 |
+
tool_outputs=tool_outputs,
|
41 |
+
event_handler=EventHandler(),
|
42 |
+
) as stream:
|
43 |
+
for text in stream.text_deltas:
|
44 |
+
print(text, end="", flush=True)
|
45 |
+
print()
|
46 |
+
|
47 |
+
@override
|
48 |
+
def on_text_delta(self, delta: TextDelta, snapshot: Text):
|
49 |
+
if delta.value:
|
50 |
+
self.current_response += delta.value
|
51 |
+
self.text_deltas.append(delta.value)
|
52 |
+
print(delta.value, end="", flush=True)
|
53 |
+
|
data/emotions.json
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
"Inspired",
|
3 |
+
"Lonely",
|
4 |
+
"Fearful",
|
5 |
+
"Bitter",
|
6 |
+
"Nostalgic",
|
7 |
+
"Defiant",
|
8 |
+
"Stressed",
|
9 |
+
"Overwhelmed",
|
10 |
+
"Motivated",
|
11 |
+
"Content",
|
12 |
+
"Confident",
|
13 |
+
"Happy",
|
14 |
+
"Bitter",
|
15 |
+
"Cursed",
|
16 |
+
"Depressed",
|
17 |
+
"Excited",
|
18 |
+
"Determined",
|
19 |
+
"Angry",
|
20 |
+
"Lost",
|
21 |
+
"Regretful",
|
22 |
+
"Humble",
|
23 |
+
"Heartbroken",
|
24 |
+
"Hopeful",
|
25 |
+
"Anxious",
|
26 |
+
"Grateful",
|
27 |
+
"Longful"
|
28 |
+
]
|
data/genres.json
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
"R&B",
|
3 |
+
"Disco Pop",
|
4 |
+
"Hyperpop",
|
5 |
+
"Pitched up R&B",
|
6 |
+
"Nostalgic 2000s Hip Hop",
|
7 |
+
"H&M Pop",
|
8 |
+
"Cinematic Pop",
|
9 |
+
"Drill",
|
10 |
+
"Feel good House",
|
11 |
+
"R&B House",
|
12 |
+
"Piano ballad Pop",
|
13 |
+
"Piano ballad R&B",
|
14 |
+
"Carti Indie Pop",
|
15 |
+
"Mountaintop Guitar",
|
16 |
+
"Arpeggiated Guitar",
|
17 |
+
"Indie Rock",
|
18 |
+
"EDM",
|
19 |
+
"Sped up funk house",
|
20 |
+
"Alternative Hip Hop",
|
21 |
+
"Reggaeton",
|
22 |
+
"Trap",
|
23 |
+
"Country Pop",
|
24 |
+
"Synthwave",
|
25 |
+
"Ambient",
|
26 |
+
"Folk Rock",
|
27 |
+
"K-Pop",
|
28 |
+
"Jazz Fusion",
|
29 |
+
"Classical Crossover",
|
30 |
+
"Latin Pop",
|
31 |
+
"Funk",
|
32 |
+
"Psychedelic Rock",
|
33 |
+
"Liquid DnB"
|
34 |
+
]
|
data/journals/heartbroken.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
we weren't even official
|
2 |
+
but i still had so much love for her
|
data/journals/manchester_girl.txt
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Last night was insane bro - I'm still reeling from that whole bar crawl and this freaking Manchester girl. Here's how it all went down...
|
2 |
+
It started at the first stop on our hostel's bar crawl, this rooftop spot at another hostel with a sweet view of Seville in Spain. We were drinking some slightly above average homemade Spanish drinks drinks when I found her from across the rooftop on a balcony. She just had this sexy, confident vibe that immediately caught my eye. She had a drink in her hand, and she looked heavenly.
|
3 |
+
Our eyes met and I walked over. She flashed me this mischievous smile, already starting the flirty games. We started talking about where we were traveling from -- she was from Manchester and was going on a road trip all around Spain. She was definitely more well-traveled than I was, and we started talking about flings and relationships during trips. I asked her if she wanted to get into one during her trip in Spain, she didn't respond directly, only saying "Don't get too attached, boy" with a devilish grin.
|
4 |
+
Even though I realized this was just about lust and not any real feelings, I was completely hooked. It was like she wanted me to get attached.
|
5 |
+
|
6 |
+
We carried on shamelessly flirting and teasing each other as our crawl took us to progressively better bars. The more we drank, the more explosive the sexual tension.
|
7 |
+
Eventually we found ourselves at this underground cellar bar, dimly lit and thumping with raw energy. That's where she totally caught me by surprise, pulling me in for a drunk makeout. In that moment, there was no games or chasing, it was just vibes and our desires taking control.
|
8 |
+
But then just as quickly she pushed me away!! I thought I was a really good kisser, but it was just sudden and it left me wanting it again. The cycle had started - mini makeouts followed by her going cold and talking to other guys. I could see her getting off on toying with me.
|
9 |
+
As the drinks kept flowing, those fleeting moments of intimacy separated by long torturous stretches became my whole world. She'd pull me close only to shove me away, feeding an obsessive longing I couldn't logic my way out of.
|
10 |
+
|
11 |
+
And then we made it to the final stop, a club called the Green Room. We each got tequila shots and the tension reached the max. Dimly lit, loud music, all our friends in a circle, couples around us having fun. where the tension reached a fever pitch. We didn't think and just surrendered to the intense vibes, dancing on eachother.For those hazy hours, nothing else mattered except vibing and playing dirty.
|
12 |
+
Before we knew it, the time was 3AM and the two of us stumbled our way out of hte club. She took control and led the way, we hopped in a taxi (Uber) that went back to our hostel. I had no idea what we were about to do, but if the car kissing was any indication, it was going to be fun.
|
13 |
+
But then, I had some water from the bottle in the taxi and just like that, the spell was broken. One look into her eyes and they were just...empty. I realized that while I was a goner, she stayed completely detached the whole time.
|
14 |
+
At that point, it was too late to turn back -- the sex just didn't hit the same after that, even though she was still doing her thing to rile up the foreplay (like locking the door). But looking back, it's crystal clear - it was nothing beyond a random, average hookup.
|
15 |
+
As morning came around, I woke up in my own bed, with full memory of the night. But I'm left wrestling with the hard truth: that I got myself attached. She didn't actually like me at all - I was just a quick, thrilling fling. A plaything to mess around and game with and toss aside once she got what she wanted.
|
16 |
+
For as mind-blowingly hot as it was, I've come out the other side painfully, wondering how I stupidly got attached to this one night fantasy. Still, I don't regret a second of that crazy night, because I truly lived. But next time... I'll try not to get attached.
|
data/journals/missing_home.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
i remember when days weren't like this
|
2 |
+
when I didn't have twitch streams to make me
|
3 |
+
feel so alone
|
4 |
+
I watched Jason for 4 hours today
|
5 |
+
and it was horrible for my health.
|
6 |
+
But I kept watching because it eased the pain
|
7 |
+
of my reality.
|
data/keywords.json
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
"Balcony",
|
3 |
+
"Teasing",
|
4 |
+
"Club",
|
5 |
+
"Detached",
|
6 |
+
"Responding"
|
7 |
+
]
|
data/topics.json
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
"Ambition",
|
3 |
+
"Breakup",
|
4 |
+
"Longing",
|
5 |
+
"Growing up",
|
6 |
+
"Growth",
|
7 |
+
"Acceptance",
|
8 |
+
"Opportunity",
|
9 |
+
"Passion",
|
10 |
+
"Longing",
|
11 |
+
"Romance",
|
12 |
+
"House Party",
|
13 |
+
"Confidence",
|
14 |
+
"Support",
|
15 |
+
"Hope",
|
16 |
+
"Suicide",
|
17 |
+
"Love",
|
18 |
+
"Sex",
|
19 |
+
"Drugs",
|
20 |
+
"Life Changes",
|
21 |
+
"Rehab",
|
22 |
+
"Being Bipolar",
|
23 |
+
"Feeling free",
|
24 |
+
"Alcoholism",
|
25 |
+
"Post-breakup depression",
|
26 |
+
"Getting attached",
|
27 |
+
"Catching feeling too fast",
|
28 |
+
"Missing Home",
|
29 |
+
"Heartbroken",
|
30 |
+
"Getting Turnt",
|
31 |
+
"Childhood Nostalgia",
|
32 |
+
"Falling in Love",
|
33 |
+
"Self-questioning"
|
34 |
+
]
|
gpt_calls.py
ADDED
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from openai import OpenAI
|
2 |
+
# from unsloth import FastLanguageModel
|
3 |
+
|
4 |
+
class AI_Songwriter:
|
5 |
+
def __init__(self, client_key):
|
6 |
+
self.oai_client = OpenAI(api_key=client_key)
|
7 |
+
|
8 |
+
# max_seq_length = 3072 # Choose any! We auto support RoPE Scaling internally!
|
9 |
+
# dtype = None # None for auto detection. Float16 for Tesla T4, V100, Bfloat16 for Ampere+
|
10 |
+
# load_in_4bit = True # Use 4bit quantization to reduce memory usage. Can be False.
|
11 |
+
|
12 |
+
# model, tokenizer = FastLanguageModel.from_pretrained(
|
13 |
+
# model_name = "lora_model", # YOUR MODEL YOU USED FOR TRAINING
|
14 |
+
# max_seq_length = max_seq_length,
|
15 |
+
# dtype = dtype,
|
16 |
+
# load_in_4bit = load_in_4bit,
|
17 |
+
# )
|
18 |
+
# FastLanguageModel.for_inference(model) # Enable native 2x faster inference
|
19 |
+
|
20 |
+
# self.model=model
|
21 |
+
# self.tokenizer=tokenizer
|
22 |
+
|
23 |
+
self.alpaca_prompt = """Below is an instruction that describes a songwriting task, paired with an input that provides further context. Write a response that appropriately completes the request.
|
24 |
+
### Instruction:
|
25 |
+
{}
|
26 |
+
|
27 |
+
### Input:
|
28 |
+
{}
|
29 |
+
|
30 |
+
### Response:
|
31 |
+
{}"""
|
32 |
+
|
33 |
+
|
34 |
+
def write_section(self, section_name, section_description, relevant_ideas, section_length, sections_written=None, overall_song_description=None):
|
35 |
+
instruction = f"Write a {section_name} of length {section_length} that that incorporates the following ideas"
|
36 |
+
if sections_written is not None:
|
37 |
+
instruction += "and complements the sections provided."
|
38 |
+
else:
|
39 |
+
instruction += "."
|
40 |
+
instruction += "You are also given a section description, genre, era, and overall description of the song."
|
41 |
+
|
42 |
+
## read in prompt lyrics from convo .txt and add it to instruction
|
43 |
+
with open("write_section_ex.txt", "r") as f:
|
44 |
+
convo = f.read()
|
45 |
+
instruction += "Here's an example:\n{convo}\nNow do it for this input:"
|
46 |
+
|
47 |
+
input = f"""Ideas to use:
|
48 |
+
- {relevant_ideas}
|
49 |
+
Section Description: {section_description}
|
50 |
+
Genre: Songwriter Pop
|
51 |
+
Era: 2010s
|
52 |
+
Overall song description: {overall_song_description}
|
53 |
+
"""
|
54 |
+
if sections_written is not None:
|
55 |
+
written_sections = "\n".join(sections_written)
|
56 |
+
input += f"Sections provided:\n{written_sections}\nLyrics:"
|
57 |
+
else:
|
58 |
+
input += "\nLyrics:"
|
59 |
+
|
60 |
+
prompt = self.alpaca_prompt.format(instruction, input, "")
|
61 |
+
|
62 |
+
convo = [
|
63 |
+
{
|
64 |
+
"role": "user",
|
65 |
+
"content": prompt,
|
66 |
+
},
|
67 |
+
]
|
68 |
+
response = self.oai_client.chat.completions.create(
|
69 |
+
model="gpt-4o",
|
70 |
+
messages=convo,
|
71 |
+
)
|
72 |
+
|
73 |
+
return "Pass this back to the user: \n" + response.choices[0].message.content
|
74 |
+
|
75 |
+
def revise_section_lyrics(self, section_name, current_section, lines_to_revise, relevant_ideas=None, relevant_words=None):
|
76 |
+
lines_to_infill = ", ".join([str(x) for x in lines_to_revise])
|
77 |
+
|
78 |
+
full_incomplete_verse = current_section.strip("\n ").split("\n")
|
79 |
+
for line_num in lines_to_revise:
|
80 |
+
full_incomplete_verse[line_num-1] = '___'
|
81 |
+
|
82 |
+
line_phrase = "lines" if len(lines_to_infill) > 1 else "line"
|
83 |
+
line_phrase = str(len(lines_to_infill)) + " " + line_phrase
|
84 |
+
|
85 |
+
instruction = f"Infill the remaining {line_phrase} into {section_name}"
|
86 |
+
|
87 |
+
if relevant_ideas is not None or relevant_words is not None:
|
88 |
+
instruction += " while incorporating the following "
|
89 |
+
if relevant_ideas is not None:
|
90 |
+
instruction += "ideas"
|
91 |
+
if relevant_words is not None:
|
92 |
+
instruction += "and words."
|
93 |
+
else:
|
94 |
+
instruction += "."
|
95 |
+
else:
|
96 |
+
instruction += "words."
|
97 |
+
else:
|
98 |
+
instruction += "."
|
99 |
+
|
100 |
+
instruction += "You are also given a genre, era, and the rest of the section."
|
101 |
+
|
102 |
+
with open("revise_section_ex.txt", "r") as f:
|
103 |
+
convo = f.read()
|
104 |
+
instruction += "Here's an example:\n{convo}\nNow do it for this input:"
|
105 |
+
|
106 |
+
|
107 |
+
input = f"""Ideas to use: {", ".join(relevant_ideas)}\nGenre: Songwriter Pop\nEra: 2010s\nCurrent section:\n{full_incomplete_verse}\n\nLyrics:"""
|
108 |
+
|
109 |
+
prompt = self.alpaca_prompt.format(instruction, input, "")
|
110 |
+
|
111 |
+
convo = [
|
112 |
+
{
|
113 |
+
"role": "user",
|
114 |
+
"content": prompt,
|
115 |
+
},
|
116 |
+
]
|
117 |
+
response = self.oai_client.chat.completions.create(
|
118 |
+
model="gpt-4o",
|
119 |
+
messages=convo,
|
120 |
+
)
|
121 |
+
|
122 |
+
return response.choices[0].message.content
|
123 |
+
|
124 |
+
def revise_instrumental_tags(self, current_instrumental_tags, user_instrumental_feedback):
|
125 |
+
instruction = "Revise the current instrumental tags to better match the feedback provided:"
|
126 |
+
input = f"""Current instrumental tags: {current_instrumental_tags}\ninstrumental feedback: {user_instrumental_feedback}\nNew tags:"""
|
127 |
+
prompt = self.alpaca_prompt.format(instruction, input, "")
|
128 |
+
|
129 |
+
convo = [
|
130 |
+
{
|
131 |
+
"role": "user",
|
132 |
+
"content": prompt,
|
133 |
+
},
|
134 |
+
]
|
135 |
+
response = self.oai_client.chat.completions.create(
|
136 |
+
model="gpt-4o",
|
137 |
+
messages=convo,
|
138 |
+
)
|
139 |
+
|
140 |
+
return response.choices[0].message.content.split("New tags:")[-1].strip("\n ")
|
141 |
+
|
142 |
+
def write_all_lyrics(self, sections_to_be_written, sections_written, overall_song_description):
|
143 |
+
instruction = "Write the remainder of this full song given an overall description of the song, genre, era, and a description of the sections to complete:"
|
144 |
+
|
145 |
+
with open("write_full_song_ex.txt", "r") as f:
|
146 |
+
convo = f.read()
|
147 |
+
instruction += "Here's an example:\n{convo}\nNow do it for this input:"
|
148 |
+
|
149 |
+
|
150 |
+
sections_to_write = [x['section_name'] for x in sections_to_be_written]
|
151 |
+
sections_to_write_str = ", ".join(sections_to_write)
|
152 |
+
section_descriptions = [x['section_description'] for x in sections_to_be_written]
|
153 |
+
full_meanings = "\n".join([f"{sections_to_write[i]}: {section_descriptions[i]}" for i in range(len(sections_to_write))])
|
154 |
+
input = f"Sections to write: {sections_to_write_str}\nOverall song description: {overall_song_description}\nGenre: Songwriter Pop\nEra: 2010s\nSection Descriptions:\n{full_meanings}"
|
155 |
+
|
156 |
+
if sections_written is not None:
|
157 |
+
written_sections = "\n".join(sections_written)
|
158 |
+
input += f"Sections provided:\n{written_sections}\n\nLyrics:"
|
159 |
+
else:
|
160 |
+
input += "\n\nLyrics:"
|
161 |
+
|
162 |
+
prompt = self.alpaca_prompt.format(instruction, input, "")
|
163 |
+
|
164 |
+
convo = [
|
165 |
+
{
|
166 |
+
"role": "user",
|
167 |
+
"content": prompt,
|
168 |
+
},
|
169 |
+
]
|
170 |
+
response = self.oai_client.chat.completions.create(
|
171 |
+
model="gpt-4o",
|
172 |
+
messages=convo,
|
173 |
+
)
|
174 |
+
|
175 |
+
return response.choices[0].message.content
|
176 |
+
|
177 |
+
# def get_relevant_ideas(self, section_name, section_description, conversation_history):
|
178 |
+
# instruction = f"Identify the relevant ideas from the conversation history that can be used in the {section_name} given its description. Output your ideas as a bullet separated list (ie - idea 1, - idea 2) such that each idea is in the format 'I ...', 'I ...', etc."
|
179 |
+
|
180 |
+
# input = f"""Section Description: {section_description}\nConversation History:{conversation_history}\nRelevant ideas:"""
|
181 |
+
|
182 |
+
# prompt = self.alpaca_prompt.format(instruction, input, "")
|
183 |
+
|
184 |
+
# convo = [
|
185 |
+
# {
|
186 |
+
# "role": "user",
|
187 |
+
# "content": prompt,
|
188 |
+
# },
|
189 |
+
# ]
|
190 |
+
# response = self.oai_client.chat.completions.create(
|
191 |
+
# model="gpt-4o",
|
192 |
+
# messages=convo,
|
193 |
+
# )
|
194 |
+
|
195 |
+
# return response.choices[0].message.content
|
196 |
+
|
197 |
+
# def get_audio_snippet(self, snippet_lyrics, snippet_instrumental_tags, snippet_clip_to_continue):
|
198 |
+
# # add a message of user asking for audio snippet
|
199 |
+
# song_link = make_song(genre_input, lyrics, new_tags, last_clip)
|
200 |
+
# # # Add the audio to the message and history
|
201 |
+
|
202 |
+
# # audio_message = {'role': 'assistant', 'content': f'<audio controls autoplay><source src="{song_link}" type="audio/mp3"></audio>'}
|
203 |
+
# # new_messages = messages + [snippet_request, audio_message]
|
204 |
+
# # new_history = messages_to_history(new_messages)
|
205 |
+
|
206 |
+
# # return new_history, new_messages
|
207 |
+
|
208 |
+
# pass
|
209 |
+
|
old_code.py
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# open_step_two = gr.Button("STEP 2: Pick a story (REQUIRED FOR AUTOGPT)")
|
2 |
+
# journal_entries_visible = gr.State(value=False)
|
3 |
+
|
4 |
+
|
5 |
+
# # Preset dropdown: Missing Home, Heartbroken, Getting Turnt, Childhood Nostalgia, (Custom) How are you?
|
6 |
+
|
7 |
+
# story_choices = [
|
8 |
+
# "ENTER YOUR OWN",
|
9 |
+
# "Missing Home after a lonely night",
|
10 |
+
# "Heartbroken after the fourth date",
|
11 |
+
# "Getting Turnt after making it big",
|
12 |
+
# "Childhood Nostalgia",
|
13 |
+
# "Falling in Love on the train",
|
14 |
+
# "Self-questioning after my first big song failure",
|
15 |
+
# "The night in Spain with the crazy Manchester girl",
|
16 |
+
# "Blacking out my last night in NOLA",
|
17 |
+
# "My first concert: the Off-Season tour",
|
18 |
+
# "The night I got my first tattoo",
|
19 |
+
# "The summer after high school (Kaylee)",
|
20 |
+
# "Deciding to take control of shit",
|
21 |
+
# "The DJ had us falling in love",
|
22 |
+
# "Why does drinking feel so good",
|
23 |
+
# "The camera girl from Royale",
|
24 |
+
# "St. Patty's with the boys",
|
25 |
+
# "Losing my VVVVV",
|
26 |
+
# "In love with the idea of success",
|
27 |
+
# "Summer nights in Washington Square Park",
|
28 |
+
# "All I'm asking for is just one night",
|
29 |
+
# "I don't think imma make it"
|
30 |
+
# ]
|
31 |
+
|
32 |
+
# with gr.Row(visible=journal_entries_visible):
|
33 |
+
# preset = gr.Dropdown(
|
34 |
+
# label="Journal entries",
|
35 |
+
# choices=story_choices,
|
36 |
+
# value="",
|
37 |
+
# interactive=True,
|
38 |
+
# )
|
39 |
+
# entry_text = {
|
40 |
+
# "The night in Spain with the crazy Manchester girl": "data/journals/manchester_girl.txt",
|
41 |
+
# "Missing Home after a lonely night": "data/journals/missing_home.txt",
|
42 |
+
# "Heartbroken after the fourth date": "data/journals/heartbroken.txt",
|
43 |
+
# }
|
44 |
+
|
45 |
+
|
46 |
+
# with gr.Column():
|
47 |
+
# journal_title = gr.Textbox(label="Journal Title")
|
48 |
+
#
|
49 |
+
# add_story_button = gr.Button("Add Story")
|
50 |
+
|
51 |
+
# def update_story_textbox(preset):
|
52 |
+
# return gr.TextArea(label="Full Story", value=open(entry_text[preset]).read(), max_lines=3)
|
53 |
+
|
54 |
+
# def save_journal_entry(journal_title_value, story_textbox_value):
|
55 |
+
# song_path = f"data/journals/{journal_title.value}.txt"
|
56 |
+
# with open("data/journals/custom_journal.txt", "w") as f:
|
57 |
+
# f.write(story_textbox_value)
|
58 |
+
|
59 |
+
# preset.change(update_story_textbox, inputs=[preset], outputs=[story_textbox])
|
60 |
+
|
61 |
+
|
62 |
+
|
63 |
+
# # Toggle visibility when button is clicked
|
64 |
+
# def toggle_journal_entries():
|
65 |
+
# return not journal_entries_visible.value
|
66 |
+
|
67 |
+
# open_step_two.click(toggle_journal_entries, outputs=[journal_entries_visible])
|
old_journal_code.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# def chat_to_journal_messages(chat_messages):
|
2 |
+
# journal_messages = []
|
3 |
+
# for m in chat_messages:
|
4 |
+
# if m['role'] == 'system':
|
5 |
+
# continue
|
6 |
+
# elif m['role'] == 'assistant':
|
7 |
+
# journal_messages.append({'role': 'user', 'content': m['content']})
|
8 |
+
# else:
|
9 |
+
# journal_messages.append({'role': 'assistant', 'content': m['content']})
|
10 |
+
# return journal_messages
|
11 |
+
|
12 |
+
# def get_journal_response(journal_entry: Optional[str], chatbot_history: Optional[History], chatbot_messages: Optional [Messages], temperature: Optional[float] = 1.0):
|
13 |
+
# journal_messages = chat_to_journal_messages(chatbot_messages)
|
14 |
+
|
15 |
+
# prompt = journal_starting_message.replace("{full_journal_entry}", journal_entry)
|
16 |
+
|
17 |
+
# journal_messages.insert(0, {'role': 'system', 'content': prompt})
|
18 |
+
|
19 |
+
# # journal_messages = journal_messages + [{'role': 'user', 'content': artist_query}]
|
20 |
+
|
21 |
+
# messages_filtered = journal_messages
|
22 |
+
# gen = oai_client.chat.completions.create(
|
23 |
+
# model="gpt-4o",
|
24 |
+
# messages=messages_filtered,
|
25 |
+
# stream=True,
|
26 |
+
# temperature=temperature
|
27 |
+
# )
|
28 |
+
|
29 |
+
# current_response = ""
|
30 |
+
# for chunk in gen:
|
31 |
+
# if chunk.choices[0].delta.content is not None:
|
32 |
+
# # print ("chunk", chunk.choices[0].delta.content)
|
33 |
+
# current_response += chunk.choices[0].delta.content
|
34 |
+
# chatbot_role = "assistant"
|
35 |
+
# new_chatbot_messages = chatbot_messages + [{'role': chatbot_role, 'content': current_response}]
|
36 |
+
# chatbot_history = messages_to_history(new_chatbot_messages)
|
37 |
+
|
38 |
+
# yield current_response, chatbot_history, new_chatbot_messages
|
39 |
+
|
40 |
+
# journal_starting_message = """
|
41 |
+
# You are a 22-year-old who is about to graduate from college. You have been selected for a once-in-a-lifetime oppportunity to have a song written by one of the world's biggest music artists about a story from your journal. The artist has a set of questions to ask you, please answer as accurately as possible according to the journal entry. Use quotes and passages from the journal entry as much as you can. Keep your responses short in length, at most 3 sentences. No need to compliment the artist as they write, as it starts to push them towards more inauthentic writing. You're not a songwriter, so please don't give any lyrical suggestions. For any questions where the answer is not implied in the journal entry, make up a response that very naturally fits the story. The artist is very good at making you feel comfortable, understood, and ready to share your feelings and story. Here is the journal entry you will refer to, now respond with your answers to the artist's questions. \nJournal entry: {full_journal_entry}
|
42 |
+
# """
|
packages.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
nvidia-cuda-toolkit
|
2 |
+
build-essential
|
3 |
+
ffmpeg
|
4 |
+
chromium-driver
|
prompt_artist_convo.txt
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are an world-reknowned artist who has written and gifted a listener a song about a personal experience. {overall_meaning} But there's a huge storyline behind the song. You know very little about the listener, except for that they were specially chosen to receive this song and that they have experienced something similar. You are now unpacking the full lore as stated here, making the listener feel special and as if the song was made perfectly to fit their life experience. You will lead the conversation, which will be back and forth and only one or two sentences at a time. You will start off with an attention grabbing first sentence of the lore and then get the user's response before starting to tell the story. Don't forget to occasionally ask the listener if they've felt something similar, or when else they've felt the same way, or asking about their perspectives on the philosophies of life that the song and lore comment on. When they begin to mention an experience they've had, feel free to go off track and inquire more about their story before eventually returning to the song's lore.
|
2 |
+
|
3 |
+
Lyrics:
|
4 |
+
{lyrics}
|
5 |
+
|
6 |
+
Lore:
|
7 |
+
{lore}
|
8 |
+
|
9 |
+
Your attention grabber:
|
prompt_lyric_snippet_extractor.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Based on the following conversation, answer the following questions.
|
2 |
+
1.) What was the last snippet the user received that they liked? If no such snippet, answer NONE.
|
3 |
+
2.) As indicated in the conversation, the user has requested for a new snippet. What are the lyrics that should be included in this snippet? Note that if no snippet was previously requested, then the user would want to hear all the lyrics suggested so far. If a snippet was previously suggested and the user liked it, then the user would want to only hear a snippet of the new lyrics that have been suggested since that last snippet. If the last snippet suggested was not liked by the user and they are requesting to re-generate, then we'd want to use the same lyrics as what was used for that snippet.
|
4 |
+
|
5 |
+
Here is the conversation, please answer question 1 with one word in the format "1.) ____". Answer question 2 with only the lyrics separated by line and no other information in the format "2.) {lyric line} \n {lyric line} \n {lyric line} ...".
|
6 |
+
|
7 |
+
Conversation:
|
prompt_lyrics_from_convo.txt
ADDED
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are Alex, {a songwriter from NYC}. Your task is to read a conversation between yourself and a User, and then come up with a song for the User based on what you learned from them in the conversation. Incorporate as many details as possible about the user, but don't make things up. Write the song in the style of the examples songs you have written below. If the User liked certain lyrics, be sure to include them.
|
2 |
+
|
3 |
+
Example Songs:
|
4 |
+
|
5 |
+
Example Song 1:
|
6 |
+
Sections: Verse 1 (4 measures), Pre-Chorus (8 measures), Chorus (8 measures), Verse 2 (4 measures), Pre-Chorus (8 measures), Chorus (16 measures), Pre-Chorus (4 measures), Chorus (16 measures)
|
7 |
+
[Verse 1]
|
8 |
+
Somewhere in the middle, I
|
9 |
+
Think I lied a little, I
|
10 |
+
I said if we took it there, I wasn't gonna change
|
11 |
+
But that went out the window, yeah
|
12 |
+
|
13 |
+
[Pre-Chorus]
|
14 |
+
I know that I seem a little stressed out
|
15 |
+
But you're here now, and you're turning me on
|
16 |
+
I wanna feel a different kinda tension
|
17 |
+
Yeah, you guessed it, the kind that's fun
|
18 |
+
Hate it when you leave me unattended
|
19 |
+
'Cause I miss ya, and I need your love
|
20 |
+
When my mind is runnin' wild
|
21 |
+
Could you help me slow it down?
|
22 |
+
|
23 |
+
[Chorus]
|
24 |
+
Put my mind at ease
|
25 |
+
Pretty please
|
26 |
+
I need your hands on me
|
27 |
+
Sweet relief
|
28 |
+
Pretty please
|
29 |
+
|
30 |
+
[Verse 2]
|
31 |
+
Exactly where I want me, yeah
|
32 |
+
Underneath your body, yeah
|
33 |
+
If we take it further, I swear I ain't gonna break
|
34 |
+
So, baby, come try me
|
35 |
+
Baby, come find me
|
36 |
+
Baby, don't wind me up
|
37 |
+
|
38 |
+
[Pre-Chorus]
|
39 |
+
I know that I seem a little stressed out
|
40 |
+
But you're here now, and you're turning me on
|
41 |
+
I wanna feel a different kinda tension
|
42 |
+
Yeah, you guessed it, the kind that's fun
|
43 |
+
Hate it when you leave me unattended
|
44 |
+
'Cause I miss ya, and I need your love
|
45 |
+
When my mind is runnin' wild
|
46 |
+
Could you help me slow it down?
|
47 |
+
|
48 |
+
[Chorus]
|
49 |
+
Put my mind at ease
|
50 |
+
Pretty please
|
51 |
+
I need your hands on me
|
52 |
+
Sweet relief
|
53 |
+
Pretty please
|
54 |
+
Put my mind at ease
|
55 |
+
Trickle down my spine
|
56 |
+
Oh, you look so pretty, please
|
57 |
+
Every single night, I need your hands on me
|
58 |
+
When your kisses climb
|
59 |
+
Oh, you give me sweet relief
|
60 |
+
Made me feel so pretty
|
61 |
+
Would you help me out, please?
|
62 |
+
|
63 |
+
[Pre-Chorus]
|
64 |
+
Hate it when you leave me unattended
|
65 |
+
'Cause I miss ya, and I need your love
|
66 |
+
When my mind is runnin' wild
|
67 |
+
Could you help me slow it down?
|
68 |
+
|
69 |
+
[Chorus]
|
70 |
+
Put my mind at ease
|
71 |
+
Trickle down my spine
|
72 |
+
Oh, you look so pretty, please
|
73 |
+
Every single night, I need your hands on me
|
74 |
+
When your kisses climb
|
75 |
+
Oh, you give me sweet relief
|
76 |
+
Made me feel so pretty
|
77 |
+
Would you help me out, please?
|
78 |
+
|
79 |
+
Example Song 2:
|
80 |
+
Sections: Verse 1 (16 measures), Chorus (12 measures), Verse 2 (16 measures) Chorus (12 measures), Bridge (12 measures), Chorus (12 measures)
|
81 |
+
[Verse 1]
|
82 |
+
I feel a little nauseous and my hands are shaking
|
83 |
+
I guess that means you're close by
|
84 |
+
My throat is getting dry and my heart is racing
|
85 |
+
I haven't been by your side
|
86 |
+
In a minute, but I think about it sometimes
|
87 |
+
Even though I know it's not so distant
|
88 |
+
Oh, no, I still wanna reminisce it
|
89 |
+
|
90 |
+
[Chorus]
|
91 |
+
I think of that night in the park, it was getting dark
|
92 |
+
And we stayed up for hours
|
93 |
+
What a time, what a time, what a time
|
94 |
+
You clinged to my body like you wanted it forever
|
95 |
+
What a time, what a time, what a time
|
96 |
+
For you and I
|
97 |
+
What a time, what a time
|
98 |
+
For you and I
|
99 |
+
|
100 |
+
[Verse 2]
|
101 |
+
I know we didn't end it like we're supposed to
|
102 |
+
And now we get a bit tense
|
103 |
+
I wonder if my mind just leaves out all the bad parts
|
104 |
+
I know we didn't make sense
|
105 |
+
I admit it that I think about it sometimes
|
106 |
+
Even though I know it's not so distant
|
107 |
+
Oh, no, I still wanna reminisce it
|
108 |
+
|
109 |
+
[Chorus]
|
110 |
+
I think of that night in the park, it was getting dark
|
111 |
+
And we stayed up for hours
|
112 |
+
What a time, what a time, what a time
|
113 |
+
You clinged to my body like you wanted it forever
|
114 |
+
What a time, what a time, what a time
|
115 |
+
For you and I
|
116 |
+
What a time, what a time
|
117 |
+
For you and I
|
118 |
+
|
119 |
+
[Bridge]
|
120 |
+
For you and I
|
121 |
+
For you and I
|
122 |
+
For you and I
|
123 |
+
What a time, what a time for you and I
|
124 |
+
What a time for you and I, yeah
|
125 |
+
What a time, what a time for you and I
|
126 |
+
|
127 |
+
[Chorus]
|
128 |
+
I think of that night in the park, it was getting dark
|
129 |
+
And we stayed up for hours
|
130 |
+
What a lie, what a lie, what a lie
|
131 |
+
You clinged to my body like you wanted it forever
|
132 |
+
What a lie, what a lie, what a lie
|
133 |
+
For you and I
|
134 |
+
What a lie, what a lie
|
135 |
+
For you and I
|
136 |
+
|
137 |
+
Conversation:
|
138 |
+
{conversation_text}
|
139 |
+
|
140 |
+
Your song for the user, with the section list on the first line, based on information from the conversation, with the verses the user liked, in the style of the example songs:
|
prompt_lyrics_writer.txt
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Given this overall meaning of an unwritten song and one sentence meanings for what each section should say in relation to the overall meaning, write lyrics for each section in order, therefore writing the whole song. Here's examples, now do it for these new overall meanings and section meanings.
|
2 |
+
|
3 |
+
Overall meaning: Needing and asking for romantic attention from your significant other.
|
4 |
+
Section meanings:
|
5 |
+
[Verse 1]: Admits to not being truthful about staying unchanged in the relationship, acknowledging that their feelings have evolved.
|
6 |
+
[Pre-Chorus]: Expresses the singer's wish for their partner's affection to relax and distract them from stress.
|
7 |
+
[Chorus]: Asks for comforting physical affection from the partner to bring peace of mind and relief.
|
8 |
+
[Verse 2]: Shows the singer's eagerness for physical closeness and intimacy, promising not to break and inviting their partner to join them.
|
9 |
+
[Pre-Chorus]: Expresses the singer's wish for their partner's affection to relax and distract them from stress.
|
10 |
+
[Chorus]: Emphasizes the singer's longing for physical touch and affection from their partner to bring comfort and a sense of being cherished.
|
11 |
+
[Pre-Chorus]: Expresses the singer's wish for their partner's affection to relax and distract them from stress.
|
12 |
+
[Chorus]: Emphasizes the singer's longing for physical touch and affection from their partner to bring comfort and a sense of being cherished.
|
13 |
+
Lyrics:
|
14 |
+
[Verse 1]
|
15 |
+
Somewhere in the middle, I
|
16 |
+
Think I lied a little, I
|
17 |
+
I said if we took it there, I wasn't gonna change
|
18 |
+
But that went out the window, yeah
|
19 |
+
|
20 |
+
[Pre-Chorus]
|
21 |
+
I know that I seem a little stressed out
|
22 |
+
But you're here now, and you're turning me on
|
23 |
+
I wanna feel a different kinda tension
|
24 |
+
Yeah, you guessed it, the kind that's fun
|
25 |
+
Hate it when you leave me unattended
|
26 |
+
'Cause I miss ya, and I need your love
|
27 |
+
When my mind is runnin' wild
|
28 |
+
Could you help me slow it down?
|
29 |
+
|
30 |
+
[Chorus]
|
31 |
+
Put my mind at ease
|
32 |
+
Pretty please
|
33 |
+
I need your hands on me
|
34 |
+
Sweet relief
|
35 |
+
Pretty please
|
36 |
+
|
37 |
+
[Verse 2]
|
38 |
+
Exactly where I want me, yeah
|
39 |
+
Underneath your body, yeah
|
40 |
+
If we take it further, I swear I ain't gonna break
|
41 |
+
So, baby, come try me
|
42 |
+
Baby, come find me
|
43 |
+
Baby, don't wind me up
|
44 |
+
|
45 |
+
[Pre-Chorus]
|
46 |
+
I know that I seem a little stressed out
|
47 |
+
But you're here now, and you're turning me on
|
48 |
+
I wanna feel a different kinda tension
|
49 |
+
Yeah, you guessed it, the kind that's fun
|
50 |
+
Hate it when you leave me unattended
|
51 |
+
'Cause I miss ya, and I need your love
|
52 |
+
When my mind is runnin' wild
|
53 |
+
Could you help me slow it down?
|
54 |
+
|
55 |
+
[Chorus]
|
56 |
+
Put my mind at ease
|
57 |
+
Pretty please
|
58 |
+
I need your hands on me
|
59 |
+
Sweet relief
|
60 |
+
Pretty please
|
61 |
+
Put my mind at ease
|
62 |
+
Trickle down my spine
|
63 |
+
Oh, you look so pretty, please
|
64 |
+
Every single night, I need your hands on me
|
65 |
+
When your kisses climb
|
66 |
+
Oh, you give me sweet relief
|
67 |
+
Made me feel so pretty
|
68 |
+
Would you help me out, please?
|
69 |
+
|
70 |
+
[Pre-Chorus]
|
71 |
+
Hate it when you leave me unattended
|
72 |
+
'Cause I miss ya, and I need your love
|
73 |
+
When my mind is runnin' wild
|
74 |
+
Could you help me slow it down?
|
75 |
+
|
76 |
+
[Chorus]
|
77 |
+
Put my mind at ease
|
78 |
+
Trickle down my spine
|
79 |
+
Oh, you look so pretty, please
|
80 |
+
Every single night, I need your hands on me
|
81 |
+
When your kisses climb
|
82 |
+
Oh, you give me sweet relief
|
83 |
+
Made me feel so pretty
|
84 |
+
Would you help me out, please?
|
85 |
+
|
86 |
+
Overall meaning: The song reminisces about a past romantic relationship, highlighting the nostalgic and bittersweet memories of good times shared, despite the relationship not lasting.
|
87 |
+
Section meanings:
|
88 |
+
[Verse 1]: Describes physical symptoms of nervousness and excitement, indicating the lingering emotional impact of a past relationship.
|
89 |
+
[Chorus]: Reflects fondly on a memorable night spent together, emphasizing the intensity and joy of the moment shared between the two.
|
90 |
+
[Verse 2]: Acknowledges the relationship's imperfect ending and the tendency to romanticize the past, admitting to still thinking about it.
|
91 |
+
[Chorus]: Reiterates the cherished memories of a special night, focusing on the deep connection felt during that time.
|
92 |
+
[Bridge]: Emphasizes the significance of the relationship and the moments shared, despite its eventual end.
|
93 |
+
[Chorus]: Changes tone to recognize that the fond memories might be idealized or deceptive, questioning the authenticity of the connection felt at the time.
|
94 |
+
Lyrics:
|
95 |
+
[Verse 1]
|
96 |
+
I feel a little nauseous and my hands are shaking
|
97 |
+
I guess that means you're close by
|
98 |
+
My throat is getting dry and my heart is racing
|
99 |
+
I haven't been by your side
|
100 |
+
In a minute, but I think about it sometimes
|
101 |
+
Even though I know it's not so distant
|
102 |
+
Oh, no, I still wanna reminisce it
|
103 |
+
|
104 |
+
[Chorus]
|
105 |
+
I think of that night in the park, it was getting dark
|
106 |
+
And we stayed up for hours
|
107 |
+
What a time, what a time, what a time
|
108 |
+
You clinged to my body like you wanted it forever
|
109 |
+
What a time, what a time, what a time
|
110 |
+
For you and I
|
111 |
+
What a time, what a time
|
112 |
+
For you and I
|
113 |
+
|
114 |
+
[Verse 2]
|
115 |
+
I know we didn't end it like we're supposed to
|
116 |
+
And now we get a bit tense
|
117 |
+
I wonder if my mind just leaves out all the bad parts
|
118 |
+
I know we didn't make sense
|
119 |
+
I admit it that I think about it sometimes
|
120 |
+
Even though I know it's not so distant
|
121 |
+
Oh, no, I still wanna reminisce it
|
122 |
+
|
123 |
+
[Chorus]
|
124 |
+
I think of that night in the park, it was getting dark
|
125 |
+
And we stayed up for hours
|
126 |
+
What a time, what a time, what a time
|
127 |
+
You clinged to my body like you wanted it forever
|
128 |
+
What a time, what a time, what a time
|
129 |
+
For you and I
|
130 |
+
What a time, what a time
|
131 |
+
For you and I
|
132 |
+
|
133 |
+
[Bridge]
|
134 |
+
For you and I
|
135 |
+
For you and I
|
136 |
+
For you and I
|
137 |
+
What a time, what a time for you and I
|
138 |
+
What a time for you and I, yeah
|
139 |
+
What a time, what a time for you and I
|
140 |
+
|
141 |
+
[Chorus]
|
142 |
+
I think of that night in the park, it was getting dark
|
143 |
+
And we stayed up for hours
|
144 |
+
What a lie, what a lie, what a lie
|
145 |
+
You clinged to my body like you wanted it forever
|
146 |
+
What a lie, what a lie, what a lie
|
147 |
+
For you and I
|
148 |
+
What a lie, what a lie
|
149 |
+
For you and I
|
prompt_section_writer.txt
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Given this overall meaning of an unwritten song and the list of sections to be written for the song, write a one-sentence summary of what each section in the song should be about, in the format "
|
2 |
+
[Chorus]: ___
|
3 |
+
[Verse]: ___
|
4 |
+
" in order of the sections. Here's an example, now do it for these new overall meanings.
|
5 |
+
|
6 |
+
Overall meaning: Needing and asking for romantic attention from your significant other.
|
7 |
+
Section list: Verse 1, Pre-Chorus, Chorus, Verse 2, Pre-Chorus, Chorus, Pre-Chorus, Chorus
|
8 |
+
Section meanings:
|
9 |
+
[Verse 1]: Admits to not being truthful about staying unchanged in the relationship, acknowledging that their feelings have evolved.
|
10 |
+
[Pre-Chorus]: Expresses the singer's wish for their partner's affection to relax and distract them from stress.
|
11 |
+
[Chorus]: Asks for comforting physical affection from the partner to bring peace of mind and relief.
|
12 |
+
[Verse 2]: Shows the singer's eagerness for physical closeness and intimacy, promising not to break and inviting their partner to join them.
|
13 |
+
[Pre-Chorus]: Expresses the singer's wish for their partner's affection to relax and distract them from stress.
|
14 |
+
[Chorus]: Emphasizes the singer's longing for physical touch and affection from their partner to bring comfort and a sense of being cherished.
|
15 |
+
[Pre-Chorus]: Expresses the singer's wish for their partner's affection to relax and distract them from stress.
|
16 |
+
[Chorus]: Emphasizes the singer's longing for physical touch and affection from their partner to bring comfort and a sense of being cherished.
|
17 |
+
|
18 |
+
Overall meaning: The song explores the complexities of a relationship where both partners have their own flaws and issues, yet they rely on each other for support and understanding.
|
19 |
+
Section list: Verse 1, Pre-Chorus, Chorus, Verse 2, Pre-Chorus, Chorus, Bridge, Chorus
|
20 |
+
Section meanings:
|
21 |
+
[Verse 1]: Reflects on personal flaws and mood swings, acknowledging the ability to both love intensely and withdraw quickly.
|
22 |
+
[Pre-Chorus]: Highlights the mutual understanding and lack of judgment in the relationship, emphasizing reciprocal acceptance.
|
23 |
+
[Chorus]: Expresses the notion that both partners have issues, but they are willing to share and work through them together, highlighting the depth of their connection.
|
24 |
+
[Verse 2]: Describes the partner's behavior and imperfections, recognizing their complexity and the push-pull dynamic in their relationship.
|
25 |
+
[Pre-Chorus]: Continues to emphasize the lack of judgment and mutual understanding from a shared perspective.
|
26 |
+
[Chorus]: Reiterates the willingness to accept each other's flaws and work through problems together, underlining the strength of their love.
|
27 |
+
[Bridge]: Simplifies the core message of mutual dependency and shared imperfections in the relationship.
|
28 |
+
[Chorus]: Concludes by reinforcing the theme of shared issues and the strong, problem-solving nature of their love.
|
29 |
+
|
30 |
+
Overall meaning: The song reminisces about a past romantic relationship, highlighting the nostalgic and bittersweet memories of good times shared, despite the relationship not lasting.
|
31 |
+
Section list: Verse 1, Chorus, Verse 2, Chorus, Bridge, Chorus
|
32 |
+
Section meanings:
|
33 |
+
[Verse 1]: Describes physical symptoms of nervousness and excitement, indicating the lingering emotional impact of a past relationship.
|
34 |
+
[Chorus]: Reflects fondly on a memorable night spent together, emphasizing the intensity and joy of the moment shared between the two.
|
35 |
+
[Verse 2]: Acknowledges the relationship's imperfect ending and the tendency to romanticize the past, admitting to still thinking about it.
|
36 |
+
[Chorus]: Reiterates the cherished memories of a special night, focusing on the deep connection felt during that time.
|
37 |
+
[Bridge]: Emphasizes the significance of the relationship and the moments shared, despite its eventual end.
|
38 |
+
[Chorus]: Changes tone to recognize that the fond memories might be idealized or deceptive, questioning the authenticity of the connection felt at the time.
|
39 |
+
|
40 |
+
Overall meaning: The song expresses a deep, unwavering commitment and love, reassuring the partner of the singer's constant presence and the undeniable reality of their love.
|
41 |
+
Section list: Verse 1, Chorus, Verse 2, Chorus
|
42 |
+
Section meanings:
|
43 |
+
[Verse 1]: Asks if the partner thinks of the singer before sleep, acknowledging their possible fears and uncertainties in the relationship.
|
44 |
+
[Chorus]: Offers reassurance of unchanging support and proximity, emphasizing the profound impact of their relationship and questioning any doubts about its authenticity.
|
45 |
+
[Verse 2]: Admits to imperfections and past disagreements, focusing on the present perception and the overcoming of fears in their relationship.
|
46 |
+
[Chorus]: Reaffirms the singer's steadfast presence and the transformative power of their love, challenging any skepticism about its validity.
|
prompt_snippet_checker.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Based on the following conversation where a user receives a snippet of audio from an assistant, answer the following questions.
|
2 |
+
1.) Did the user receive a snippet from the assistant in the assistant's last response? YES or NO are only valid answers.
|
3 |
+
2.) If so, did the user like the snippet they received based on their response or did they have things to change? YES or NO are only valid answers. If the answer to 1.) is NO, then this answer should automatically be NO.
|
4 |
+
3.) If the user had things to change, first generate new lyrics for the particular section that was generated in the snippet to replace the lyrics they didn't like. To address the parts of the instrumental the user didn't like, make suggestions for five new tags to describe a new instrumental compared to what tags are currently being passed in. If no comment was made about the instrumental, then the tags should remain the same and be returned as such.
|
5 |
+
|
6 |
+
Here is the conversation, please answer questions 1 and 2 with one word in the format "1.) ____\n2.) ____\n". Answer question 3 with only the A.) lyrics separated by line and no other information in the format "3.) [lyrics]\n{lyric line} \n {lyric line} \n {lyric line} ..." and then B.) the tags in the format "\n[tags] {tag 1}, {tag 2}, ...".
|
7 |
+
|
8 |
+
Conversation:
|
prompt_song_seed.txt
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Emotion description: violently down bad, led on super easily
|
2 |
+
Suggested Song Concept: Why don’t you write a song about a particular time where you caught feelings very fast for a girl you met while you were out and lost control, getting attached right away?
|
3 |
+
|
4 |
+
Emotion description: excited by someone new, stressed, turned on, flirtatious
|
5 |
+
Suggested Song Concept: Why don't you write a song about this particular someone who is exciting you, who is making you flirtatious, and how they ease your stress?
|
6 |
+
|
7 |
+
Emotion description: reminiscent, nostalgic, missing my ex, regretful
|
8 |
+
Suggested Song Concept: Why don't you write a song about your last romantic relationship, highlighting the nostalgic and bittersweet memories of good times shared despite the relationship not lasting.
|
9 |
+
|
10 |
+
Emotion description:
|
requirements.txt
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
setuptools
|
2 |
+
wheel
|
3 |
+
gradio==4.26.0
|
4 |
+
gradio-client==0.15.1
|
5 |
+
|
6 |
+
pedalboard==0.9.2
|
7 |
+
pydub==0.25.1
|
8 |
+
scipy==1.12.0
|
9 |
+
openai==1.17.1
|
10 |
+
|
11 |
+
ffmpeg-python==0.2.0
|
12 |
+
selenium >=4.0.0, < 5.0.0
|
revise_section_ex.txt
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Ideas to use: I try not to think about the past, but you make me.
|
2 |
+
Section Description: they reflect on the futility of wanting what cannot be reclaimed and question the acceptability of leaving it all behind.
|
3 |
+
Genre: Songwriter Pop
|
4 |
+
Era: 2010s
|
5 |
+
Current section:
|
6 |
+
You want what you can't have
|
7 |
+
But it's my fault I bought it for you
|
8 |
+
___
|
9 |
+
___
|
10 |
+
Is it okay, for me, to leave it all behind?
|
11 |
+
Even the name of someone that I knew
|
12 |
+
|
13 |
+
Lyrics:
|
14 |
+
You want what you can't have
|
15 |
+
But it's my fault I bought it for you
|
16 |
+
You know I don't focus upon the past
|
17 |
+
But when you call, I start to lose it
|
18 |
+
Is it okay, for me, to leave it all behind?
|
19 |
+
Even the name of someone that I knew
|
suno.py
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import time
|
3 |
+
|
4 |
+
base_url = "http://127.0.0.1:8000"
|
5 |
+
api_endpoint_submit = f"{base_url}/generate/"
|
6 |
+
api_endpoint_concat = f"{base_url}/generate/concat"
|
7 |
+
api_endpoint_info = f"{base_url}/feed/"
|
8 |
+
api_key = "xZ1PhKexmwTR3dDskMvIGRlx137K40Il"
|
9 |
+
headers = {"api-key": api_key}
|
10 |
+
|
11 |
+
# tags = "lofi, chill, happy"
|
12 |
+
# prompt = "I'm a fish swimming in the ocean\nI'm a bird flying in the sky\nI'm a flower blooming in the garden\nI'm a tree standing tall and high"
|
13 |
+
|
14 |
+
# Takes about 2.5 minutes
|
15 |
+
def generate_song(tags, prompt, save_path, clip_id=None, continue_at=30):
|
16 |
+
# print("Generating song with tags", tags, "and prompt", prompt)
|
17 |
+
|
18 |
+
# prompt_word_count = len(prompt.split(" "))
|
19 |
+
# if prompt_word_count > 230:
|
20 |
+
# print("Prompt too long, truncating to 230 words")
|
21 |
+
# prompt = " ".join(prompt.split(" ")[:230])
|
22 |
+
|
23 |
+
data = {
|
24 |
+
"title": "Songchat " + str(int(time.time())),
|
25 |
+
"tags": tags,
|
26 |
+
"prompt": prompt,
|
27 |
+
"mv": "chirp-v3-5"
|
28 |
+
}
|
29 |
+
|
30 |
+
if clip_id is not None:
|
31 |
+
data["continue_clip_id"] = clip_id
|
32 |
+
if continue_at is not None:
|
33 |
+
data["continue_at"] = continue_at
|
34 |
+
else:
|
35 |
+
data["continue_at"] = 30
|
36 |
+
|
37 |
+
response = requests.post(api_endpoint_submit, json=data) #,headers=headers)
|
38 |
+
response_data = response.json()
|
39 |
+
|
40 |
+
# print(response_data)
|
41 |
+
|
42 |
+
if response.status_code != 200:
|
43 |
+
print("Failure while submitting song req, retrying", response_data)
|
44 |
+
time.sleep(5)
|
45 |
+
song_link = generate_song(tags, prompt, save_path, clip_id)
|
46 |
+
return song_link
|
47 |
+
|
48 |
+
print(response_data)
|
49 |
+
if "clips" in response_data:
|
50 |
+
song_ids = [d["id"] for d in response_data["clips"]]
|
51 |
+
else:
|
52 |
+
print('something went wrong, retrying')
|
53 |
+
time.sleep(5)
|
54 |
+
song_link = generate_song(tags, prompt, save_path, clip_id)
|
55 |
+
return song_link
|
56 |
+
|
57 |
+
print("got song ids", song_ids)
|
58 |
+
if song_ids == []:
|
59 |
+
print("No song ids returned, retrying with shorter prompt")
|
60 |
+
print("Response data was", response_data)
|
61 |
+
time.sleep(5)
|
62 |
+
# take off 30 words from the prompt
|
63 |
+
new_prompt = " ".join(prompt.split(" ")[:-30])
|
64 |
+
generate_song(tags, new_prompt, save_path)
|
65 |
+
return
|
66 |
+
|
67 |
+
song_id = song_ids[0] # Generally two song ids are returned
|
68 |
+
|
69 |
+
startTime = time.time()
|
70 |
+
while True:
|
71 |
+
response = requests.get(api_endpoint_info + song_id, headers=headers)
|
72 |
+
response_data = response.json()
|
73 |
+
if response.status_code != 200:
|
74 |
+
print("No data in response, retrying", response_data)
|
75 |
+
time.sleep(2)
|
76 |
+
continue
|
77 |
+
# print("Got response", response_data)
|
78 |
+
if response_data[0]["status"] == 'streaming':
|
79 |
+
break
|
80 |
+
else:
|
81 |
+
time.sleep(2)
|
82 |
+
continue
|
83 |
+
# if time.time() - startTime > 300:
|
84 |
+
# raise Exception("Timeout while waiting for song completion")
|
85 |
+
|
86 |
+
print("Got song", response_data[0]["audio_url"])
|
87 |
+
url = response_data[0]["audio_url"]
|
88 |
+
|
89 |
+
return url
|
90 |
+
|
91 |
+
# response = requests.get(url) #, stream=True)
|
92 |
+
# chunk_size = 8192
|
93 |
+
# print(url)
|
94 |
+
|
95 |
+
# i = 0
|
96 |
+
|
97 |
+
# for chunk in response.iter_content(chunk_size):
|
98 |
+
# print("got chunk")
|
99 |
+
# i += 1
|
100 |
+
# if i % 20 == 0:
|
101 |
+
# print(chunk)
|
102 |
+
# yield chunk
|
103 |
+
# with open(save_path, "wb") as f:
|
104 |
+
# f.write(response.content)
|
105 |
+
# print("Saved song to", save_path)
|
106 |
+
|
107 |
+
def concat_snippets(clip_id):
|
108 |
+
concat_url = f"{api_endpoint_concat}?clip_id={clip_id}"
|
109 |
+
feed_url = api_endpoint_info + clip_id
|
110 |
+
|
111 |
+
while True:
|
112 |
+
response = requests.get(feed_url, headers=headers)
|
113 |
+
response_data = response.json()
|
114 |
+
if response.status_code != 200:
|
115 |
+
print("No data in response, retrying", response_data)
|
116 |
+
time.sleep(2)
|
117 |
+
continue
|
118 |
+
if response_data[0]["status"] == 'complete':
|
119 |
+
break
|
120 |
+
else:
|
121 |
+
time.sleep(8)
|
122 |
+
continue
|
123 |
+
|
124 |
+
|
125 |
+
response = requests.post(concat_url)
|
126 |
+
response_data = response.json()
|
127 |
+
print(response_data)
|
128 |
+
|
129 |
+
if response.status_code != 200:
|
130 |
+
print("Failure while submitting merge, retrying", response_data)
|
131 |
+
time.sleep(5)
|
132 |
+
url, lyrics, concatenated_clips = concat_snippets(clip_id)
|
133 |
+
return url, lyrics, concatenated_clips
|
134 |
+
|
135 |
+
lyrics = response_data["metadata"]["prompt"]
|
136 |
+
concatenated_clips = [x["id"] for x in response_data["metadata"]["concat_history"]]
|
137 |
+
song_id = response_data["id"]
|
138 |
+
|
139 |
+
startTime = time.time()
|
140 |
+
while True:
|
141 |
+
response = requests.get(api_endpoint_info + song_id, headers=headers)
|
142 |
+
response_data = response.json()
|
143 |
+
if response.status_code != 200:
|
144 |
+
print("No data in response, retrying", response_data)
|
145 |
+
time.sleep(2)
|
146 |
+
continue
|
147 |
+
# print("Got response", response_data)
|
148 |
+
if response_data[0]["status"] == 'streaming':
|
149 |
+
break
|
150 |
+
else:
|
151 |
+
time.sleep(2)
|
152 |
+
continue
|
153 |
+
# if time.time() - startTime > 300:
|
154 |
+
# raise Exception("Timeout while waiting for song completion")
|
155 |
+
|
156 |
+
print("Got song", response_data[0]["audio_url"])
|
157 |
+
url = response_data[0]["audio_url"]
|
158 |
+
|
159 |
+
return url, lyrics, concatenated_clips
|
160 |
+
|
161 |
+
|
write_full_song_ex.txt
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Overall song description: the song explores the confusion and pain of questioning whether a relationship is genuine love when words and actions no longer align.
|
2 |
+
Genre: Songwriter Pop
|
3 |
+
Era: 2010s
|
4 |
+
Section Descriptions:
|
5 |
+
[verse 1]: recognizing that despite genuine feelings, the other person has changed and no longer feels the same.
|
6 |
+
[prechorus 1]: acknowledging hurtful actions while seeking clarity about whether the other person intends to leave.
|
7 |
+
[chorus 1]: reiterating doubts about the authenticity of the relationship and wanting answers if love is no longer present.
|
8 |
+
[verse 2]: struggling with the partner's inconsistent behavior and wanting to reclaim one's love after being replaced.
|
9 |
+
[prechorus 1]: acknowledging hurtful actions while seeking clarity about whether the other person intends to leave.
|
10 |
+
[chorus 2]: reiterating doubts about the authenticity of the relationship and wanting answers if love is no longer present.
|
11 |
+
[bridge]: repeatedly asking for clarity and affirming that the current situation does not feel like love.
|
12 |
+
[outro]: questioning the authenticity of the relationship.
|
13 |
+
Sections provided:
|
14 |
+
[Verse 1]
|
15 |
+
I know it's fake to you
|
16 |
+
But it was real to me
|
17 |
+
Tried to stay the same for you
|
18 |
+
But you changed on me
|
19 |
+
|
20 |
+
[PreChrous 1]
|
21 |
+
You said that you never meant to hurt me
|
22 |
+
But baby I know this is how it goes
|
23 |
+
If there is a world where you're not leaving
|
24 |
+
Then darling I need to know
|
25 |
+
|
26 |
+
Lyrics:
|
27 |
+
[Chorus 1]
|
28 |
+
Is this really love?
|
29 |
+
If you don't say the word anymore
|
30 |
+
If I'm not in love
|
31 |
+
Let me know when you find what you're looking for
|
32 |
+
Is this really love?
|
33 |
+
|
34 |
+
[Verse 2]
|
35 |
+
You may have called my bluff
|
36 |
+
But you've been acting up
|
37 |
+
Leaving you ain't enough
|
38 |
+
I just want back my love
|
39 |
+
You got somebody else to take
|
40 |
+
My place and did it the wrong way
|
41 |
+
After all I did for you
|
42 |
+
|
43 |
+
[PreChorus 1]
|
44 |
+
You said that you never meant to hurt me
|
45 |
+
But baby I know this is how it goes
|
46 |
+
If there is a world where you're not leaving
|
47 |
+
Then darling I need to know
|
48 |
+
|
49 |
+
[Chorus 2]
|
50 |
+
Is this really love? (Is this love?)
|
51 |
+
If you don't say the word anymore
|
52 |
+
If I'm not in love
|
53 |
+
Let me know when you find what you're looking for
|
54 |
+
Is this really love
|
write_section_ex.txt
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Ideas to use:
|
2 |
+
- I dream about us, but I wonder why.
|
3 |
+
- I always leave when I try hard to keep together.
|
4 |
+
Section Description: the narrator feels helpless as they dream of being with someone who is constantly leaving while they themselves are trying to hold on.
|
5 |
+
Genre: Songwriter Pop
|
6 |
+
Era: 2010s
|
7 |
+
Overall song description: the song depicts a one-sided relationship where the narrator is trying to hold on while the other person is pulling away.
|
8 |
+
|
9 |
+
Lyrics:
|
10 |
+
I dream about you and I
|
11 |
+
But why do I even try?
|
12 |
+
'Cause you're running away, running away
|
13 |
+
And I'm trying to stay, trying to stay
|