ss
Browse files
app.py
CHANGED
@@ -249,12 +249,11 @@ I need EXACTLY {num_phrases} lines of lyrics - one line for each musical phrase.
|
|
249 |
CRITICAL INSTRUCTIONS:
|
250 |
- Each line MUST be VERY SHORT with only {min_syllables}-{max_syllables} syllables (aim for {avg_syllables} or fewer)
|
251 |
- PRIORITIZE BREVITY - use fewer syllables rather than more
|
252 |
-
-
|
253 |
-
-
|
254 |
-
-
|
255 |
-
- Each
|
256 |
- Use simple, short words whenever possible
|
257 |
-
- End each line at a natural speaking pause point
|
258 |
|
259 |
FORMAT:
|
260 |
- Just write {num_phrases} plain text lines
|
@@ -263,15 +262,24 @@ FORMAT:
|
|
263 |
- Don't use any tags or markers
|
264 |
- Don't include section labels like [Verse] or [Chorus]
|
265 |
|
266 |
-
EXAMPLE OF
|
267 |
-
Empty chair ({min_syllables} syllables)
|
268 |
-
Waiting by the door ({avg_syllables} syllables)
|
269 |
-
Memories fade ({min_syllables+1} syllables)
|
270 |
-
Into silence ({avg_syllables-1} syllables)
|
271 |
-
Your ghost remains ({avg_syllables} syllables)
|
272 |
-
(... and so on)
|
273 |
|
274 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
"""
|
276 |
|
277 |
# Generate lyrics using the LLM model
|
@@ -631,37 +639,137 @@ def analyze_lyrics_rhythm_match(lyrics, lyric_templates, genre="pop"):
|
|
631 |
result += f"- Average stress pattern accuracy: {avg_stress_percentage:.1f}%\n"
|
632 |
result += f"- Overall rhythmic accuracy: {((range_match_rate + avg_stress_percentage) / 2):.1f}%\n"
|
633 |
|
634 |
-
#
|
635 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
636 |
result += f"- Aim for {min([t.get('min_expected', 3) for t in lyric_templates])}-{max([t.get('max_expected', 7) for t in lyric_templates])} syllables per line\n"
|
637 |
-
result += f"- Break complete thoughts across
|
638 |
-
result += f"-
|
|
|
639 |
|
640 |
# Add genre-specific notes
|
641 |
result += f"\n**Genre Notes ({genre}):**\n"
|
642 |
|
643 |
# Add appropriate genre notes based on genre
|
644 |
if genre.lower() == "pop":
|
645 |
-
result += "- Pop lyrics
|
646 |
-
result += "-
|
647 |
elif genre.lower() == "rock":
|
648 |
-
result += "- Rock lyrics
|
649 |
-
result += "-
|
650 |
elif genre.lower() == "country":
|
651 |
-
result += "- Country lyrics
|
652 |
-
result += "-
|
653 |
elif genre.lower() == "disco":
|
654 |
-
result += "- Disco lyrics work well with
|
655 |
-
result += "-
|
656 |
elif genre.lower() == "metal":
|
657 |
-
result += "- Metal lyrics
|
658 |
-
result += "-
|
659 |
else:
|
660 |
-
result += "- This genre
|
661 |
-
result += "-
|
662 |
|
663 |
return result
|
664 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
665 |
# Create Gradio interface
|
666 |
def create_interface():
|
667 |
with gr.Blocks(title="Music Analysis & Lyrics Generator") as demo:
|
|
|
249 |
CRITICAL INSTRUCTIONS:
|
250 |
- Each line MUST be VERY SHORT with only {min_syllables}-{max_syllables} syllables (aim for {avg_syllables} or fewer)
|
251 |
- PRIORITIZE BREVITY - use fewer syllables rather than more
|
252 |
+
- CONNECT YOUR LINES - spread complete thoughts across 2-3 consecutive lines
|
253 |
+
- Create SENTENCE FLOW across lines instead of making each line independent
|
254 |
+
- Let sentence clauses and phrases flow naturally across multiple lines
|
255 |
+
- Each individual line should still fit into one measure of music
|
256 |
- Use simple, short words whenever possible
|
|
|
257 |
|
258 |
FORMAT:
|
259 |
- Just write {num_phrases} plain text lines
|
|
|
262 |
- Don't use any tags or markers
|
263 |
- Don't include section labels like [Verse] or [Chorus]
|
264 |
|
265 |
+
EXAMPLE OF CONNECTED THOUGHTS ACROSS LINES:
|
|
|
|
|
|
|
|
|
|
|
|
|
266 |
|
267 |
+
Moonlight falls (3 syllables)
|
268 |
+
through my window pane (5 syllables)
|
269 |
+
as I wait for you (5 syllables)
|
270 |
+
|
271 |
+
Notice how these 3 lines form ONE complete sentence.
|
272 |
+
|
273 |
+
Another example:
|
274 |
+
|
275 |
+
Whispers fade (3 syllables)
|
276 |
+
in the morning light (5 syllables)
|
277 |
+
leaving memories (5 syllables)
|
278 |
+
of our last goodbye (5 syllables)
|
279 |
+
|
280 |
+
These 4 lines form a connected thought, not independent statements.
|
281 |
+
|
282 |
+
JUST THE PLAIN LYRICS, EXACTLY {num_phrases} LINES, KEEPING EACH LINE TO {min_syllables}-{max_syllables} SYLLABLES, WITH CONNECTED THOUGHTS ACROSS LINES.
|
283 |
"""
|
284 |
|
285 |
# Generate lyrics using the LLM model
|
|
|
639 |
result += f"- Average stress pattern accuracy: {avg_stress_percentage:.1f}%\n"
|
640 |
result += f"- Overall rhythmic accuracy: {((range_match_rate + avg_stress_percentage) / 2):.1f}%\n"
|
641 |
|
642 |
+
# Analyze sentence flow across lines
|
643 |
+
sentence_flow_analysis = analyze_sentence_flow(lines)
|
644 |
+
result += f"\n**Sentence Flow Analysis:**\n"
|
645 |
+
result += f"- Connected thought groups: {sentence_flow_analysis['connected_groups']} detected\n"
|
646 |
+
result += f"- Average lines per thought: {sentence_flow_analysis['avg_lines_per_group']:.1f}\n"
|
647 |
+
result += f"- Flow quality: {sentence_flow_analysis['flow_quality']}\n"
|
648 |
+
|
649 |
+
# Add guidance on ideal distribution for syllables and sentence flow
|
650 |
+
result += f"\n**Syllable & Flow Guidance:**\n"
|
651 |
result += f"- Aim for {min([t.get('min_expected', 3) for t in lyric_templates])}-{max([t.get('max_expected', 7) for t in lyric_templates])} syllables per line\n"
|
652 |
+
result += f"- Break complete thoughts across 2-3 lines for natural flow\n"
|
653 |
+
result += f"- Connect your lyrics with sentence fragments that flow across lines\n"
|
654 |
+
result += f"- Use conjunctions, prepositions, and dependent clauses to connect lines\n"
|
655 |
|
656 |
# Add genre-specific notes
|
657 |
result += f"\n**Genre Notes ({genre}):**\n"
|
658 |
|
659 |
# Add appropriate genre notes based on genre
|
660 |
if genre.lower() == "pop":
|
661 |
+
result += "- Pop lyrics work well with thoughts spanning 2-3 musical phrases\n"
|
662 |
+
result += "- Create flow by connecting lines with transitions like 'as', 'when', 'through'\n"
|
663 |
elif genre.lower() == "rock":
|
664 |
+
result += "- Rock lyrics benefit from short phrases that build into complete thoughts\n"
|
665 |
+
result += "- Use line breaks strategically to emphasize key words\n"
|
666 |
elif genre.lower() == "country":
|
667 |
+
result += "- Country lyrics tell stories that flow naturally across multiple lines\n"
|
668 |
+
result += "- Connect narrative elements across phrases for authentic storytelling\n"
|
669 |
elif genre.lower() == "disco":
|
670 |
+
result += "- Disco lyrics work well with phrases that create rhythmic momentum\n"
|
671 |
+
result += "- Use line transitions that maintain energy and flow\n"
|
672 |
elif genre.lower() == "metal":
|
673 |
+
result += "- Metal lyrics can create intensity by breaking phrases at dramatic points\n"
|
674 |
+
result += "- Connect lines to build tension and release across measures\n"
|
675 |
else:
|
676 |
+
result += "- This genre works well with connected thoughts across multiple lines\n"
|
677 |
+
result += "- Aim for natural speech flow rather than complete thoughts per line\n"
|
678 |
|
679 |
return result
|
680 |
|
681 |
+
def analyze_sentence_flow(lines):
|
682 |
+
"""Analyze how well the lyrics create sentence flow across multiple lines"""
|
683 |
+
if not lines or len(lines) < 2:
|
684 |
+
return {
|
685 |
+
"connected_groups": 0,
|
686 |
+
"avg_lines_per_group": 0,
|
687 |
+
"flow_quality": "Insufficient lines to analyze"
|
688 |
+
}
|
689 |
+
|
690 |
+
# Simplified analysis looking for grammatical clues of sentence continuation
|
691 |
+
continuation_starters = [
|
692 |
+
'and', 'but', 'or', 'nor', 'for', 'yet', 'so', # Coordinating conjunctions
|
693 |
+
'as', 'when', 'while', 'before', 'after', 'since', 'until', 'because', 'although', 'though', # Subordinating conjunctions
|
694 |
+
'with', 'without', 'through', 'throughout', 'beyond', 'beneath', 'under', 'over', 'into', 'onto', # Prepositions
|
695 |
+
'to', 'from', 'by', 'at', 'in', 'on', 'of', # Common prepositions
|
696 |
+
'where', 'how', 'who', 'whom', 'whose', 'which', 'that', # Relative pronouns
|
697 |
+
'if', 'then', # Conditional connectors
|
698 |
+
]
|
699 |
+
|
700 |
+
# Check for lines that likely continue a thought from previous line
|
701 |
+
connected_lines = []
|
702 |
+
potential_groups = []
|
703 |
+
current_group = [0] # Start with first line
|
704 |
+
|
705 |
+
for i in range(1, len(lines)):
|
706 |
+
# Check if line starts with a continuation word
|
707 |
+
words = lines[i].lower().split()
|
708 |
+
|
709 |
+
# Empty line or no words
|
710 |
+
if not words:
|
711 |
+
if len(current_group) > 1: # Only consider groups of 2+ lines
|
712 |
+
potential_groups.append(current_group.copy())
|
713 |
+
current_group = [i]
|
714 |
+
continue
|
715 |
+
|
716 |
+
# Check first word for continuation clues
|
717 |
+
first_word = words[0].strip(',.!?;:')
|
718 |
+
if first_word in continuation_starters:
|
719 |
+
connected_lines.append(i)
|
720 |
+
current_group.append(i)
|
721 |
+
# Check for absence of capitalization as continuation clue
|
722 |
+
elif not first_word[0].isupper() and first_word[0].isalpha():
|
723 |
+
connected_lines.append(i)
|
724 |
+
current_group.append(i)
|
725 |
+
# Check if current line is very short (likely part of a continued thought)
|
726 |
+
elif len(words) <= 3 and i < len(lines) - 1:
|
727 |
+
# Look ahead to see if next line could be a continuation
|
728 |
+
if i+1 < len(lines):
|
729 |
+
next_words = lines[i+1].lower().split()
|
730 |
+
if next_words and next_words[0] in continuation_starters:
|
731 |
+
connected_lines.append(i)
|
732 |
+
current_group.append(i)
|
733 |
+
else:
|
734 |
+
# This might end a group
|
735 |
+
if len(current_group) > 1: # Only consider groups of 2+ lines
|
736 |
+
potential_groups.append(current_group.copy())
|
737 |
+
current_group = [i]
|
738 |
+
else:
|
739 |
+
# This likely starts a new thought
|
740 |
+
if len(current_group) > 1: # Only consider groups of 2+ lines
|
741 |
+
potential_groups.append(current_group.copy())
|
742 |
+
current_group = [i]
|
743 |
+
|
744 |
+
# Add the last group if it has multiple lines
|
745 |
+
if len(current_group) > 1:
|
746 |
+
potential_groups.append(current_group)
|
747 |
+
|
748 |
+
# Calculate metrics
|
749 |
+
connected_groups = len(potential_groups)
|
750 |
+
|
751 |
+
if connected_groups > 0:
|
752 |
+
avg_lines_per_group = sum(len(group) for group in potential_groups) / connected_groups
|
753 |
+
|
754 |
+
# Determine flow quality
|
755 |
+
if connected_groups >= len(lines) / 3 and avg_lines_per_group >= 2.5:
|
756 |
+
flow_quality = "Excellent - multiple connected thoughts across lines"
|
757 |
+
elif connected_groups >= len(lines) / 4 and avg_lines_per_group >= 2:
|
758 |
+
flow_quality = "Good - some connected thoughts across lines"
|
759 |
+
elif connected_groups > 0:
|
760 |
+
flow_quality = "Fair - limited connection between lines"
|
761 |
+
else:
|
762 |
+
flow_quality = "Poor - mostly independent lines"
|
763 |
+
else:
|
764 |
+
avg_lines_per_group = 0
|
765 |
+
flow_quality = "Poor - no connected thoughts detected"
|
766 |
+
|
767 |
+
return {
|
768 |
+
"connected_groups": connected_groups,
|
769 |
+
"avg_lines_per_group": avg_lines_per_group,
|
770 |
+
"flow_quality": flow_quality
|
771 |
+
}
|
772 |
+
|
773 |
# Create Gradio interface
|
774 |
def create_interface():
|
775 |
with gr.Blocks(title="Music Analysis & Lyrics Generator") as demo:
|