ajayarora1235
commited on
Commit
·
917b084
1
Parent(s):
8b3be6a
beta version, add spaces remote
Browse files- ai_tools.json +97 -11
- app.py +350 -58
- chat.py +329 -84
- data/conversation_history.json +1 -0
- gpt_calls.py +35 -35
- suno.py +57 -4
- utils/song_utils.py +17 -5
ai_tools.json
CHANGED
@@ -50,6 +50,42 @@
|
|
50 |
}
|
51 |
}
|
52 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
{
|
54 |
"type": "function",
|
55 |
"function": {
|
@@ -73,14 +109,6 @@
|
|
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": {
|
@@ -96,7 +124,7 @@
|
|
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"
|
100 |
}
|
101 |
}
|
102 |
},
|
@@ -131,6 +159,64 @@
|
|
131 |
}
|
132 |
}
|
133 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
{
|
135 |
"type": "function",
|
136 |
"function": {
|
@@ -149,7 +235,7 @@
|
|
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"]
|
@@ -208,7 +294,7 @@
|
|
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",
|
|
|
50 |
}
|
51 |
}
|
52 |
},
|
53 |
+
{
|
54 |
+
"type": "function",
|
55 |
+
"function": {
|
56 |
+
"name": "ask_question",
|
57 |
+
"description": "Ask a question to the user to get more information. This function should be called when the AI needs more information about the user to continue writing the song.",
|
58 |
+
"parameters": {
|
59 |
+
"type": "object",
|
60 |
+
"properties": {},
|
61 |
+
"required": []
|
62 |
+
}
|
63 |
+
}
|
64 |
+
},
|
65 |
+
{
|
66 |
+
"type": "function",
|
67 |
+
"function": {
|
68 |
+
"name": "clarify_arguments",
|
69 |
+
"description": "Ask a question to the user to get more information. This function should be called when the AI needs clarification on arguments to pass to a different function call. Should always be called for snippet_clip_to_continue_from in get_audio_snippet and whole_song in revise_instrumental_tags.",
|
70 |
+
"parameters": {
|
71 |
+
"type": "object",
|
72 |
+
"properties": {
|
73 |
+
"function_name": {
|
74 |
+
"type": "string",
|
75 |
+
"description": "Function to call that needs clarification on arguments"
|
76 |
+
},
|
77 |
+
"arguments_to_clarify": {
|
78 |
+
"type": "array",
|
79 |
+
"items": {
|
80 |
+
"type": "string"
|
81 |
+
},
|
82 |
+
"description": "List of questions to ask the end user to clarify the arguments we don't know"
|
83 |
+
}
|
84 |
+
},
|
85 |
+
"required": ["function_name", "arguments_to_clarify"]
|
86 |
+
}
|
87 |
+
}
|
88 |
+
},
|
89 |
{
|
90 |
"type": "function",
|
91 |
"function": {
|
|
|
109 |
},
|
110 |
"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."
|
111 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
"relevant_ideas": {
|
113 |
"type": "array",
|
114 |
"items": {
|
|
|
124 |
"description": "Words that are requested to be included in revised lines. Unless specific words are requested, this should be empty"
|
125 |
}
|
126 |
},
|
127 |
+
"required": ["section_name", "current_section", "lines_to_revise"]
|
128 |
}
|
129 |
}
|
130 |
},
|
|
|
159 |
}
|
160 |
}
|
161 |
},
|
162 |
+
{
|
163 |
+
"type": "function",
|
164 |
+
"function": {
|
165 |
+
"name": "revise_section_lyrics_and_instrumental",
|
166 |
+
"description": "Incorporates simultaneous feedback on lyrics and instrumental from a single user message. Call this when the user either has both feedback on lyric changes and instrumental changes that they ask for in a single message or they ask to regenerate a snippet with both changed lyrics and instrumental tags in mind.",
|
167 |
+
"parameters": {
|
168 |
+
"type": "object",
|
169 |
+
"properties": {
|
170 |
+
"current_instrumental_tags": {
|
171 |
+
"type": "array",
|
172 |
+
"items": {
|
173 |
+
"type": "string"
|
174 |
+
},
|
175 |
+
"description": "Current instrumental tags passed to instrumental generator. Deduce from most recent list of instrumental tags in conversation."
|
176 |
+
},
|
177 |
+
"user_instrumental_feedback": {
|
178 |
+
"type": "string",
|
179 |
+
"description": "A single sentence summary of the user's feedback on instrumental. Can include suggested moods, genres, or instruments."
|
180 |
+
},
|
181 |
+
"section_name": {
|
182 |
+
"type": "string",
|
183 |
+
"description": "Name of section we are revising"
|
184 |
+
},
|
185 |
+
"current_section": {
|
186 |
+
"type": "string",
|
187 |
+
"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."
|
188 |
+
},
|
189 |
+
"lines_to_revise": {
|
190 |
+
"type": "array",
|
191 |
+
"items": {
|
192 |
+
"type": "number"
|
193 |
+
},
|
194 |
+
"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."
|
195 |
+
},
|
196 |
+
"snippet_clip_to_continue_from": {
|
197 |
+
"type": "string",
|
198 |
+
"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 section's snippet's audioplayer; if it is None, this should not be passed."
|
199 |
+
},
|
200 |
+
"relevant_ideas": {
|
201 |
+
"type": "array",
|
202 |
+
"items": {
|
203 |
+
"type": "string"
|
204 |
+
},
|
205 |
+
"description": "Ideas that should be included in the lines that are being changed. Should be directly derived from suggested user changes."
|
206 |
+
},
|
207 |
+
"relevant_words": {
|
208 |
+
"type": "array",
|
209 |
+
"items": {
|
210 |
+
"type": "string"
|
211 |
+
},
|
212 |
+
"description": "Words that are requested to be included in revised lines. Unless specific words are requested, this should be empty"
|
213 |
+
}
|
214 |
+
|
215 |
+
},
|
216 |
+
"required": ["current_instrumental_tags", "user_instrumental_feedback", "section_name", "current_section", "lines_to_revise"]
|
217 |
+
}
|
218 |
+
}
|
219 |
+
},
|
220 |
{
|
221 |
"type": "function",
|
222 |
"function": {
|
|
|
235 |
},
|
236 |
"snippet_clip_to_continue_from": {
|
237 |
"type": "string",
|
238 |
+
"description": "The last approved song clip to continue from. Almost always the most recent clip id outputted in the conversation. This is located in the tool message prior to the assistant message with the audio player for that audio. If user did not receive a snippet for the prior section or ever before, this should not be passed."
|
239 |
}
|
240 |
},
|
241 |
"required": ["snippet_lyrics", "snippet_instrumental_tags"]
|
|
|
294 |
},
|
295 |
"snippet_clip_to_continue_from": {
|
296 |
"type": "string",
|
297 |
+
"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. This is located in the tool message prior to the assistant message with the audio player for that audio. If user did not receive a snippet for the prior section or ever before, this should not be passed."
|
298 |
},
|
299 |
"sections_written": {
|
300 |
"type": "array",
|
app.py
CHANGED
@@ -1,14 +1,27 @@
|
|
1 |
from typing import List, Tuple, Dict
|
2 |
import gradio as gr
|
|
|
|
|
3 |
|
4 |
from utils.song_utils import generate_song_seed, get_starting_messages, messages_to_history, update_song_details, get_sections
|
5 |
from chat import model_chat
|
6 |
-
from
|
7 |
|
8 |
History = List[Tuple[str, str]] # a type: pairs of (query, response), where query is user input and response is system output
|
9 |
Messages = List[Dict[str, str]] # a type: list of messages with role and content
|
10 |
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
gr.Markdown("""<center><font size=8>AI Songwriter (alpha)</center>""")
|
13 |
gr.Markdown("""<center><font size=4>Turning your stories into musical poetry. 2024 MIT Senior Thesis.</center>""")
|
14 |
|
@@ -18,8 +31,7 @@ with gr.Blocks() as demo:
|
|
18 |
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>""")
|
19 |
gr.Markdown("""<center><font size=3>If you're stuck, check out <a href="https://onestopforwriters.com/emotions" target="_blank">here</a>.</font></center>""")
|
20 |
with gr.Row():
|
21 |
-
feeling_input = gr.Textbox(label='
|
22 |
-
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)
|
23 |
# audio_input = gr.Audio(sources=["upload"], type="numpy", label="Instrumental",
|
24 |
# interactive=True, elem_id="instrumental-input")
|
25 |
|
@@ -36,7 +48,9 @@ with gr.Blocks() as demo:
|
|
36 |
title_input = gr.Textbox(label='Title', placeholder='Enter a song title')
|
37 |
genre_input = gr.Textbox(label='Genre', placeholder='Enter a genre')
|
38 |
blurb_input = gr.Textbox(label='Blurb', placeholder='Enter a one-sentence blurb')
|
39 |
-
|
|
|
|
|
40 |
gr.Markdown("""<center><font size=4>Edit these to your liking and hit 'Continue to Next Step' to start creating!</font></center>""")
|
41 |
|
42 |
def open_accordion(x):
|
@@ -52,6 +66,7 @@ with gr.Blocks() as demo:
|
|
52 |
song_seed = song_seed.split("Suggested Song Concept:")[1].strip()
|
53 |
return song_seed
|
54 |
generate_seed_button.click(generate_song_seed, inputs=[feeling_input], outputs=[instrumental_output]).then(clean_song_seed, inputs=[instrumental_output], outputs=[instrumental_output])
|
|
|
55 |
|
56 |
def make_row_visible(x):
|
57 |
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)
|
@@ -66,37 +81,332 @@ with gr.Blocks() as demo:
|
|
66 |
return gr.Tabs(selected=id)
|
67 |
continue_btn.click(change_tab, gr.Number(1, visible=False), tabs)
|
68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
with gr.TabItem("Generation", id=1): #index is 1
|
71 |
start_song_gen = gr.State(value=False)
|
72 |
-
gr.Markdown("""<center><font size=4>Now, chat with an AI songwriter to make your song!
|
73 |
-
|
74 |
-
|
75 |
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")
|
76 |
|
77 |
starting_messages, starting_history = get_starting_messages("", "Home", "Missing home", "Ballad", instrumental_textbox.value)
|
78 |
-
|
79 |
messages = gr.State(value=starting_messages)
|
|
|
80 |
# journal_messages = gr.State(value=[journal_starting_message])
|
81 |
# journal_response = gr.State(value="")
|
82 |
|
|
|
|
|
|
|
83 |
with gr.Row():
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
|
|
|
|
|
|
88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
section_meanings = gr.State(value="")
|
90 |
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])
|
91 |
continue_btn.click(get_starting_messages, inputs=[instrumental_textbox, title_input, blurb_input, genre_input, section_meanings], outputs=[messages, chatbot_history])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
|
93 |
with gr.Row():
|
94 |
-
textbox
|
95 |
-
submit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
with gr.Row():
|
98 |
-
get_snippet_button = gr.Button("Get Audio Snippet", scale=2)
|
99 |
-
done = gr.Button("Finish Full Song 🎶", scale=
|
100 |
#autoGPT_checkbox = gr.Checkbox(label="AutoGPT", value=True, info="Auto-generate responses from journal entry", interactive=True, scale=2)
|
101 |
#journal_llm_creativity = gr.Slider(label="Journal LLM Temperature", minimum=0, maximum=1, step=0.01, value=1, interactive=True, scale=2)
|
102 |
reset_button = gr.Button("Reset", scale=2)
|
@@ -104,57 +414,39 @@ with gr.Blocks() as demo:
|
|
104 |
def reset_chat(messages, chatbot_history):
|
105 |
messages = messages[:2]
|
106 |
chatbot_history = messages_to_history(messages[:2])
|
107 |
-
return messages, chatbot_history, ''
|
108 |
|
109 |
-
reset_button.click(reset_chat, inputs=[messages, chatbot_history], outputs=[messages, chatbot_history,
|
110 |
|
111 |
|
112 |
-
|
113 |
-
|
114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
|
116 |
-
# download_btn = gr.Button("Download Conversation")
|
117 |
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
# with open(f'conversation_{now}.json', 'w') as f:
|
123 |
-
# json.dump(messages, f)
|
124 |
|
125 |
|
126 |
-
|
127 |
-
|
|
|
128 |
# story_textbox = gr.TextArea(label="Story to provide context to songwriter", value="", max_lines=3)
|
129 |
|
|
|
|
|
|
|
|
|
130 |
|
131 |
-
def reset_textbox(textbox):
|
132 |
-
return ""
|
133 |
-
def set_snippet_query(textbox):
|
134 |
-
return "Can I have an audio snippet of what we have now?"
|
135 |
-
def set_finish_query(textbox):
|
136 |
-
return "I'm ready for the full song now! Can you finish it up?"
|
137 |
-
def set_lyrics_song_displays(messages):
|
138 |
-
final_message = messages[-1]['content']
|
139 |
-
final_lyrics = final_message.split("Final Lyrics:")[1].split("Final song:")[0].strip("\n ")
|
140 |
-
song = final_message.split("Final song:")[1].strip("\n ")
|
141 |
-
return final_lyrics, song
|
142 |
-
|
143 |
-
submit.click(model_chat,
|
144 |
-
inputs=[genre_input, textbox, chatbot_history, messages],
|
145 |
-
outputs=[textbox, chatbot_history, messages, lyrics_display]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
146 |
-
textbox.submit(model_chat,
|
147 |
-
inputs=[genre_input, textbox, chatbot_history, messages],
|
148 |
-
outputs=[textbox, chatbot_history, messages, lyrics_display]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
149 |
-
|
150 |
-
get_snippet_button.click(set_snippet_query, inputs=[textbox], outputs=[textbox]).then(model_chat,
|
151 |
-
inputs=[genre_input, textbox, chatbot_history, messages],
|
152 |
-
outputs=[textbox, chatbot_history, messages]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
153 |
-
|
154 |
-
done.click(set_finish_query, inputs=[textbox], outputs=[textbox]).then(model_chat,
|
155 |
-
inputs=[genre_input, textbox, chatbot_history, messages],
|
156 |
-
outputs=[textbox, chatbot_history, messages, lyrics_display]).then(
|
157 |
-
set_lyrics_song_displays, inputs=[messages], outputs=[lyrics_display, song]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
158 |
|
159 |
|
160 |
demo.queue(api_open=False)
|
|
|
1 |
from typing import List, Tuple, Dict
|
2 |
import gradio as gr
|
3 |
+
import os
|
4 |
+
import json
|
5 |
|
6 |
from utils.song_utils import generate_song_seed, get_starting_messages, messages_to_history, update_song_details, get_sections
|
7 |
from chat import model_chat
|
8 |
+
from gradio_modal import Modal
|
9 |
|
10 |
History = List[Tuple[str, str]] # a type: pairs of (query, response), where query is user input and response is system output
|
11 |
Messages = List[Dict[str, str]] # a type: list of messages with role and content
|
12 |
|
13 |
+
css = """
|
14 |
+
#audio-group {
|
15 |
+
max-height: 800px;
|
16 |
+
overflow-y: scroll;
|
17 |
+
}
|
18 |
+
"""
|
19 |
+
|
20 |
+
textbox = gr.Textbox(lines=1, label='Send a message', show_label=False, placeholder='Send a message', scale=4, visible=True)
|
21 |
+
submit = gr.Button("Send", scale=2, visible=True)
|
22 |
+
|
23 |
+
|
24 |
+
with gr.Blocks(css=css) as demo:
|
25 |
gr.Markdown("""<center><font size=8>AI Songwriter (alpha)</center>""")
|
26 |
gr.Markdown("""<center><font size=4>Turning your stories into musical poetry. 2024 MIT Senior Thesis.</center>""")
|
27 |
|
|
|
31 |
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>""")
|
32 |
gr.Markdown("""<center><font size=3>If you're stuck, check out <a href="https://onestopforwriters.com/emotions" target="_blank">here</a>.</font></center>""")
|
33 |
with gr.Row():
|
34 |
+
feeling_input = gr.Textbox(label="What's an emotion(s) that you've been feeling a lot recently? And why?", placeholder='Enter your emotions', scale=2)
|
|
|
35 |
# audio_input = gr.Audio(sources=["upload"], type="numpy", label="Instrumental",
|
36 |
# interactive=True, elem_id="instrumental-input")
|
37 |
|
|
|
48 |
title_input = gr.Textbox(label='Title', placeholder='Enter a song title')
|
49 |
genre_input = gr.Textbox(label='Genre', placeholder='Enter a genre')
|
50 |
blurb_input = gr.Textbox(label='Blurb', placeholder='Enter a one-sentence blurb')
|
51 |
+
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)
|
52 |
+
|
53 |
+
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", visible=False, interactive=True, max_lines=3)
|
54 |
gr.Markdown("""<center><font size=4>Edit these to your liking and hit 'Continue to Next Step' to start creating!</font></center>""")
|
55 |
|
56 |
def open_accordion(x):
|
|
|
66 |
song_seed = song_seed.split("Suggested Song Concept:")[1].strip()
|
67 |
return song_seed
|
68 |
generate_seed_button.click(generate_song_seed, inputs=[feeling_input], outputs=[instrumental_output]).then(clean_song_seed, inputs=[instrumental_output], outputs=[instrumental_output])
|
69 |
+
feeling_input.submit(generate_song_seed, inputs=[feeling_input], outputs=[instrumental_output]).then(clean_song_seed, inputs=[instrumental_output], outputs=[instrumental_output])
|
70 |
|
71 |
def make_row_visible(x):
|
72 |
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)
|
|
|
81 |
return gr.Tabs(selected=id)
|
82 |
continue_btn.click(change_tab, gr.Number(1, visible=False), tabs)
|
83 |
|
84 |
+
# with gr.TabItem("Tutorial", id=1):
|
85 |
+
# gr.Markdown("""<center><font size=4>Now, let's walkthrough writing a verse together! Start chatting with the chatbot.</font></center>""")
|
86 |
+
|
87 |
+
# 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")
|
88 |
+
|
89 |
+
# starting_messages, starting_history = get_starting_messages("", "Home", "Missing home", "Ballad", instrumental_textbox.value)
|
90 |
+
|
91 |
+
# messages = gr.State(value=starting_messages)
|
92 |
+
|
93 |
+
# section_meanings = gr.State(value="")
|
94 |
+
# 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])
|
95 |
+
|
96 |
+
# # lyrics_display = gr.State("")
|
97 |
+
|
98 |
+
# generated_audios = gr.State([])
|
99 |
+
# def reset_textbox(textbox):
|
100 |
+
# return ""
|
101 |
+
|
102 |
+
# 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")
|
103 |
|
104 |
+
# starting_messages, starting_history = get_starting_messages("", "Home", "Missing home", "Ballad", instrumental_textbox.value)
|
105 |
+
# print(starting_history, "STARTING HISTORY")
|
106 |
+
# messages = gr.State(value=starting_messages)
|
107 |
+
# # messages += [{"role": "assistant", "content": "You are a songwriter. You write songs."}]
|
108 |
+
# # journal_messages = gr.State(value=[journal_starting_message])
|
109 |
+
# # journal_response = gr.State(value="")
|
110 |
+
|
111 |
+
# generated_audios = gr.State(value=[])
|
112 |
+
# tutorial_step = gr.Number(0, visible=False)
|
113 |
+
|
114 |
+
# with gr.Row():
|
115 |
+
# with gr.Column(scale=2):
|
116 |
+
# chatbot_history = gr.Chatbot(type="messages", value=starting_history, label='SongChat', placeholder=None, layout='bubble', bubble_full_width=False, height=500)
|
117 |
+
# with gr.Row():
|
118 |
+
# typical_responses = [textbox, submit]
|
119 |
+
|
120 |
+
# def update_response_options(buttons, button_dict):
|
121 |
+
# return [gr.Textbox(visible=len(buttons)==0, scale=4), gr.Button(visible=len(buttons)==0, scale=2)] + [gr.Button(visible=(x in buttons)) for x in button_dict.keys()]
|
122 |
+
|
123 |
+
# button_options = gr.State([])
|
124 |
+
# button_dict = gr.State({
|
125 |
+
# "revise lyrics": "Can we revise the lyrics?",
|
126 |
+
# "generate audio snippet": "Can you generate an audio snippet?",
|
127 |
+
# "continue revising" : "Can we continue revising this section?",
|
128 |
+
# "generate audio snippet with new lyrics": "Can you generate an audio snippet with these new lyrics?",
|
129 |
+
# "return to original instrumental": "Can you use the original clip for this section instead?",
|
130 |
+
# "revise genre": "Can we revise the instrumental tags?",
|
131 |
+
# "re-revise genre": "Can we revise the instrumental tags?",
|
132 |
+
# "continue to next section": "Looks good! Let's move on to the next section.",
|
133 |
+
# "merge snippets": "Can you merge this snippet into its full song?"
|
134 |
+
# })
|
135 |
+
|
136 |
+
# for button in button_dict.value.keys():
|
137 |
+
# btn = gr.Button(button, visible=(button in button_options.value))
|
138 |
+
# typical_responses.append(btn)
|
139 |
+
|
140 |
+
|
141 |
+
# with gr.Column(elem_id="audio-group", scale=1) as audio_group_column:
|
142 |
+
# # songwriter_creativity = gr.Slider(label="Songwriter LLM Temperature", minimum=0, maximum=1, step=0.01, value=1)
|
143 |
+
|
144 |
+
# with gr.Group():
|
145 |
+
# # loop thru all audio in audio_clips
|
146 |
+
# gr.Markdown("""<center><font size=4>All Generations</font></center>""")
|
147 |
+
|
148 |
+
# @gr.render(inputs=generated_audios, triggers=[demo.load, generated_audios.change, textbox.submit, submit.click] + [btn.click for btn in typical_responses[2:]])
|
149 |
+
# def render_audio_group(generated_audios):
|
150 |
+
# # audio_group = gr.Group()
|
151 |
+
# for audio in generated_audios:
|
152 |
+
# clip_path, lyrics, instrumental, title, status = audio
|
153 |
+
# with gr.Accordion(title, open=False):
|
154 |
+
# if status == 'complete':
|
155 |
+
# gr.Audio(value=clip_path, label=title, interactive=False, show_label=False, waveform_options={"show_controls": False})
|
156 |
+
# else:
|
157 |
+
# gr.HTML(f'<audio controls><source src="{clip_path}" type="audio/mp3"></audio>')
|
158 |
+
# gr.TextArea(label="Lyrics", value=lyrics, interactive=False, show_label=False)
|
159 |
+
# gr.TextArea(label="Instrumental", value=instrumental, interactive=False, show_label=False, max_lines=1)
|
160 |
+
|
161 |
+
# gr.Markdown("""<center><font size=4>Current Generation</font></center>""")
|
162 |
+
# current_section = gr.Textbox(label="Current section", value="Verse 1", interactive=False, show_label=True)
|
163 |
+
# current_lyrics = gr.Textbox(label="Lyrics", value="", interactive=True, show_label=True)
|
164 |
+
# with gr.Row():
|
165 |
+
# curr_tags = gr.Textbox(label="Instrumental Tags", value="", interactive=True, show_label=True)
|
166 |
+
# # @gr.render(inputs=generated_audios, triggers=[demo.load])
|
167 |
+
# # def render_clip_to_continue(generated_audios):
|
168 |
+
# audio_clips = [x[3] for x in generated_audios.value]
|
169 |
+
# clip_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=audio_clips+[""], interactive=True)
|
170 |
+
# #clip_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=audio_clips+[""], interactive=True)
|
171 |
+
# songwriter_style = gr.Dropdown(label='Songwriter Style', value= "GPT 4o", choices=["GPT 4o", "d4vd"], interactive=True)
|
172 |
+
# with gr.Row():
|
173 |
+
# #curr_audio = gr.State("")
|
174 |
+
# curr_audio = gr.HTML(label="Generated section")
|
175 |
+
# regen = gr.Button("Re-generate")
|
176 |
+
|
177 |
+
|
178 |
+
# section_meanings = gr.State(value="")
|
179 |
+
# 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])
|
180 |
+
# continue_btn.click(get_starting_messages, inputs=[instrumental_textbox, title_input, blurb_input, genre_input, section_meanings], outputs=[messages, chatbot_history])
|
181 |
+
|
182 |
+
# def set_response_buttons(button_dict, button_name):
|
183 |
+
# print(button_name)
|
184 |
+
# return button_dict[button_name]
|
185 |
+
|
186 |
+
|
187 |
+
# with gr.Row(visible=True) as chat_row_0:
|
188 |
+
# textbox_0 = gr.Textbox(lines=1, label='Send a message', show_label=False, placeholder='Send a message', scale=4)
|
189 |
+
# submit_0 = gr.Button("Send", scale=2)
|
190 |
+
|
191 |
+
# for btn in typical_responses[2:]:
|
192 |
+
# btn.click(set_response_buttons, inputs=[button_dict, btn], outputs=[textbox]).then(model_chat,
|
193 |
+
# inputs=[genre_input, textbox, chatbot_history, messages, generated_audios],
|
194 |
+
# outputs=[textbox, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options]).then(reset_textbox, inputs=[textbox], outputs=[textbox]).then(
|
195 |
+
# update_response_options, [button_options, button_dict], typical_responses
|
196 |
+
# )
|
197 |
+
|
198 |
+
|
199 |
+
|
200 |
+
# with Modal(visible=False) as modal_0:
|
201 |
+
# gr.Markdown("Welcome to the AI songwriter! The AI songwriter will help you write a song. You can chat with the AI, generate lyrics, and listen to audio snippets. Let's start by chatting with the AI.")
|
202 |
+
# with Modal(visible=False) as modal:
|
203 |
+
# gr.Markdown("The chatbot is run by an AI songwriter. It can respond to your conversations, generate lyrics and audio, and edit prior generations.\n\nNow, continue and respond to this second question from the AI songwriter.")
|
204 |
+
# with Modal(visible=False) as modal_1:
|
205 |
+
# gr.Markdown("The AI songwriter has now proposed a first verse! You now have the option to hear an audio snippet, revise the lyrics, or continue to the next section. The latter two options continue the conversation, whereas the first starts audio generation models. Select the 'get audio snippet' button to continue to the next step.")
|
206 |
+
# with Modal(visible=False) as modal_2:
|
207 |
+
# gr.Markdown("Awesome! You generated your first audio snippet./n/n As you work thru each section, the generated snippets are populated on the right panel. You'll be able to listen thru snippets as you work thru the song. \n\n "
|
208 |
+
# "The current section is also displayed on the right panel. You'll be able to revise sections via the chat or directly via the right panel. \n\n "
|
209 |
+
# "You're ready to start your official song! Hit the 'Start' button to start.")
|
210 |
+
# start_button = gr.Button("Start")
|
211 |
+
|
212 |
+
# # start_button.click(change_tab, gr.Number(2, visible=False), tabs).then(update_generation_tab,
|
213 |
+
# # inputs=[],
|
214 |
+
# # outputs=[])
|
215 |
+
# continue_btn.click(lambda: Modal(visible=True), None, modal_0)
|
216 |
+
|
217 |
+
# def make_modal_visible(step_number):
|
218 |
+
# new_step_number = step_number + 1 if step_number in [0, 1, 2] else step_number
|
219 |
+
# modals = [Modal(visible=i == step_number) for i in range(3)]
|
220 |
+
# return new_step_number, *modals
|
221 |
+
|
222 |
+
|
223 |
+
|
224 |
+
|
225 |
+
# submit_0.click(update_textbox, [textbox_0, tutorial_step], [textbox_0]).then(model_chat,
|
226 |
+
# inputs=[genre_input, textbox_0, chatbot_history, messages, generated_audios],
|
227 |
+
# outputs=[textbox_0, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options]).then(reset_textbox, inputs=[textbox_0], outputs=[textbox_0]).then(
|
228 |
+
# update_response_options, [button_options, button_dict], typical_responses
|
229 |
+
# ).then(
|
230 |
+
# make_modal_visible, [tutorial_step], [tutorial_step, modal, modal_1, modal_2]
|
231 |
+
# )
|
232 |
+
# textbox_0.submit(update_textbox, [textbox_0, tutorial_step], [textbox_0]).then(model_chat,
|
233 |
+
# inputs=[genre_input, textbox_0, chatbot_history, messages, generated_audios],
|
234 |
+
# outputs=[textbox_0, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options]).then(reset_textbox, inputs=[textbox_0], outputs=[textbox_0]).then(
|
235 |
+
# update_response_options, [button_options, button_dict], typical_responses
|
236 |
+
# ).then(
|
237 |
+
# make_modal_visible, [tutorial_step], [tutorial_step, modal, modal_1, modal_2]
|
238 |
+
# )
|
239 |
+
|
240 |
+
|
241 |
+
|
242 |
with gr.TabItem("Generation", id=1): #index is 1
|
243 |
start_song_gen = gr.State(value=False)
|
244 |
+
gr.Markdown("""<center><font size=4>Now, chat with an AI songwriter to make your song! Hit finish when ready to hear full song.</font></center>""")
|
245 |
+
|
|
|
246 |
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")
|
247 |
|
248 |
starting_messages, starting_history = get_starting_messages("", "Home", "Missing home", "Ballad", instrumental_textbox.value)
|
249 |
+
print(starting_history, "STARTING HISTORY")
|
250 |
messages = gr.State(value=starting_messages)
|
251 |
+
# messages += [{"role": "assistant", "content": "You are a songwriter. You write songs."}]
|
252 |
# journal_messages = gr.State(value=[journal_starting_message])
|
253 |
# journal_response = gr.State(value="")
|
254 |
|
255 |
+
generated_audios = gr.State(value=[])
|
256 |
+
tutorial_step = gr.Number(value=0, visible=False)
|
257 |
+
|
258 |
with gr.Row():
|
259 |
+
with gr.Column(scale=2):
|
260 |
+
chatbot_history = gr.Chatbot(type="messages", value=starting_history, label='SongChat', placeholder=None, layout='bubble', bubble_full_width=False, height=500)
|
261 |
+
with gr.Row():
|
262 |
+
typical_responses = [textbox, submit]
|
263 |
+
|
264 |
+
def update_response_options(buttons, button_dict):
|
265 |
+
return [gr.Textbox(visible=len(buttons)==0, scale=4), gr.Button(visible=len(buttons)==0, scale=2)] + [gr.Button(visible=(x in buttons)) for x in button_dict.keys()]
|
266 |
|
267 |
+
button_options = gr.State([])
|
268 |
+
button_dict = gr.State({
|
269 |
+
"revise lyrics": "Can we revise the lyrics?",
|
270 |
+
"generate audio snippet": "Can you generate an audio snippet?",
|
271 |
+
"continue revising" : "Can we continue revising this section?",
|
272 |
+
"generate audio snippet with new lyrics": "Can you generate an audio snippet with these new lyrics?",
|
273 |
+
"return to original instrumental": "Can you use the original clip for this section instead?",
|
274 |
+
"revise genre": "Can we revise the instrumental tags?",
|
275 |
+
"re-revise genre": "Can we revise the instrumental tags?",
|
276 |
+
"continue to next section": "Looks good! Let's move on to the next section.",
|
277 |
+
"merge snippets": "Can you merge this snippet into its full song?"
|
278 |
+
})
|
279 |
+
|
280 |
+
for button in button_dict.value.keys():
|
281 |
+
btn = gr.Button(button, visible=(button in button_options.value))
|
282 |
+
typical_responses.append(btn)
|
283 |
+
|
284 |
+
|
285 |
+
with gr.Column(elem_id="audio-group", scale=1):
|
286 |
+
# songwriter_creativity = gr.Slider(label="Songwriter LLM Temperature", minimum=0, maximum=1, step=0.01, value=1)
|
287 |
+
|
288 |
+
with gr.Group():
|
289 |
+
# loop thru all audio in audio_clips
|
290 |
+
gr.Markdown("""<center><font size=4>All Generations</font></center>""")
|
291 |
+
|
292 |
+
@gr.render(inputs=generated_audios, triggers=[demo.load, generated_audios.change, textbox.submit, submit.click] + [btn.click for btn in typical_responses[2:]])
|
293 |
+
def render_audio_group(generated_audios):
|
294 |
+
# audio_group = gr.Group()
|
295 |
+
for audio in generated_audios:
|
296 |
+
clip_path, lyrics, instrumental, title, status = audio
|
297 |
+
with gr.Accordion(title, open=False):
|
298 |
+
if status == 'complete':
|
299 |
+
gr.Audio(value=clip_path, label=title, interactive=False, show_label=False, waveform_options={"show_controls": False})
|
300 |
+
else:
|
301 |
+
gr.HTML(f'<audio controls><source src="{clip_path}" type="audio/mp3"></audio>')
|
302 |
+
gr.TextArea(label="Lyrics", value=lyrics, interactive=False, show_label=False)
|
303 |
+
gr.TextArea(label="Instrumental", value=instrumental, interactive=False, show_label=False, max_lines=1)
|
304 |
+
|
305 |
+
gr.Markdown("""<center><font size=4>Current Generation</font></center>""")
|
306 |
+
current_section = gr.Textbox(label="Current section", value="Verse 1", interactive=False, show_label=True)
|
307 |
+
current_lyrics = gr.Textbox(label="Lyrics", value="", interactive=True, show_label=True)
|
308 |
+
with gr.Row():
|
309 |
+
curr_tags = gr.Textbox(label="Instrumental Tags", value="", interactive=True, show_label=True)
|
310 |
+
# @gr.render(inputs=generated_audios, triggers=[demo.load])
|
311 |
+
# def render_clip_to_continue(generated_audios):
|
312 |
+
audio_clips = [x[3] for x in generated_audios.value]
|
313 |
+
clip_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=audio_clips+[""], interactive=True)
|
314 |
+
#clip_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=audio_clips+[""], interactive=True)
|
315 |
+
songwriter_style = gr.Dropdown(label='Songwriter Style', value= "GPT 4o", choices=["GPT 4o", "d4vd"], interactive=True)
|
316 |
+
with gr.Row():
|
317 |
+
#curr_audio = gr.State("")
|
318 |
+
curr_audio = gr.HTML(label="Generated section")
|
319 |
+
regen = gr.Button("Re-generate")
|
320 |
+
|
321 |
+
|
322 |
section_meanings = gr.State(value="")
|
323 |
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])
|
324 |
continue_btn.click(get_starting_messages, inputs=[instrumental_textbox, title_input, blurb_input, genre_input, section_meanings], outputs=[messages, chatbot_history])
|
325 |
+
|
326 |
+
with Modal(visible=False) as modal_0:
|
327 |
+
gr.Markdown("Welcome to the AI songwriter! The AI songwriter will help you write a song. You can chat with the AI, generate lyrics, and listen to audio snippets. Let's start by chatting with the AI.")
|
328 |
+
with Modal(visible=False) as modal:
|
329 |
+
gr.Markdown("The chatbot is run by an AI songwriter. It can respond to your conversations, generate lyrics and audio, and edit prior generations.\n\nNow, continue and respond to this second question from the AI songwriter.")
|
330 |
+
with Modal(visible=False) as modal_1:
|
331 |
+
gr.Markdown("The AI songwriter has now proposed a first verse! You now have the option to hear an audio snippet, revise the lyrics, or continue to the next section. The latter two options continue the conversation, whereas the first starts audio generation models. Select the 'get audio snippet' button to continue to the next step.")
|
332 |
+
with Modal(visible=False) as modal_2:
|
333 |
+
gr.Markdown("Awesome! You generated your first audio snippet./n/n As you work thru each section, the generated snippets are populated on the right panel. You'll be able to listen thru snippets as you work thru the song. \n\n "
|
334 |
+
"The current section is also displayed on the right panel. You'll be able to revise sections via the chat or directly via the right panel. \n\n "
|
335 |
+
"You're ready to start your official song! Hit the 'Start' button to start.")
|
336 |
+
start_button = gr.Button("Start")
|
337 |
+
|
338 |
+
continue_btn.click(lambda: Modal(visible=True), None, modal_0)
|
339 |
+
start_button.click(lambda: Modal(visible=False), None, modal_2)
|
340 |
+
|
341 |
+
def make_modal_visible(step_number):
|
342 |
+
new_step_number = step_number + 1 if step_number in [0, 1, 2] else step_number
|
343 |
+
modals = [Modal(visible=i == step_number) for i in range(3)]
|
344 |
+
return new_step_number, *modals
|
345 |
+
|
346 |
+
def update_textbox(textbox, step_number):
|
347 |
+
if step_number == 0:
|
348 |
+
return textbox + "\nAsk me another question to inform the verse"
|
349 |
+
elif step_number == 1:
|
350 |
+
return textbox + "\nUse this info to write a verse"
|
351 |
+
else:
|
352 |
+
return textbox
|
353 |
+
|
354 |
+
def set_response_buttons(button_dict, button_name):
|
355 |
+
print(button_name)
|
356 |
+
return button_dict[button_name]
|
357 |
+
|
358 |
+
def set_regenerate_query(textbox, current_section, current_lyrics, curr_tags, clip_to_continue):
|
359 |
+
return f"Can you revise this section so it uses these lyrics and instrumentals and then generate an audio snippet using it?\nLyrics:\n{current_lyrics}Instrumental tags: {curr_tags}\nClip to continue: {clip_to_continue}"
|
360 |
+
def set_snippet_query(textbox):
|
361 |
+
return "Can I have an audio snippet of what we have now?"
|
362 |
+
def set_finish_query(textbox):
|
363 |
+
return "I'm ready for the full song now! Can you finish it up?"
|
364 |
+
def reset_textbox(textbox):
|
365 |
+
return ""
|
366 |
|
367 |
with gr.Row():
|
368 |
+
textbox.render()
|
369 |
+
submit.render()
|
370 |
+
|
371 |
+
for btn in typical_responses[2:]:
|
372 |
+
btn.click(set_response_buttons, inputs=[button_dict, btn], outputs=[textbox]).then(model_chat,
|
373 |
+
inputs=[genre_input, textbox, chatbot_history, messages, generated_audios],
|
374 |
+
outputs=[textbox, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options]).then(reset_textbox, inputs=[textbox], outputs=[textbox]).then(
|
375 |
+
update_response_options, [button_options, button_dict], typical_responses
|
376 |
+
).then(
|
377 |
+
make_modal_visible, [tutorial_step], [tutorial_step, modal, modal_1, modal_2]
|
378 |
+
)
|
379 |
+
|
380 |
+
|
381 |
+
|
382 |
+
|
383 |
+
submit.click(update_textbox, [textbox, tutorial_step], [textbox]).then(model_chat,
|
384 |
+
inputs=[genre_input, textbox, chatbot_history, messages, generated_audios],
|
385 |
+
outputs=[textbox, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options]).then(reset_textbox, inputs=[textbox], outputs=[textbox]).then(
|
386 |
+
update_response_options, [button_options, button_dict], typical_responses
|
387 |
+
).then(
|
388 |
+
make_modal_visible, [tutorial_step], [tutorial_step, modal, modal_1, modal_2]
|
389 |
+
)
|
390 |
+
textbox.submit(update_textbox, [textbox, tutorial_step], [textbox]).then(model_chat,
|
391 |
+
inputs=[genre_input, textbox, chatbot_history, messages, generated_audios],
|
392 |
+
outputs=[textbox, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options]).then(reset_textbox, inputs=[textbox], outputs=[textbox]).then(
|
393 |
+
update_response_options, [button_options, button_dict], typical_responses
|
394 |
+
).then(
|
395 |
+
make_modal_visible, [tutorial_step], [tutorial_step, modal, modal_1, modal_2]
|
396 |
+
)
|
397 |
+
|
398 |
+
|
399 |
+
regen.click(set_regenerate_query, inputs=[textbox, current_section, current_lyrics, curr_tags, clip_to_continue], outputs=[textbox]).then(model_chat,
|
400 |
+
inputs=[genre_input, textbox, chatbot_history, messages, generated_audios],
|
401 |
+
outputs=[textbox, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options]).then(reset_textbox, inputs=[textbox], outputs=[textbox]).then(
|
402 |
+
update_response_options, [button_options, button_dict], typical_responses
|
403 |
+
).then(
|
404 |
+
make_modal_visible, [tutorial_step], [tutorial_step, modal, modal_1, modal_2]
|
405 |
+
)
|
406 |
|
407 |
with gr.Row():
|
408 |
+
# get_snippet_button = gr.Button("Get Audio Snippet", scale=2)
|
409 |
+
done = gr.Button("Finish Full Song 🎶", scale=4)
|
410 |
#autoGPT_checkbox = gr.Checkbox(label="AutoGPT", value=True, info="Auto-generate responses from journal entry", interactive=True, scale=2)
|
411 |
#journal_llm_creativity = gr.Slider(label="Journal LLM Temperature", minimum=0, maximum=1, step=0.01, value=1, interactive=True, scale=2)
|
412 |
reset_button = gr.Button("Reset", scale=2)
|
|
|
414 |
def reset_chat(messages, chatbot_history):
|
415 |
messages = messages[:2]
|
416 |
chatbot_history = messages_to_history(messages[:2])
|
417 |
+
return messages, chatbot_history, '', '', '', '', gr.HTML('<center>generating...</center>'), [], []
|
418 |
|
419 |
+
reset_button.click(reset_chat, inputs=[messages, chatbot_history], outputs=[messages, chatbot_history, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options])
|
420 |
|
421 |
|
422 |
+
done.click(set_finish_query, inputs=[textbox], outputs=[textbox]).then(model_chat,
|
423 |
+
inputs=[genre_input, textbox, chatbot_history, messages, generated_audios],
|
424 |
+
outputs=[textbox, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios, button_options])
|
425 |
+
|
426 |
+
demo.load(reset_chat, inputs=[messages, chatbot_history], outputs=[messages, chatbot_history, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios])
|
427 |
+
|
428 |
+
|
429 |
+
# with gr.Row():
|
430 |
+
# song_link = gr.State(value="")
|
431 |
+
# song = gr.HTML()
|
432 |
|
|
|
433 |
|
434 |
+
|
435 |
+
def download_conversation(messages):
|
436 |
+
with open(f'data/conversation_history.json', 'w') as f:
|
437 |
+
json.dump(messages, f)
|
|
|
|
|
438 |
|
439 |
|
440 |
+
with gr.Accordion("Admin", open=False):
|
441 |
+
download_btn = gr.Button("Download Conversation")
|
442 |
+
download_btn.click(download_conversation, [messages], None)
|
443 |
# story_textbox = gr.TextArea(label="Story to provide context to songwriter", value="", max_lines=3)
|
444 |
|
445 |
+
|
446 |
+
# get_snippet_button.click(set_snippet_query, inputs=[textbox], outputs=[textbox]).then(model_chat,
|
447 |
+
# inputs=[genre_input, textbox, chatbot_history, messages, generated_audios],
|
448 |
+
# outputs=[textbox, chatbot_history, messages, current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio, generated_audios]).then(reset_textbox, inputs=[textbox], outputs=[textbox])
|
449 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
450 |
|
451 |
|
452 |
demo.queue(api_open=False)
|
chat.py
CHANGED
@@ -2,8 +2,17 @@ from typing import List, Optional, Tuple, Dict
|
|
2 |
import os
|
3 |
import json
|
4 |
from openai import OpenAI
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
-
|
|
|
|
|
|
|
7 |
from gpt_calls import AI_Songwriter
|
8 |
from utils.song_utils import messages_to_history
|
9 |
|
@@ -11,17 +20,21 @@ History = List[Tuple[str, str]] # a type: pairs of (query, response), where quer
|
|
11 |
Messages = List[Dict[str, str]] # a type: list of messages with role and content
|
12 |
|
13 |
client_key = os.getenv("OPEN_AI_KEY")
|
|
|
14 |
oai_client = OpenAI(
|
15 |
api_key=client_key,
|
16 |
)
|
17 |
|
18 |
-
def
|
19 |
-
|
20 |
-
|
|
|
|
|
21 |
|
22 |
-
if not query.endswith('?'):
|
23 |
-
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."
|
24 |
|
|
|
|
|
|
|
25 |
with open('ai_tools.json') as f:
|
26 |
ai_tools = json.load(f)
|
27 |
|
@@ -32,14 +45,13 @@ def model_chat(genre_input, query: Optional[str], history: Optional[History], me
|
|
32 |
else:
|
33 |
messages = messages + [{'role': 'user', 'content': query}]
|
34 |
|
35 |
-
|
36 |
|
37 |
messages_filtered = messages
|
38 |
response_message = oai_client.chat.completions.create(
|
39 |
model="gpt-4o",
|
40 |
messages=messages_filtered,
|
41 |
tools = ai_tools,
|
42 |
-
tool_choice="
|
43 |
)
|
44 |
print(response_message, "model chat response")
|
45 |
current_response = ""
|
@@ -52,18 +64,124 @@ def model_chat(genre_input, query: Optional[str], history: Optional[History], me
|
|
52 |
"tool_calls": tool_calls,
|
53 |
"function_call": response_message.choices[0].message.function_call
|
54 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
# If true the model will return the name of the tool / function to call and the argument(s)
|
56 |
for tool_call in tool_calls:
|
57 |
print(tool_call)
|
58 |
tool_call_id = tool_call.id
|
59 |
tool_function_name = tool_call.function.name
|
60 |
tool_query_args = eval(tool_call.function.arguments)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
|
62 |
-
|
63 |
-
if tool_function_name == 'write_section':
|
64 |
snippet_instrumental_tags = tool_query_args.pop('snippet_instrumental_tags', None)
|
65 |
snippet_clip_to_continue_from = tool_query_args.pop('snippet_clip_to_continue_from', None)
|
66 |
suggested_lyrics = songwriterAssistant.write_section(**tool_query_args)
|
|
|
67 |
|
68 |
## yield suggested lyrics in tool and assistant message
|
69 |
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': suggested_lyrics}
|
@@ -77,35 +195,36 @@ def model_chat(genre_input, query: Optional[str], history: Optional[History], me
|
|
77 |
current_response = model_response_with_function_call.choices[0].message.content
|
78 |
|
79 |
role = "assistant"
|
80 |
-
new_messages = new_messages + [{'role': role, 'content': current_response}]
|
81 |
# new_messages = [msg for msg in new_messages if msg['content'] is not None and msg['role'] in ['user', 'assistant']]
|
82 |
history = messages_to_history(new_messages)
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
|
86 |
-
# new_history = messages_to_history(new_messages)
|
87 |
-
# yield '', new_history, new_messages, '[...]'
|
88 |
|
89 |
-
|
90 |
-
# song_link = make_song(suggested_lyrics, snippet_instrumental_tags, snippet_clip_to_continue)
|
91 |
|
92 |
-
|
93 |
-
# clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
94 |
|
95 |
-
# ## add song link to tool and audio message
|
96 |
-
# tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': suggested_lyrics + '\nclip id: ' + clip_id}
|
97 |
-
# 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>'}
|
98 |
-
# audio_message['content'] += f'<p>continued from clip: {snippet_clip_to_continue}</p>'
|
99 |
-
# audio_message['content'] += f'\n\nWhat do you think?'
|
100 |
-
# new_messages = messages + [tool_message, audio_message]
|
101 |
-
# new_history = messages_to_history(new_messages)
|
102 |
-
# yield '', new_history, new_messages, '[...]'
|
103 |
|
104 |
elif tool_function_name == 'revise_section_lyrics':
|
105 |
-
snippet_instrumental_tags = tool_query_args.pop('snippet_instrumental_tags', None)
|
106 |
-
snippet_clip_to_continue_from = tool_query_args.pop('snippet_clip_to_continue_from', None)
|
107 |
revised_lyrics = songwriterAssistant.revise_section_lyrics(**tool_query_args)
|
108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
# ## yield revised lyrics in tool and assistant message
|
110 |
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': revised_lyrics}
|
111 |
# audio_message = {'role': 'assistant', 'content': "Here's my revised lyrics:\n" + revised_lyrics + "\n\nGenerating audio snippet..."}
|
@@ -117,45 +236,36 @@ def model_chat(genre_input, query: Optional[str], history: Optional[History], me
|
|
117 |
) # get a new response from the model where it can see the function response
|
118 |
current_response = model_response_with_function_call.choices[0].message.content
|
119 |
|
|
|
|
|
120 |
role = "assistant"
|
121 |
-
new_messages = new_messages + [{'role': role, 'content': current_response}]
|
122 |
# new_messages = [msg for msg in new_messages if msg['content'] is not None and msg['role'] in ['user', 'assistant']]
|
123 |
history = messages_to_history(new_messages)
|
124 |
-
|
125 |
-
|
126 |
-
# yield '', new_history, new_messages, '[...]'
|
127 |
-
|
128 |
-
# ### call make_song here with the snippet_lyrics, snippet_instrumental_tags, and snippet_clip_to_continue
|
129 |
-
# song_link = make_song(revised_lyrics, snippet_instrumental_tags, snippet_clip_to_continue)
|
130 |
|
131 |
-
|
132 |
-
# clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
133 |
|
134 |
-
# ## add song link to tool and audio message
|
135 |
-
# tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': revised_lyrics + '\nclip id: ' + clip_id}
|
136 |
-
# 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>'}
|
137 |
-
# audio_message['content'] += f'<p>continued from clip: {snippet_clip_to_continue}</p>'
|
138 |
-
# audio_message['content'] += f'\n\nWhat do you think?'
|
139 |
-
# new_messages = messages + [tool_message, audio_message]
|
140 |
-
# new_history = messages_to_history(new_messages)
|
141 |
-
# yield '', new_history, new_messages, '[...]'
|
142 |
|
143 |
elif tool_function_name == 'revise_instrumental_tags':
|
144 |
#detangle tool_query_args dict
|
145 |
#snippet_lyrics = tool_query_args['snippet_lyrics'] + "\n[End]"
|
146 |
-
snippet_instrumental_tags = tool_query_args
|
147 |
-
user_instrumental_feedback = tool_query_args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
# if 'snippet_clip_to_continue_from' not in tool_query_args:
|
149 |
# tool_query_args['snippet_clip_to_continue_from'] = None
|
150 |
# snippet_clip_to_continue_from = tool_query_args['snippet_clip_to_continue_from']
|
151 |
|
152 |
new_instrumental_tags = songwriterAssistant.revise_instrumental_tags(snippet_instrumental_tags, user_instrumental_feedback)
|
153 |
-
# yield new_instrumental_tags in tool and assistant message
|
154 |
-
# tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'new instrumental tags: {new_instrumental_tags}'}
|
155 |
-
# audio_message = {'role': 'assistant', 'content': f'Sure! I\'ve revised the instrumental tags: {new_instrumental_tags}\n\n Generating audio snippet...'}
|
156 |
-
# new_messages = messages + [tool_message, audio_message]
|
157 |
-
# new_history = messages_to_history(new_messages)
|
158 |
-
# yield '', new_history, new_messages, '[...]'
|
159 |
|
160 |
if isinstance(tool_query_args['sections_written'], str):
|
161 |
current_lyrics = tool_query_args['sections_written']
|
@@ -164,28 +274,116 @@ def model_chat(genre_input, query: Optional[str], history: Optional[History], me
|
|
164 |
else:
|
165 |
current_lyrics = ""
|
166 |
|
|
|
|
|
|
|
167 |
#current_lyrics = "\n".join(tool_query_args['sections_written'])
|
168 |
song_link = make_song(current_lyrics, new_instrumental_tags)
|
169 |
## filter out suno link from tool query arg
|
|
|
|
|
|
|
|
|
|
|
170 |
clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
171 |
|
172 |
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}'}
|
173 |
-
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
|
174 |
audio_message['content'] += f'\n\nWhat do you think?'
|
175 |
new_messages = messages + [tool_message, audio_message]
|
176 |
new_history = messages_to_history(new_messages)
|
177 |
-
yield '', new_history, new_messages, '[...]'
|
178 |
-
elif tool_function_name == 'merge_all_snippets':
|
179 |
-
updated_clip_url, updated_lyrics, clips_list = concat_snippets(tool_query_args['last_snippet_id'])
|
180 |
-
updated_clip_id = updated_clip_url.split("https://audiopipe.suno.ai/?item_id=")[1]
|
181 |
|
182 |
-
#
|
183 |
-
|
184 |
-
|
|
|
|
|
|
|
185 |
|
186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
new_history = messages_to_history(new_messages)
|
188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
elif tool_function_name == 'finish_full_song':
|
190 |
## args are sections_to_be_written, relevant_ideas, last_snippet_id, sni
|
191 |
|
@@ -203,7 +401,10 @@ def model_chat(genre_input, query: Optional[str], history: Optional[History], me
|
|
203 |
## STEP 1: WRITE ALL LYRICS using songwriterAssistant
|
204 |
remaining_lyrics = songwriterAssistant.write_all_lyrics(**tool_query_args)
|
205 |
full_lyrics = current_lyrics + remaining_lyrics + "\n[End]"
|
206 |
-
|
|
|
|
|
|
|
207 |
|
208 |
## STEP 2: MAKE SONG FOR REMAINING LYRICS
|
209 |
song_link = make_song(remaining_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from)
|
@@ -214,11 +415,15 @@ def model_chat(genre_input, query: Optional[str], history: Optional[History], me
|
|
214 |
|
215 |
new_messages = messages + [tool_message, audio_message]
|
216 |
new_history = messages_to_history(new_messages)
|
217 |
-
|
|
|
|
|
218 |
|
219 |
## STEP 3: MERGE FULL SONG
|
220 |
if snippet_clip_to_continue_from not in [None, ""]:
|
221 |
-
updated_clip_url
|
|
|
|
|
222 |
else:
|
223 |
updated_clip_url, updated_lyrics, clips_list = song_link, remaining_lyrics, []
|
224 |
## YIELD UPDATED CLIP URL, LYRICS, AND CLIPS LIST
|
@@ -226,42 +431,82 @@ def model_chat(genre_input, query: Optional[str], history: Optional[History], me
|
|
226 |
|
227 |
#tool and assistant message
|
228 |
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}'}
|
229 |
-
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
|
230 |
|
231 |
new_messages = messages + [tool_message, audio_message]
|
232 |
new_history = messages_to_history(new_messages)
|
233 |
-
|
|
|
|
|
|
|
|
|
234 |
|
235 |
elif tool_function_name == 'get_audio_snippet':
|
236 |
#detangle tool_query_args dict
|
237 |
snippet_lyrics = tool_query_args['snippet_lyrics'] + "\n[End]"
|
238 |
snippet_instrumental_tags = tool_query_args['snippet_instrumental_tags']
|
239 |
-
|
240 |
-
|
241 |
-
snippet_clip_to_continue_from = tool_query_args['snippet_clip_to_continue_from']
|
242 |
song_link = make_song(snippet_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
## filter out suno link from tool query arg
|
244 |
clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
245 |
|
246 |
-
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'
|
247 |
-
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
|
248 |
audio_message_content += f'<p>continued from clip: {snippet_clip_to_continue_from}</p>'
|
|
|
249 |
audio_message = {'role': 'assistant', 'content': audio_message_content}
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
new_messages = messages + [tool_message, audio_message]
|
251 |
new_history = messages_to_history(new_messages)
|
252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
else:
|
254 |
print(f"Error: function {tool_function_name} does not exist")
|
255 |
-
|
256 |
-
# messages.append({
|
257 |
-
# "role":"tool",
|
258 |
-
# "tool_call_id":tool_call_id,
|
259 |
-
# "name": tool_function_name,
|
260 |
-
# "content":results
|
261 |
-
# })
|
262 |
-
|
263 |
-
# Step 4: Invoke the chat completions API with the function response appended to the messages list
|
264 |
-
# Note that messages with role 'tool' must be a response to a preceding message with 'tool_calls'
|
265 |
|
266 |
else:
|
267 |
# Model did not identify a function to call, result can be returned to the user
|
|
|
2 |
import os
|
3 |
import json
|
4 |
from openai import OpenAI
|
5 |
+
from dotenv import load_dotenv
|
6 |
+
import asyncio
|
7 |
+
import regex as re
|
8 |
+
from gradio_modal import Modal
|
9 |
+
import gradio as gr
|
10 |
+
import time
|
11 |
|
12 |
+
# Load environment variables from .env file
|
13 |
+
load_dotenv()
|
14 |
+
|
15 |
+
from suno import make_song, concat_snippets, update_song_links
|
16 |
from gpt_calls import AI_Songwriter
|
17 |
from utils.song_utils import messages_to_history
|
18 |
|
|
|
20 |
Messages = List[Dict[str, str]] # a type: list of messages with role and content
|
21 |
|
22 |
client_key = os.getenv("OPEN_AI_KEY")
|
23 |
+
print(client_key)
|
24 |
oai_client = OpenAI(
|
25 |
api_key=client_key,
|
26 |
)
|
27 |
|
28 |
+
def determine_title(section_name, generated_audios):
|
29 |
+
count = sum(1 for audio in generated_audios if audio[2].startswith(section_name))
|
30 |
+
if count > 0:
|
31 |
+
section_name = f"{section_name} {count + 1}"
|
32 |
+
return section_name
|
33 |
|
|
|
|
|
34 |
|
35 |
+
def model_chat(genre_input, query: Optional[str], history: Optional[History], messages: Optional[Messages], generated_audios: List[Tuple[str, str, str]], auto=False) -> Tuple[str, History, Messages, str, str, str, str, str, List]:
|
36 |
+
if query is None:
|
37 |
+
query = ''
|
38 |
with open('ai_tools.json') as f:
|
39 |
ai_tools = json.load(f)
|
40 |
|
|
|
45 |
else:
|
46 |
messages = messages + [{'role': 'user', 'content': query}]
|
47 |
|
|
|
48 |
|
49 |
messages_filtered = messages
|
50 |
response_message = oai_client.chat.completions.create(
|
51 |
model="gpt-4o",
|
52 |
messages=messages_filtered,
|
53 |
tools = ai_tools,
|
54 |
+
tool_choice="required",
|
55 |
)
|
56 |
print(response_message, "model chat response")
|
57 |
current_response = ""
|
|
|
64 |
"tool_calls": tool_calls,
|
65 |
"function_call": response_message.choices[0].message.function_call
|
66 |
})
|
67 |
+
|
68 |
+
if len(tool_calls) > 1:
|
69 |
+
for tool_call in tool_calls:
|
70 |
+
tool_message = {
|
71 |
+
'role': 'tool',
|
72 |
+
'tool_call_id': tool_call.id,
|
73 |
+
'name': tool_call.function.name,
|
74 |
+
'content': "You called two different functions when you can only call one at a time. Did you mean to call revise_section_lyrics_and_instrumental but instead had two different calls for lyrics and instrumental? Communicate this failure to the user and clarify what they are asking for, then only call one tool next time."
|
75 |
+
}
|
76 |
+
messages.append(tool_message)
|
77 |
+
|
78 |
+
# Generate a response using GPT-4o and add it as a message
|
79 |
+
model_response_with_function_call = oai_client.chat.completions.create(
|
80 |
+
model="gpt-4o",
|
81 |
+
messages=messages,
|
82 |
+
)
|
83 |
+
current_response = model_response_with_function_call.choices[0].message.content
|
84 |
+
|
85 |
+
role = "assistant"
|
86 |
+
messages.append({'role': role, 'content': current_response})
|
87 |
+
|
88 |
+
yield '', messages_to_history(messages), messages, '', '', '', '', None, generated_audios, []
|
89 |
+
return
|
90 |
+
|
91 |
+
|
92 |
# If true the model will return the name of the tool / function to call and the argument(s)
|
93 |
for tool_call in tool_calls:
|
94 |
print(tool_call)
|
95 |
tool_call_id = tool_call.id
|
96 |
tool_function_name = tool_call.function.name
|
97 |
tool_query_args = eval(tool_call.function.arguments)
|
98 |
+
|
99 |
+
print(tool_function_name, tool_query_args)
|
100 |
+
|
101 |
+
with open('ai_tools.json') as f:
|
102 |
+
ai_tools = json.load(f)
|
103 |
+
|
104 |
+
for tool in ai_tools:
|
105 |
+
if tool['function']['name'] == tool_function_name:
|
106 |
+
valid_keys = tool['function']['parameters']['properties'].keys()
|
107 |
+
required_keys = tool['function']['parameters']['required']
|
108 |
+
break
|
109 |
+
|
110 |
+
print('query args before', tool_query_args)
|
111 |
+
tool_query_args = {k: v for k, v in tool_query_args.items() if k in valid_keys}
|
112 |
+
print('query args after', tool_query_args)
|
113 |
+
missing_keys = []
|
114 |
+
for key in required_keys:
|
115 |
+
if key not in tool_query_args:
|
116 |
+
missing_keys.append(key)
|
117 |
+
if len(missing_keys)>0:
|
118 |
+
missing_keys_str = ", ".join(missing_keys)
|
119 |
+
tool_message = {
|
120 |
+
'role': 'tool',
|
121 |
+
'tool_call_id': tool_call_id,
|
122 |
+
'name': tool_function_name,
|
123 |
+
'content': f"Sorry, the keys {missing_keys_str} from the function you called are missing, communicate this to the user and either get what these args should be or figure out which function to call."
|
124 |
+
}
|
125 |
+
|
126 |
+
new_messages = messages + [tool_message]
|
127 |
+
|
128 |
+
model_response_with_function_call = oai_client.chat.completions.create(
|
129 |
+
model="gpt-4o",
|
130 |
+
messages=new_messages,
|
131 |
+
) # get a new response from the model where it can see the function response
|
132 |
+
current_response = model_response_with_function_call.choices[0].message.content
|
133 |
+
|
134 |
+
role = "assistant"
|
135 |
+
new_messages = new_messages + [{'role': role, 'content': current_response}]
|
136 |
+
new_history = messages_to_history(new_messages)
|
137 |
+
|
138 |
+
generated_audios = update_song_links(generated_audios)
|
139 |
+
yield '', new_history, new_messages, '', '', '', '', None, generated_audios, []
|
140 |
+
|
141 |
+
|
142 |
+
# Step 3: Call the function and retrieve results. Append the results to the messages list.
|
143 |
+
if tool_function_name == 'ask_question':
|
144 |
+
question = songwriterAssistant.ask_question(messages)
|
145 |
+
|
146 |
+
question = question.replace("ask question:", "").replace("ask question ", "").replace("ask question\n", "").replace("ask question", "")
|
147 |
+
|
148 |
+
## yield question in tool and assistant message
|
149 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': question}
|
150 |
+
|
151 |
+
new_messages = messages + [tool_message]
|
152 |
+
|
153 |
+
question_message = {'role': 'assistant', 'content': question}
|
154 |
+
new_messages = new_messages + [question_message]
|
155 |
+
new_history = messages_to_history(new_messages)
|
156 |
+
|
157 |
+
generated_audios = update_song_links(generated_audios)
|
158 |
+
yield '', new_history, new_messages, '', '', '', '', None, generated_audios, []
|
159 |
+
|
160 |
+
elif tool_function_name == 'clarify_arguments':
|
161 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': 'arguments to clarify: \n' + '\n'.join(tool_query_args['arguments_to_clarify'])}
|
162 |
+
|
163 |
+
new_messages = messages + [tool_message]
|
164 |
+
|
165 |
+
model_response_with_function_call = oai_client.chat.completions.create(
|
166 |
+
model="gpt-4o",
|
167 |
+
messages=new_messages,
|
168 |
+
) # get a new response from the model where it can see the function response
|
169 |
+
current_response = model_response_with_function_call.choices[0].message.content
|
170 |
+
|
171 |
+
role = "assistant"
|
172 |
+
new_messages = new_messages + [{'role': role, 'content': current_response}] # + "\n\nWould you like to get an audio snippet? Or continue writing?"}]
|
173 |
+
# new_messages = [msg for msg in new_messages if msg['content'] is not None and msg['role'] in ['user', 'assistant']]
|
174 |
+
new_history = messages_to_history(new_messages)
|
175 |
+
|
176 |
+
generated_audios = update_song_links(generated_audios)
|
177 |
+
yield '', new_history, new_messages, '', '', '', '', None, generated_audios, []
|
178 |
+
|
179 |
|
180 |
+
elif tool_function_name == 'write_section':
|
|
|
181 |
snippet_instrumental_tags = tool_query_args.pop('snippet_instrumental_tags', None)
|
182 |
snippet_clip_to_continue_from = tool_query_args.pop('snippet_clip_to_continue_from', None)
|
183 |
suggested_lyrics = songwriterAssistant.write_section(**tool_query_args)
|
184 |
+
suggested_lyrics = suggested_lyrics.strip('`*-\n')
|
185 |
|
186 |
## yield suggested lyrics in tool and assistant message
|
187 |
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': suggested_lyrics}
|
|
|
195 |
current_response = model_response_with_function_call.choices[0].message.content
|
196 |
|
197 |
role = "assistant"
|
198 |
+
new_messages = new_messages + [{'role': role, 'content': current_response}] # + "\n\nWould you like to get an audio snippet? Or continue writing?"}]
|
199 |
# new_messages = [msg for msg in new_messages if msg['content'] is not None and msg['role'] in ['user', 'assistant']]
|
200 |
history = messages_to_history(new_messages)
|
201 |
+
|
202 |
+
# current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio
|
203 |
+
buttons = ["revise lyrics", "generate audio snippet", "continue to next section"]
|
204 |
+
|
205 |
+
generated_audios = update_song_links(generated_audios)
|
206 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = snippet_clip_to_continue_from, choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
207 |
|
208 |
|
|
|
|
|
209 |
|
210 |
+
yield '', history, new_messages, tool_query_args['section_name'], suggested_lyrics.split(':')[-1], snippet_instrumental_tags, clips_to_continue, None, generated_audios, buttons
|
|
|
211 |
|
212 |
+
### DO SOMETHING TO UPDATE CURRENT GENERATION for write_section
|
|
|
213 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
|
215 |
elif tool_function_name == 'revise_section_lyrics':
|
|
|
|
|
216 |
revised_lyrics = songwriterAssistant.revise_section_lyrics(**tool_query_args)
|
217 |
|
218 |
+
# if isinstance(revised_lyrics, list):
|
219 |
+
# revised_lyrics = '\n'.join(revised_lyrics)
|
220 |
+
if isinstance(revised_lyrics, str) and revised_lyrics.startswith("[") and revised_lyrics.endswith("]"):
|
221 |
+
try:
|
222 |
+
revised_lyrics = eval(revised_lyrics)
|
223 |
+
if isinstance(revised_lyrics, list):
|
224 |
+
revised_lyrics = '\n'.join(revised_lyrics)
|
225 |
+
except:
|
226 |
+
pass
|
227 |
+
|
228 |
# ## yield revised lyrics in tool and assistant message
|
229 |
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': revised_lyrics}
|
230 |
# audio_message = {'role': 'assistant', 'content': "Here's my revised lyrics:\n" + revised_lyrics + "\n\nGenerating audio snippet..."}
|
|
|
236 |
) # get a new response from the model where it can see the function response
|
237 |
current_response = model_response_with_function_call.choices[0].message.content
|
238 |
|
239 |
+
buttons = ["revise lyrics again", "generate audio snippet with new lyrics", "continue to next section"]
|
240 |
+
|
241 |
role = "assistant"
|
242 |
+
new_messages = new_messages + [{'role': role, 'content': current_response + "\n\nWould you like to get an audio snippet? Or continue writing?"}]
|
243 |
# new_messages = [msg for msg in new_messages if msg['content'] is not None and msg['role'] in ['user', 'assistant']]
|
244 |
history = messages_to_history(new_messages)
|
245 |
+
generated_audios = update_song_links(generated_audios)
|
246 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
|
|
|
|
|
|
|
|
247 |
|
248 |
+
yield '', history, new_messages, tool_query_args['section_name'], revised_lyrics, '', clips_to_continue, None, generated_audios, buttons
|
|
|
249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
|
251 |
elif tool_function_name == 'revise_instrumental_tags':
|
252 |
#detangle tool_query_args dict
|
253 |
#snippet_lyrics = tool_query_args['snippet_lyrics'] + "\n[End]"
|
254 |
+
snippet_instrumental_tags = tool_query_args.get('current_instrumental_tags', None)
|
255 |
+
user_instrumental_feedback = tool_query_args.get('user_instrumental_feedback', None)
|
256 |
+
|
257 |
+
if snippet_instrumental_tags is None or user_instrumental_feedback is None:
|
258 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': 'Arguments are missing. Please clarify your feedback on the instrumental. Note that you cannot revise the genre if you haven\'t generated a snippet.'}
|
259 |
+
audio_message = {'role': 'assistant', 'content': 'It seems like some information is missing. Could you please provide your feedback on the instrumental? Note that you cannot revise the genre if you haven\'t generated a snippet.'}
|
260 |
+
new_messages = messages + [tool_message, audio_message]
|
261 |
+
new_history = messages_to_history(new_messages)
|
262 |
+
yield '', new_history, new_messages, '', '', '', None, None, generated_audios, []
|
263 |
+
return
|
264 |
# if 'snippet_clip_to_continue_from' not in tool_query_args:
|
265 |
# tool_query_args['snippet_clip_to_continue_from'] = None
|
266 |
# snippet_clip_to_continue_from = tool_query_args['snippet_clip_to_continue_from']
|
267 |
|
268 |
new_instrumental_tags = songwriterAssistant.revise_instrumental_tags(snippet_instrumental_tags, user_instrumental_feedback)
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
|
270 |
if isinstance(tool_query_args['sections_written'], str):
|
271 |
current_lyrics = tool_query_args['sections_written']
|
|
|
274 |
else:
|
275 |
current_lyrics = ""
|
276 |
|
277 |
+
import re
|
278 |
+
sections_list = re.findall(r'\[.*?\]', 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 |
+
while "https://audiopipe.suno.ai/?item_id=" not in song_link:
|
284 |
+
print("BUGGED OUT, trying again...")
|
285 |
+
time.sleep(5)
|
286 |
+
song_link = make_song(current_lyrics, new_instrumental_tags)
|
287 |
+
|
288 |
clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
289 |
|
290 |
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}'}
|
291 |
+
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>'}
|
292 |
audio_message['content'] += f'\n\nWhat do you think?'
|
293 |
new_messages = messages + [tool_message, audio_message]
|
294 |
new_history = messages_to_history(new_messages)
|
|
|
|
|
|
|
|
|
295 |
|
296 |
+
# current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio
|
297 |
+
if len(sections_list) > 0:
|
298 |
+
section_name = f"Up to {sections_list[-1]}"
|
299 |
+
else:
|
300 |
+
section_name = "Up to latest section"
|
301 |
+
section_name = determine_title(section_name, generated_audios)
|
302 |
|
303 |
+
generated_audios.append((song_link, current_lyrics, new_instrumental_tags, section_name, "streaming"))
|
304 |
+
generated_audios = update_song_links(generated_audios)
|
305 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
306 |
+
|
307 |
+
buttons = ["return to original instrumental", "re-revise genre", "revise lyrics", "merge snippets", "continue to next section"]
|
308 |
+
|
309 |
+
yield '', new_history, new_messages, ', '.join(sections_list), current_lyrics, new_instrumental_tags, clips_to_continue, f'<audio controls><source src="{song_link}" type="audio/mp3"></audio>', generated_audios, buttons
|
310 |
+
elif tool_function_name == 'revise_section_lyrics_and_instrumental':
|
311 |
+
snippet_instrumental_tags = tool_query_args.pop('current_instrumental_tags', None)
|
312 |
+
user_instrumental_feedback = tool_query_args.pop('user_instrumental_feedback', None)
|
313 |
+
snippet_clip_to_continue_from = tool_query_args.pop('snippet_clip_to_continue_from', None)
|
314 |
+
|
315 |
+
# Revise section lyrics
|
316 |
+
revised_lyrics = songwriterAssistant.revise_section_lyrics(**tool_query_args)
|
317 |
+
|
318 |
+
# Revise instrumental tags
|
319 |
+
|
320 |
+
new_instrumental_tags = songwriterAssistant.revise_instrumental_tags(snippet_instrumental_tags, user_instrumental_feedback)
|
321 |
+
|
322 |
+
song_link = make_song(revised_lyrics, new_instrumental_tags, snippet_clip_to_continue_from)
|
323 |
+
while "https://audiopipe.suno.ai/?item_id=" not in song_link:
|
324 |
+
print("BUGGED OUT, trying again...")
|
325 |
+
time.sleep(5)
|
326 |
+
song_link = make_song(revised_lyrics, new_instrumental_tags, snippet_clip_to_continue_from)
|
327 |
+
|
328 |
+
clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
329 |
+
|
330 |
+
tool_message_instrumental = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'revised lyrics: {revised_lyrics}\nrevised instrumental tags: {new_instrumental_tags}, clip id: {clip_id}'}
|
331 |
+
audio_message = {'role': 'assistant', 'content': f'Sure! I\'ve revised the lyrics and instrumental tags: {revised_lyrics}\nRevised lyrics: {revised_lyrics}\n\n <audio controls autoplay><source src="{song_link}" type="audio/mp3"></audio>'}
|
332 |
+
audio_message['content'] += f'\n\nWhat do you think?'
|
333 |
+
|
334 |
+
new_messages = messages + [tool_message_instrumental, audio_message]
|
335 |
new_history = messages_to_history(new_messages)
|
336 |
+
|
337 |
+
generated_audios.append((song_link, revised_lyrics, new_instrumental_tags, tool_query_args["section_name"], "streaming"))
|
338 |
+
generated_audios = update_song_links(generated_audios)
|
339 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = snippet_clip_to_continue_from, choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
340 |
+
|
341 |
+
buttons = ["return to original instrumental", "re-revise genre", "revise lyrics", "merge snippets", "continue to next section"]
|
342 |
+
|
343 |
+
yield '', new_history, new_messages, tool_query_args["section_name"], revised_lyrics, new_instrumental_tags, clips_to_continue, f'<audio controls><source src="{song_link}" type="audio/mp3"></audio>', generated_audios, buttons
|
344 |
+
|
345 |
+
elif tool_function_name == 'merge_all_snippets':
|
346 |
+
updated_clip_url, updated_lyrics, updated_tags, clips_list = concat_snippets(tool_query_args['last_snippet_id'])
|
347 |
+
|
348 |
+
if "still streaming" in updated_clip_url:
|
349 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'still streaming, try again later'}
|
350 |
+
audio_message = {'role': 'assistant', 'content': f'Unfortunately the generated clip audio is still being streamed, so you can merge later when it is fully generated.'}
|
351 |
+
|
352 |
+
new_messages = messages + [tool_message, audio_message]
|
353 |
+
new_history = messages_to_history(new_messages)
|
354 |
+
|
355 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
356 |
+
|
357 |
+
|
358 |
+
yield '', new_history, new_messages, "", "", "", clips_to_continue, None, generated_audios, ["merge snippets", "continue to next section"]
|
359 |
+
|
360 |
+
else:
|
361 |
+
updated_clip_id = updated_clip_url.split("https://audiopipe.suno.ai/?item_id=")[1]
|
362 |
+
|
363 |
+
#pass this info in new tool and assistant message
|
364 |
+
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}'}
|
365 |
+
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 clips path: {clips_list}</p>'}
|
366 |
+
|
367 |
+
sections_list = [line for line in current_lyrics.split('\n') if line.startswith('[') and line.endswith(']')]
|
368 |
+
|
369 |
+
|
370 |
+
new_messages = messages + [tool_message, audio_message]
|
371 |
+
new_history = messages_to_history(new_messages)
|
372 |
+
|
373 |
+
if len(sections_list) > 0:
|
374 |
+
section_name = "Merge up to " + sections_list[-1]
|
375 |
+
else:
|
376 |
+
section_name = "Merge up to latest section"
|
377 |
+
section_name = determine_title(section_name, generated_audios)
|
378 |
+
|
379 |
+
# current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio
|
380 |
+
generated_audios.append((updated_clip_url, updated_lyrics, updated_tags, section_name, "streaming"))
|
381 |
+
|
382 |
+
generated_audios = update_song_links(generated_audios)
|
383 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
384 |
+
|
385 |
+
|
386 |
+
yield '', new_history, new_messages, section_name, updated_lyrics, updated_tags, clips_to_continue, f'<audio controls><source src="{updated_clip_url}" type="audio/mp3"></audio>', generated_audios, []
|
387 |
elif tool_function_name == 'finish_full_song':
|
388 |
## args are sections_to_be_written, relevant_ideas, last_snippet_id, sni
|
389 |
|
|
|
401 |
## STEP 1: WRITE ALL LYRICS using songwriterAssistant
|
402 |
remaining_lyrics = songwriterAssistant.write_all_lyrics(**tool_query_args)
|
403 |
full_lyrics = current_lyrics + remaining_lyrics + "\n[End]"
|
404 |
+
|
405 |
+
|
406 |
+
# current_section, current_lyrics, curr_tags, clip_to_continue, curr_audio
|
407 |
+
yield '', history, messages, "Full Song", full_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from, None, generated_audios, []
|
408 |
|
409 |
## STEP 2: MAKE SONG FOR REMAINING LYRICS
|
410 |
song_link = make_song(remaining_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from)
|
|
|
415 |
|
416 |
new_messages = messages + [tool_message, audio_message]
|
417 |
new_history = messages_to_history(new_messages)
|
418 |
+
generated_audios.append((song_link, remaining_lyrics, snippet_instrumental_tags, "Rest of Song", "streaming"))
|
419 |
+
|
420 |
+
yield '', new_history, new_messages, "Rest of Song", full_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from, song_link, generated_audios, []
|
421 |
|
422 |
## STEP 3: MERGE FULL SONG
|
423 |
if snippet_clip_to_continue_from not in [None, ""]:
|
424 |
+
updated_clip_url = "still streaming"
|
425 |
+
while "still streaming" in updated_clip_url:
|
426 |
+
updated_clip_url, updated_lyrics, updated_tags, clips_list = concat_snippets(song_link.split("https://audiopipe.suno.ai/?item_id=")[1])
|
427 |
else:
|
428 |
updated_clip_url, updated_lyrics, clips_list = song_link, remaining_lyrics, []
|
429 |
## YIELD UPDATED CLIP URL, LYRICS, AND CLIPS LIST
|
|
|
431 |
|
432 |
#tool and assistant message
|
433 |
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}'}
|
434 |
+
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>'}
|
435 |
|
436 |
new_messages = messages + [tool_message, audio_message]
|
437 |
new_history = messages_to_history(new_messages)
|
438 |
+
generated_audios.append((updated_clip_url, updated_lyrics, updated_tags, "Full Song", "streaming"))
|
439 |
+
generated_audios = update_song_links(generated_audios)
|
440 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
441 |
+
|
442 |
+
yield '', new_history, new_messages, "Full Song", full_lyrics, snippet_instrumental_tags, clips_to_continue, f'<audio controls><source src="{song_link}" type="audio/mp3"></audio>', generated_audios, []
|
443 |
|
444 |
elif tool_function_name == 'get_audio_snippet':
|
445 |
#detangle tool_query_args dict
|
446 |
snippet_lyrics = tool_query_args['snippet_lyrics'] + "\n[End]"
|
447 |
snippet_instrumental_tags = tool_query_args['snippet_instrumental_tags']
|
448 |
+
|
449 |
+
snippet_clip_to_continue_from = tool_query_args.get('snippet_clip_to_continue_from', None)
|
|
|
450 |
song_link = make_song(snippet_lyrics, snippet_instrumental_tags, snippet_clip_to_continue_from)
|
451 |
+
|
452 |
+
|
453 |
+
if "still streaming" in song_link:
|
454 |
+
tool_message = {
|
455 |
+
'role': 'tool',
|
456 |
+
'tool_call_id': tool_call_id,
|
457 |
+
'name': tool_function_name,
|
458 |
+
'content': 'The snippet to extend is still streaming. Please try generating this audio snippet in a little bit.'
|
459 |
+
}
|
460 |
+
|
461 |
+
new_messages = messages + [tool_message]
|
462 |
+
|
463 |
+
model_response_with_function_call = oai_client.chat.completions.create(
|
464 |
+
model="gpt-4o",
|
465 |
+
messages=new_messages,
|
466 |
+
) # get a new response from the model where it can see the function response
|
467 |
+
current_response = model_response_with_function_call.choices[0].message.content
|
468 |
+
|
469 |
+
role = "assistant"
|
470 |
+
new_messages = new_messages + [{'role': role, 'content': current_response}]
|
471 |
+
new_history = messages_to_history(new_messages)
|
472 |
+
|
473 |
+
generated_audios = update_song_links(generated_audios)
|
474 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = "", choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
475 |
+
buttons = ["generate audio snippet", "revise lyrics", "revise genre", "merge snippets", "continue to next section"]
|
476 |
+
|
477 |
+
yield '', new_history, new_messages, snippet_lyrics.split("\n")[0], snippet_lyrics, snippet_instrumental_tags, clips_to_continue, None, generated_audios, buttons
|
478 |
+
|
479 |
+
return
|
480 |
+
print("MAKE SONG IS DONE")
|
481 |
## filter out suno link from tool query arg
|
482 |
clip_id = song_link.split("https://audiopipe.suno.ai/?item_id=")[1]
|
483 |
|
484 |
+
tool_message = {'role': 'tool', 'tool_call_id': tool_call_id, 'name': tool_function_name, 'content': f'snippet lyrics: {snippet_lyrics}\ninstrumental tags: {tool_query_args["snippet_instrumental_tags"]}, clip id: {clip_id}'}
|
485 |
+
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>'
|
486 |
audio_message_content += f'<p>continued from clip: {snippet_clip_to_continue_from}</p>'
|
487 |
+
audio_message_content += "What do you think?"
|
488 |
audio_message = {'role': 'assistant', 'content': audio_message_content}
|
489 |
+
|
490 |
+
|
491 |
+
section_name = snippet_lyrics.split("\n")[0].strip('[]* ')
|
492 |
+
section_name = determine_title(section_name, generated_audios)
|
493 |
+
|
494 |
+
#audio_message = {'role': 'assistant', 'content': gr.Audio(value=song_link, label=section_name, interactive=False, show_label=False, waveform_options={"show_controls": False})}
|
495 |
new_messages = messages + [tool_message, audio_message]
|
496 |
new_history = messages_to_history(new_messages)
|
497 |
+
print("AUDIO MESSAGE DONE")
|
498 |
+
generated_audios.append((song_link, snippet_lyrics, snippet_instrumental_tags, section_name, "streaming"))
|
499 |
+
|
500 |
+
generated_audios = update_song_links(generated_audios)
|
501 |
+
|
502 |
+
buttons = ["revise lyrics", "revise genre", "merge snippets", "continue to next section"]
|
503 |
+
clips_to_continue = gr.Dropdown(label='Clip to continue', value = snippet_clip_to_continue_from, choices=[x[3] for x in generated_audios]+[""], interactive=True)
|
504 |
+
|
505 |
+
yield '', new_history, new_messages, snippet_lyrics.split("\n")[0], snippet_lyrics, snippet_instrumental_tags, clips_to_continue, f'<audio controls><source src="{song_link}" type="audio/mp3"></audio>', generated_audios, buttons
|
506 |
+
|
507 |
+
|
508 |
else:
|
509 |
print(f"Error: function {tool_function_name} does not exist")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
510 |
|
511 |
else:
|
512 |
# Model did not identify a function to call, result can be returned to the user
|
data/conversation_history.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
[{"role": "system", "content": "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 by asking questions about a story of theirs. Design your questions using ask_question 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."}, {"role": "user", "content": "The user has stated the following:\n I have a story that could make this concept work well. The title is Future Dreams , it's about A song about envisioning your ideal future where dreams come true, adventures unfold, and loved ones stand by your side. with a genre Pop and I think this should be the structure: \nVerse 1: 4 measures\nChorus 1: 8 measures\nVerse 2: 8 measures\nChorus 2: 8 measures\nVerse 3: 8 measures\nChorus 3: 8 measures\n Introduce yourself and kick-off the songwriting process with a question."}, {"role": "assistant", "content": "Hey there! I'm excited to help you bring \"Future Dreams\" to life. It sounds like an incredible concept. \n\nTo get started, can you tell me about a specific dream or adventure you've always envisioned for your future? This could be something big, like traveling the world, or something personal, like achieving a lifelong goal."}, {"role": "user", "content": "i've envisioned living in spain after 30"}, {"role": "assistant", "content": null, "tool_calls": [
|
gpt_calls.py
CHANGED
@@ -31,6 +31,33 @@ class AI_Songwriter:
|
|
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:
|
@@ -70,14 +97,20 @@ class AI_Songwriter:
|
|
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 |
-
|
|
|
81 |
|
82 |
line_phrase = "lines" if len(lines_to_infill) > 1 else "line"
|
83 |
line_phrase = str(len(lines_to_infill)) + " " + line_phrase
|
@@ -173,37 +206,4 @@ class AI_Songwriter:
|
|
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 |
|
|
|
31 |
{}"""
|
32 |
|
33 |
|
34 |
+
|
35 |
+
def ask_question(self, messages):
|
36 |
+
convo = messages[:-1]
|
37 |
+
|
38 |
+
instruction = "Based on this conversation history, respond to the user acknowledging their most recent response and ask a concise question to further learn more about the user's story."
|
39 |
+
|
40 |
+
## iterate thru messages and format them into a single string where each message is separated by a newline (ie Assistant: ...\n User: ...\n)
|
41 |
+
convo_str = ""
|
42 |
+
for message in convo:
|
43 |
+
convo_str += f"{message['role']}: {message['content']}\n"
|
44 |
+
convo_str += "Assistant:"
|
45 |
+
|
46 |
+
input = f"{instruction}\nConversation History:\n{convo_str}"
|
47 |
+
|
48 |
+
response = self.oai_client.chat.completions.create(
|
49 |
+
model="gpt-4o",
|
50 |
+
messages=[
|
51 |
+
{
|
52 |
+
"role": "user",
|
53 |
+
"content": input
|
54 |
+
}
|
55 |
+
],
|
56 |
+
)
|
57 |
+
|
58 |
+
return response.choices[0].message.content
|
59 |
+
|
60 |
+
|
61 |
def write_section(self, section_name, section_description, relevant_ideas, section_length, sections_written=None, overall_song_description=None):
|
62 |
instruction = f"Write a {section_name} of length {section_length} that that incorporates the following ideas"
|
63 |
if sections_written is not None:
|
|
|
97 |
messages=convo,
|
98 |
)
|
99 |
|
100 |
+
return "Pass this back to the user and ask if they would like to receive an audio snippet or make any revisions before moving to the next section: \n" + response.choices[0].message.content
|
101 |
|
102 |
def revise_section_lyrics(self, section_name, current_section, lines_to_revise, relevant_ideas=None, relevant_words=None):
|
103 |
lines_to_infill = ", ".join([str(x) for x in lines_to_revise])
|
104 |
|
105 |
full_incomplete_verse = current_section.strip("\n ").split("\n")
|
106 |
+
|
107 |
+
max_line_num = max(lines_to_revise)
|
108 |
+
if max_line_num > len(full_incomplete_verse):
|
109 |
+
full_incomplete_verse.extend([''] * (max_line_num - len(full_incomplete_verse)))
|
110 |
+
|
111 |
for line_num in lines_to_revise:
|
112 |
+
if line_num <= len(full_incomplete_verse):
|
113 |
+
full_incomplete_verse[line_num-1] = '___'
|
114 |
|
115 |
line_phrase = "lines" if len(lines_to_infill) > 1 else "line"
|
116 |
line_phrase = str(len(lines_to_infill)) + " " + line_phrase
|
|
|
206 |
)
|
207 |
|
208 |
return response.choices[0].message.content
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
|
suno.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
import requests
|
2 |
import time
|
3 |
import os
|
|
|
|
|
4 |
|
5 |
base_url = "http://127.0.0.1:8000"
|
6 |
api_endpoint_submit = f"{base_url}/generate/"
|
@@ -52,6 +54,25 @@ def generate_song(tags, prompt, save_path, clip_id=None, continue_at=30):
|
|
52 |
data["continue_at"] = continue_at
|
53 |
else:
|
54 |
data["continue_at"] = 30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
response = requests.post(api_endpoint_submit, json=data) #,headers=headers)
|
57 |
response_data = response.json()
|
@@ -107,7 +128,6 @@ def generate_song(tags, prompt, save_path, clip_id=None, continue_at=30):
|
|
107 |
|
108 |
return url
|
109 |
|
110 |
-
|
111 |
def concat_snippets(clip_id):
|
112 |
concat_url = f"{api_endpoint_concat}?clip_id={clip_id}"
|
113 |
feed_url = api_endpoint_info + clip_id
|
@@ -119,7 +139,10 @@ def concat_snippets(clip_id):
|
|
119 |
print("No data in response, retrying", response_data)
|
120 |
time.sleep(2)
|
121 |
continue
|
122 |
-
|
|
|
|
|
|
|
123 |
break
|
124 |
else:
|
125 |
time.sleep(8)
|
@@ -137,6 +160,7 @@ def concat_snippets(clip_id):
|
|
137 |
return url, lyrics, concatenated_clips
|
138 |
|
139 |
lyrics = response_data["metadata"]["prompt"]
|
|
|
140 |
concatenated_clips = [x["id"] for x in response_data["metadata"]["concat_history"]]
|
141 |
song_id = response_data["id"]
|
142 |
|
@@ -144,12 +168,13 @@ def concat_snippets(clip_id):
|
|
144 |
while True:
|
145 |
response = requests.get(api_endpoint_info + song_id, headers=headers)
|
146 |
response_data = response.json()
|
|
|
147 |
if response.status_code != 200:
|
148 |
print("No data in response, retrying", response_data)
|
149 |
time.sleep(2)
|
150 |
continue
|
151 |
# print("Got response", response_data)
|
152 |
-
if response_data[0]["status"] == 'streaming':
|
153 |
break
|
154 |
else:
|
155 |
time.sleep(2)
|
@@ -160,6 +185,34 @@ def concat_snippets(clip_id):
|
|
160 |
print("Got song", response_data[0]["audio_url"])
|
161 |
url = response_data[0]["audio_url"]
|
162 |
|
163 |
-
return url, lyrics, concatenated_clips
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
|
165 |
|
|
|
1 |
import requests
|
2 |
import time
|
3 |
import os
|
4 |
+
import asyncio
|
5 |
+
import httpx
|
6 |
|
7 |
base_url = "http://127.0.0.1:8000"
|
8 |
api_endpoint_submit = f"{base_url}/generate/"
|
|
|
54 |
data["continue_at"] = continue_at
|
55 |
else:
|
56 |
data["continue_at"] = 30
|
57 |
+
|
58 |
+
feed_url = api_endpoint_info + clip_id
|
59 |
+
response = requests.get(feed_url, headers=headers)
|
60 |
+
response_data = response.json()
|
61 |
+
while True:
|
62 |
+
if response.status_code != 200:
|
63 |
+
print("No data in response, retrying", response_data)
|
64 |
+
time.sleep(2)
|
65 |
+
continue
|
66 |
+
elif response_data[0]["status"] == 'streaming':
|
67 |
+
return "Snippet to extend is still streaming, please wait to request later."
|
68 |
+
if response_data[0]["status"] == 'complete':
|
69 |
+
break
|
70 |
+
else:
|
71 |
+
time.sleep(8)
|
72 |
+
continue
|
73 |
+
|
74 |
+
|
75 |
+
|
76 |
|
77 |
response = requests.post(api_endpoint_submit, json=data) #,headers=headers)
|
78 |
response_data = response.json()
|
|
|
128 |
|
129 |
return url
|
130 |
|
|
|
131 |
def concat_snippets(clip_id):
|
132 |
concat_url = f"{api_endpoint_concat}?clip_id={clip_id}"
|
133 |
feed_url = api_endpoint_info + clip_id
|
|
|
139 |
print("No data in response, retrying", response_data)
|
140 |
time.sleep(2)
|
141 |
continue
|
142 |
+
## CATCH THE CASE WHERE response_data a list of length 1 versus just a dictionary straight up
|
143 |
+
elif response_data["status"] == 'streaming':
|
144 |
+
return "Song is still streaming, please wait to request later.", None, None, []
|
145 |
+
if response_data["status"] == 'complete':
|
146 |
break
|
147 |
else:
|
148 |
time.sleep(8)
|
|
|
160 |
return url, lyrics, concatenated_clips
|
161 |
|
162 |
lyrics = response_data["metadata"]["prompt"]
|
163 |
+
tags = response_data["metadata"]["tags"]
|
164 |
concatenated_clips = [x["id"] for x in response_data["metadata"]["concat_history"]]
|
165 |
song_id = response_data["id"]
|
166 |
|
|
|
168 |
while True:
|
169 |
response = requests.get(api_endpoint_info + song_id, headers=headers)
|
170 |
response_data = response.json()
|
171 |
+
print("feed response for concatenated song", response_data)
|
172 |
if response.status_code != 200:
|
173 |
print("No data in response, retrying", response_data)
|
174 |
time.sleep(2)
|
175 |
continue
|
176 |
# print("Got response", response_data)
|
177 |
+
if response_data[0]["status"] == 'streaming' or response_data[0]["audio_url"] != "" or response_data[0]["status"] == 'complete':
|
178 |
break
|
179 |
else:
|
180 |
time.sleep(2)
|
|
|
185 |
print("Got song", response_data[0]["audio_url"])
|
186 |
url = response_data[0]["audio_url"]
|
187 |
|
188 |
+
return url, lyrics, tags, concatenated_clips
|
189 |
+
|
190 |
+
def update_song_links(generated_audios):
|
191 |
+
updated_generated_audios = generated_audios.copy()
|
192 |
+
for i, song_info in enumerate(generated_audios):
|
193 |
+
clip_path, lyrics, instrumental, title, status = song_info
|
194 |
+
if "audiopipe.suno.ai" in clip_path or status == "streaming":
|
195 |
+
clip_id = clip_path.split("?item_id=")[-1]
|
196 |
+
feed_url = api_endpoint_info + clip_id
|
197 |
+
|
198 |
+
response = requests.get(feed_url, headers=headers)
|
199 |
+
response_data = response.json()
|
200 |
+
if response.status_code != 200:
|
201 |
+
print("No data in response, retrying", response_data)
|
202 |
+
continue
|
203 |
+
elif response_data[0]["status"] == 'streaming':
|
204 |
+
print("still streaming, update later")
|
205 |
+
continue
|
206 |
+
if response_data[0]["status"] == 'complete':
|
207 |
+
updated_clip_path = response_data[0]["audio_url"]
|
208 |
+
print(updated_clip_path)
|
209 |
+
updated_generated_audios[i] = (updated_clip_path, lyrics, instrumental, title, "complete")
|
210 |
+
|
211 |
+
return updated_generated_audios
|
212 |
+
|
213 |
+
|
214 |
+
|
215 |
+
|
216 |
+
|
217 |
|
218 |
|
utils/song_utils.py
CHANGED
@@ -1,8 +1,15 @@
|
|
1 |
import os
|
2 |
from openai import OpenAI
|
3 |
from typing import Optional, Tuple, List, Dict
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
client_key = os.getenv("OPEN_AI_KEY")
|
|
|
6 |
oai_client = OpenAI(
|
7 |
api_key=client_key,
|
8 |
)
|
@@ -87,6 +94,7 @@ def messages_to_history(messages: Messages) -> Tuple[str, History]:
|
|
87 |
"""
|
88 |
assert messages[0]['role'] == 'system' and messages[1]['role'] == 'user'
|
89 |
|
|
|
90 |
# Filter out 'tool' messages and those containing 'tool_calls'
|
91 |
messages_for_parsing = [msg for msg in messages if msg['role'] != 'tool' and 'tool_calls' not in msg]
|
92 |
|
@@ -98,8 +106,8 @@ def messages_to_history(messages: Messages) -> Tuple[str, History]:
|
|
98 |
|
99 |
# Create history from user-assistant message pairs
|
100 |
history = [
|
101 |
-
(q['
|
102 |
-
for q
|
103 |
]
|
104 |
|
105 |
return history
|
@@ -120,8 +128,8 @@ def get_starting_messages(song_lengths: str, song_title: str, song_blurb: str, s
|
|
120 |
"""
|
121 |
system_prompt = (
|
122 |
"You are an expert at writing songs. You are with an everyday person, and you will write the lyrics of the song "
|
123 |
-
"based on this person's life by asking questions about a story of theirs. Design your questions
|
124 |
-
"
|
125 |
"resonates with them. We have equipped you with a set of tools to help you write this story; please use them. You are "
|
126 |
"very good at making the user feel comfortable, understood, and ready to share their feelings and story. Occasionally "
|
127 |
"(every 2 messages or so) you will suggest some lyrics, one section at a time, and see what the user thinks of them. "
|
@@ -145,7 +153,11 @@ def get_starting_messages(song_lengths: str, song_title: str, song_blurb: str, s
|
|
145 |
|
146 |
first_message = first_msg_res.choices[0].message.content
|
147 |
starting_messages = initial_messages + [{'role': 'assistant', 'content': first_message}]
|
148 |
-
|
|
|
|
|
|
|
|
|
149 |
|
150 |
def update_song_details(instrumental_output: str) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
151 |
"""
|
|
|
1 |
import os
|
2 |
from openai import OpenAI
|
3 |
from typing import Optional, Tuple, List, Dict
|
4 |
+
from dotenv import load_dotenv
|
5 |
+
from gradio import ChatMessage
|
6 |
+
import gradio as gr
|
7 |
+
|
8 |
+
# Load environment variables from .env file
|
9 |
+
load_dotenv()
|
10 |
|
11 |
client_key = os.getenv("OPEN_AI_KEY")
|
12 |
+
print(client_key)
|
13 |
oai_client = OpenAI(
|
14 |
api_key=client_key,
|
15 |
)
|
|
|
94 |
"""
|
95 |
assert messages[0]['role'] == 'system' and messages[1]['role'] == 'user'
|
96 |
|
97 |
+
|
98 |
# Filter out 'tool' messages and those containing 'tool_calls'
|
99 |
messages_for_parsing = [msg for msg in messages if msg['role'] != 'tool' and 'tool_calls' not in msg]
|
100 |
|
|
|
106 |
|
107 |
# Create history from user-assistant message pairs
|
108 |
history = [
|
109 |
+
ChatMessage(role = q['role'], content = q['content'])
|
110 |
+
for q in messages_for_parsing[2:]
|
111 |
]
|
112 |
|
113 |
return history
|
|
|
128 |
"""
|
129 |
system_prompt = (
|
130 |
"You are an expert at writing songs. You are with an everyday person, and you will write the lyrics of the song "
|
131 |
+
"based on this person's life by asking questions about a story of theirs. Design your questions using ask_question "
|
132 |
+
" to help you understand the user's story, so you can write a song about the user's experience that "
|
133 |
"resonates with them. We have equipped you with a set of tools to help you write this story; please use them. You are "
|
134 |
"very good at making the user feel comfortable, understood, and ready to share their feelings and story. Occasionally "
|
135 |
"(every 2 messages or so) you will suggest some lyrics, one section at a time, and see what the user thinks of them. "
|
|
|
153 |
|
154 |
first_message = first_msg_res.choices[0].message.content
|
155 |
starting_messages = initial_messages + [{'role': 'assistant', 'content': first_message}]
|
156 |
+
|
157 |
+
history = [ChatMessage(role = x['role'], content = x['content']) for x in starting_messages]
|
158 |
+
history = history[2:]
|
159 |
+
|
160 |
+
return starting_messages, history
|
161 |
|
162 |
def update_song_details(instrumental_output: str) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
163 |
"""
|