|
import os |
|
from openai import OpenAI |
|
from typing import Optional, Tuple, List, Dict |
|
from dotenv import load_dotenv |
|
from gradio import ChatMessage |
|
import gradio as gr |
|
|
|
|
|
load_dotenv() |
|
|
|
client_key = os.getenv("OPEN_AI_KEY") |
|
print(client_key) |
|
oai_client = OpenAI( |
|
api_key=client_key, |
|
) |
|
|
|
History = List[Tuple[str, str]] |
|
Messages = List[Dict[str, str]] |
|
|
|
def generate_song_seed(baseline_seed): |
|
""" |
|
Generates a song seed based on a baseline seed description. |
|
|
|
Args: |
|
baseline_seed (str): The baseline seed description to generate the song concept from. |
|
|
|
Yields: |
|
str: The generated song concept in chunks. |
|
""" |
|
song_details_prompt = ( |
|
"Analyze this description of how someone is feeling and provide a suggestion of an interesting song concept to base a song off of. " |
|
"Here are three examples, now provide a song concept for this fourth:\n\n" |
|
) |
|
|
|
song_seed_prompt_path = 'prompts/prompt_song_seed.txt' |
|
with open(song_seed_prompt_path, 'r', encoding='utf-8') as file: |
|
content_2 = file.read() |
|
|
|
song_details_prompt += f"\n\n{content_2}{baseline_seed}\nSuggested Song Concept: " |
|
|
|
response_generator = oai_client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=[{"role": "user", "content": song_details_prompt}], |
|
stream=True |
|
) |
|
|
|
current_response = "" |
|
for chunk in response_generator: |
|
delta_content = chunk.choices[0].delta.content |
|
if delta_content: |
|
current_response += delta_content |
|
yield current_response |
|
|
|
def get_sections(overall_meaning: str, section_list: str) -> str: |
|
""" |
|
Generates section meanings based on the overall meaning and section list. |
|
|
|
Args: |
|
overall_meaning (str): The overall meaning of the song. |
|
section_list (str): A newline-separated string of section names. |
|
|
|
Returns: |
|
str: The generated section meanings. |
|
""" |
|
section_list = section_list.split("\n") |
|
prompt_path = 'prompts/prompt_section_writer.txt' |
|
|
|
with open(prompt_path, 'r', encoding='utf-8') as file: |
|
prompt_content = file.read() |
|
|
|
user_message = { |
|
"role": "user", |
|
"content": f"{prompt_content}\n\nOverall meaning: {overall_meaning}\nSection list: {', '.join(section_list)}\nSection meanings:" |
|
} |
|
|
|
response = oai_client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=[user_message], |
|
) |
|
|
|
return response.choices[0].message.content |
|
|
|
def messages_to_history(messages: Messages) -> Tuple[str, History]: |
|
""" |
|
Converts a list of messages into a history of user-assistant interactions. |
|
|
|
Args: |
|
messages (Messages): A list of message dictionaries, where each dictionary contains |
|
'role' (str) and 'content' (str) keys. |
|
|
|
Returns: |
|
Tuple[str, History]: A tuple containing a string (empty in this case) and a list of tuples, |
|
where each tuple represents a user-assistant message pair. |
|
""" |
|
assert messages[0]['role'] == 'system' and messages[1]['role'] == 'user' |
|
|
|
|
|
|
|
messages_for_parsing = [msg for msg in messages if msg['role'] != 'tool' and 'tool_calls' not in msg] |
|
|
|
|
|
messages_for_parsing = [ |
|
{'role': msg['role'], 'content': msg['content'].split(" Use write_section")[0]} if msg['role'] == 'user' else msg |
|
for msg in messages_for_parsing |
|
] |
|
|
|
|
|
history = [ |
|
ChatMessage(role = q['role'], content = q['content']) |
|
for q in messages_for_parsing[2:] |
|
] |
|
|
|
return history |
|
|
|
def get_starting_messages(song_lengths: str, song_title: str, song_blurb: str, song_genre: str, init_sections: str) -> Tuple[List[Dict[str, str]], History]: |
|
""" |
|
Generates the initial messages for starting a songwriting session. |
|
|
|
Args: |
|
song_lengths (str): The lengths of the song sections. |
|
song_title (str): The title of the song. |
|
song_blurb (str): A brief description of the song. |
|
song_genre (str): The genre of the song. |
|
init_sections (str): The initial structure of the song sections. |
|
|
|
Returns: |
|
Tuple[List[Dict[str, str]], History]: A tuple containing the starting messages and the message history. |
|
""" |
|
system_prompt = ( |
|
"You are an expert at writing songs. You are with an everyday person, and you will write the lyrics of the song " |
|
"based on this person's life 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." |
|
) |
|
|
|
user_prompt = ( |
|
f"I have a story that could make this concept work well. The title is {song_title}, it's about {song_blurb} with a genre " |
|
f"{song_genre} and I think this should be the structure: {init_sections}\n{song_lengths}" |
|
) |
|
|
|
initial_messages = [ |
|
{"role": "system", "content": system_prompt}, |
|
{"role": "user", "content": f"The user has stated the following:\n {user_prompt}\n Introduce yourself and kick-off the songwriting process with a question."}, |
|
] |
|
|
|
first_msg_res = oai_client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=initial_messages, |
|
) |
|
|
|
first_message = first_msg_res.choices[0].message.content |
|
starting_messages = initial_messages + [{'role': 'assistant', 'content': first_message}] |
|
|
|
history = [ChatMessage(role = x['role'], content = x['content']) for x in starting_messages] |
|
history = history[2:] |
|
|
|
return starting_messages, history |
|
|
|
def update_song_details(instrumental_output: str) -> Tuple[Optional[str], Optional[str], Optional[str]]: |
|
""" |
|
Analyzes the given instrumental output to extract the genre, title, and blurb of a song. |
|
|
|
Args: |
|
instrumental_output (str): The assessment and suggestion of a song concept. |
|
|
|
Returns: |
|
Tuple[Optional[str], Optional[str], Optional[str]]: A tuple containing the genre, title, and blurb of the song. |
|
""" |
|
song_details_prompt = ( |
|
"Analyze this assessment and suggestion of a song concept to extract the genre, one sentence blurb of what the song is about. " |
|
"Based on this, also suggest a song title. Output exactly three lines, in the format of 'genre: [genre]', 'title: [title]', 'blurb: [blurb]'.\n\n" |
|
f"{instrumental_output}" |
|
) |
|
|
|
response = oai_client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=[{"role": "user", "content": song_details_prompt}] |
|
) |
|
|
|
response_lines = response.choices[0].message.content.split('\n') |
|
genre = next((line.split(": ")[1] for line in response_lines if "genre: " in line.lower()), None) |
|
title = next((line.split(": ")[1] for line in response_lines if "title: " in line.lower()), None) |
|
blurb = next((line.split(": ")[1] for line in response_lines if "blurb: " in line.lower()), None) |
|
|
|
return genre, title, blurb |