Compare commits
99
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cfa2d0895 | ||
|
|
aebd2a081d | ||
|
|
4900e4fc62 | ||
|
|
54d38d81b2 | ||
|
|
d589ed9031 | ||
|
|
fccc6d1f32 | ||
|
|
6e5dc411c8 | ||
|
|
c3b375e55c | ||
|
|
b18389f06d | ||
|
|
547a068e7b | ||
|
|
3a5271a4d3 | ||
|
|
2e192c481a | ||
|
|
0ac8bd4e39 | ||
|
|
3f12dc2f62 | ||
|
|
36f0092e2d | ||
|
|
10f1e092f7 | ||
|
|
c65d8cff8d | ||
|
|
ad3fc21776 | ||
|
|
a656356c7d | ||
|
|
4e85ed63be | ||
|
|
f788acf30c | ||
|
|
e6c7ec60c8 | ||
|
|
228598fe8b | ||
|
|
1da2e6dfdc | ||
|
|
c1cd74ea7c | ||
|
|
df5fecd001 | ||
|
|
186d2fdea3 | ||
|
|
bb25a9d3ad | ||
|
|
0eaf8ebb9b | ||
|
|
067aedcae2 | ||
|
|
d5a6bb7102 | ||
|
|
b792f61806 | ||
|
|
c2ae17453a | ||
|
|
a88302fdc2 | ||
|
|
930d1cec3e | ||
|
|
a230bfe0c9 | ||
|
|
b7b35f7b68 | ||
|
|
309113692b | ||
|
|
a0687a4793 | ||
|
|
9043fd85f2 | ||
|
|
0a273dd81a | ||
|
|
8af2410e90 | ||
|
|
3f3deb3417 | ||
|
|
aff654081e | ||
|
|
33a9da6009 | ||
|
|
6e95e49875 | ||
|
|
e6ca05b837 | ||
|
|
5bde8ac534 | ||
|
|
9d37b0ba21 | ||
|
|
6d141b537a | ||
|
|
6d33ceb7e7 | ||
|
|
c3b4f927c2 | ||
|
|
f495e7882d | ||
|
|
edfd8d57ba | ||
|
|
112a566361 | ||
|
|
0850b13417 | ||
|
|
e70c2e6968 | ||
|
|
0dfbbe9ea4 | ||
|
|
a07256d4ac | ||
|
|
38b4660649 | ||
|
|
1732431e06 | ||
|
|
3c154bbbd1 | ||
|
|
c8d541aadc | ||
|
|
a562917460 | ||
|
|
680d8bfe50 | ||
|
|
aa65f6a3b3 | ||
|
|
d155d1ba21 | ||
|
|
5e509ffcad | ||
|
|
4eb9f50238 | ||
|
|
814bfa8910 | ||
|
|
179de0ccd7 | ||
|
|
edb582daf9 | ||
|
|
21c5ae5481 | ||
|
|
383670ab2b | ||
|
|
c59a023095 | ||
|
|
10dc4cb693 | ||
|
|
449675e7a2 | ||
|
|
a7806c0c9d | ||
|
|
105664e93b | ||
|
|
1220c21807 | ||
|
|
86914de850 | ||
|
|
8463cfc906 | ||
|
|
ef4112c61e | ||
|
|
1eaebeb5fb | ||
|
|
6fc4b7db17 | ||
|
|
c94b6f2589 | ||
|
|
b3ac12c88d | ||
|
|
5b2c192827 | ||
|
|
991ab5d93a | ||
|
|
78cf5e6ce0 | ||
|
|
aa78a54d12 | ||
|
|
3d472d5c15 | ||
|
|
2f048dee36 | ||
|
|
a3062e848c | ||
|
|
1b2d46cb42 | ||
|
|
f2ccca60b5 | ||
|
|
db7b5f6679 | ||
|
|
98b665537f | ||
|
|
9a089f6c6b |
@@ -3,8 +3,11 @@
|
||||
## Analysis pipeline
|
||||
|
||||
- LLM analysis runs via Python scripts calling the Anthropic
|
||||
Messages API: model `claude-sonnet-4-6`, `temperature=0`,
|
||||
thinking disabled, Batch API where possible.
|
||||
Messages API, Batch API where possible. Steps 1 and 3 run
|
||||
on `claude-sonnet-4-6` with `temperature=0` and thinking
|
||||
disabled; step 4 runs on `claude-fable-5`, which accepts
|
||||
neither parameter -- its sampling variance is absorbed by
|
||||
the majority vote.
|
||||
- Prompt definition files live in
|
||||
`prompts/<step>-<substep>-<task>.md` (e.g. 01-tag.md; no
|
||||
version suffix -- versions live in git history) and are
|
||||
@@ -13,11 +16,13 @@
|
||||
deterministic vocabulary step (step 2) has no definition
|
||||
file yet holds its own number. Zero padding is for
|
||||
sorting only -- prose says "step 1", "step 3".
|
||||
- Per-song LLM judgments (coding) run the same definition
|
||||
file three times, independently, over the same input; a
|
||||
deterministic subcommand then assigns a (song, keyword)
|
||||
pair when at least two of the three runs assign it
|
||||
("3 runs + majority vote"). Free-generation steps run
|
||||
- Itemwise LLM judgments (per-song coding in step 3,
|
||||
per-keyword group selection in step 4) run the same
|
||||
definition file three times, independently, over the same
|
||||
input; a deterministic tally then assigns an item (a
|
||||
(song, keyword) or (group, keyword) pair) when at least
|
||||
two of the three runs assign it ("3 runs + majority
|
||||
vote"). Free-generation steps run
|
||||
twice and both outputs are pooled. The vocabulary is
|
||||
built by a deterministic subcommand (embedding +
|
||||
clustering), not by an LLM. If a validation outcome is
|
||||
|
||||
+192
-192
@@ -2,7 +2,7 @@ Song ID,Run,Type,To Be Replaced,Correct Term
|
||||
song-1,run1,evidence,You still hit my phone up,you still hit my phone up
|
||||
song-1,run2,evidence,You still hit my phone up,you still hit my phone up
|
||||
song-1,run3,evidence,You still hit my phone up,you still hit my phone up
|
||||
song-13,run1,evidence,"You needed me\nTo feel a little more, and give a little less","you needed me\nTo feel a little more, and give a little less"
|
||||
song-13,run1,evidence,"You needed me / To feel a little more, and give a little less","you needed me / To feel a little more, and give a little less"
|
||||
song-15,run1,evidence,The people still think I'm a star,the people still think I'm a star
|
||||
song-15,run2,evidence,The people still think I'm a star,the people still think I'm a star
|
||||
song-15,run3,evidence,The people still think I'm a star,the people still think I'm a star
|
||||
@@ -11,7 +11,7 @@ song-18,run3,evidence,Let's start living dangerously,let's start living dangerou
|
||||
song-19,run1,evidence,"It's just me, myself and I","it's just me, myself and I"
|
||||
song-19,run2,evidence,"It's just me, myself and I","it's just me, myself and I"
|
||||
song-19,run3,evidence,"It's just me, myself and I","it's just me, myself and I"
|
||||
song-20,run1,evidence,"""Who would you live for?"" ""Who would you die for?""\nAnd ""would you ever kill?""","""who would you live for?"" ""Who would you die for?""\nAnd ""would you ever kill?"""
|
||||
song-20,run1,evidence,"""Who would you live for?"" ""Who would you die for?"" / And ""would you ever kill?""","""who would you live for?"" ""Who would you die for?"" / And ""would you ever kill?"""
|
||||
song-21,run3,keyword,warning-and-danger,**REMOVE**
|
||||
song-29,run1,evidence,Last night I think I lost my patience,last night I think I lost my patience
|
||||
song-29,run2,evidence,Last night I came to a realization,"Last night, I came to a realization"
|
||||
@@ -39,22 +39,22 @@ song-63,run2,evidence,And then I let him go,and then I let him go
|
||||
song-63,run3,evidence,And then I let him go,and then I let him go
|
||||
song-64,run1,evidence,And that red dress brings me to my knees,and that red dress brings me to my knees
|
||||
song-64,run1,evidence,If I never get to build my mansion in Georgia,if I never get to build my mansion in Georgia
|
||||
song-64,run2,evidence,Baby last night was hands down one of the best nights,Baby last night was hands down\nOne of the best nights
|
||||
song-64,run2,evidence,Between the bottle of wine and the look in your eyes and the Marvin Gaye,Between the bottle of wine\nAnd the look in your eyes and the Marvin Gaye
|
||||
song-64,run2,evidence,Baby last night was hands down one of the best nights,Baby last night was hands down / One of the best nights
|
||||
song-64,run2,evidence,Between the bottle of wine and the look in your eyes and the Marvin Gaye,Between the bottle of wine / And the look in your eyes and the Marvin Gaye
|
||||
song-64,run2,evidence,But that black dress makes it hard to breathe,but that black dress makes it hard to breathe
|
||||
song-64,run3,evidence,Baby last night was hands down one of the best nights,Baby last night was hands down\nOne of the best nights
|
||||
song-64,run3,evidence,Between the bottle of wine and the look in your eyes and the Marvin Gaye,Between the bottle of wine\nAnd the look in your eyes and the Marvin Gaye
|
||||
song-64,run3,evidence,Baby last night was hands down one of the best nights,Baby last night was hands down / One of the best nights
|
||||
song-64,run3,evidence,Between the bottle of wine and the look in your eyes and the Marvin Gaye,Between the bottle of wine / And the look in your eyes and the Marvin Gaye
|
||||
song-64,run3,evidence,But that black dress makes it hard to breathe,but that black dress makes it hard to breathe
|
||||
song-65,run3,evidence,Jump all them Jordans,jump all them Jordans
|
||||
song-79,run1,evidence,I bet these memories follow you around,I bet these memories\nFollow you around
|
||||
song-86,run1,evidence,He knows dirty secrets that I keep,He knows\nDirty secrets that I keep
|
||||
song-90,run1,evidence,"Any car, any house\nBaby you can get like any ring, anything","any car, any house\nBaby you can get like any ring, anything"
|
||||
song-90,run1,evidence,"Baby the cars on decline\nYou roll with me, you miss shine","baby the cars on decline\nYou roll with me, you miss shine"
|
||||
song-90,run2,evidence,"Any car, any house\nBaby you can get like any ring, anything","any car, any house\nBaby you can get like any ring, anything"
|
||||
song-79,run1,evidence,I bet these memories follow you around,I bet these memories / Follow you around
|
||||
song-86,run1,evidence,He knows dirty secrets that I keep,He knows / Dirty secrets that I keep
|
||||
song-90,run1,evidence,"Any car, any house / Baby you can get like any ring, anything","any car, any house / Baby you can get like any ring, anything"
|
||||
song-90,run1,evidence,"Baby the cars on decline / You roll with me, you miss shine","baby the cars on decline / You roll with me, you miss shine"
|
||||
song-90,run2,evidence,"Any car, any house / Baby you can get like any ring, anything","any car, any house / Baby you can get like any ring, anything"
|
||||
song-90,run2,evidence,Baby the cars on decline,baby the cars on decline
|
||||
song-90,run2,evidence,You don't have to worry 'bout a thing,You don't have to worry ‘bout a thing
|
||||
song-90,run3,evidence,"'Cause I may not know you, just let me hold you","‘Cause I may not know you, just let me hold you"
|
||||
song-90,run3,evidence,"Any car, any house\nBaby you can get like any ring, anything","any car, any house\nBaby you can get like any ring, anything"
|
||||
song-90,run3,evidence,"Any car, any house / Baby you can get like any ring, anything","any car, any house / Baby you can get like any ring, anything"
|
||||
song-90,run3,evidence,Baby the cars on decline,baby the cars on decline
|
||||
song-90,run3,evidence,"You be my soldier, and you from the 'Nolia","You be my soldier, and you from the ‘Nolia"
|
||||
song-92,run1,evidence,All my diamonds shine 'cause they really diamonds,All my diamonds shine ‘cause they really diamonds
|
||||
@@ -74,8 +74,8 @@ song-98,run3,evidence,"Ten niggas with 'em, ten clappin' on 'em","Ten niggas wit
|
||||
song-98,run3,evidence,"Young boy walkin', wishin' for a burner","Young boy walkin’, wishin’ for a burner"
|
||||
song-99,run3,evidence,Hard work forever pays now I see you in a better place,hard work forever pays now I see you in a better place
|
||||
song-106,run3,evidence,"Sim, armadilha jovem negro com o Ak (rrah)","Sim, dessa forma, armadilha jovem negro com o Ak (rrah)"
|
||||
song-110,run1,evidence,You made me feel as though I was enough,You made me feel as though\nI was enough
|
||||
song-110,run2,evidence,You made me feel as though I was enough,You made me feel as though\nI was enough
|
||||
song-110,run1,evidence,You made me feel as though I was enough,You made me feel as though / I was enough
|
||||
song-110,run2,evidence,You made me feel as though I was enough,You made me feel as though / I was enough
|
||||
song-112,run1,keyword,alcohol-and-substance-use,alcohol-and-substance-abuse
|
||||
song-113,run1,evidence,"Buy my Range, make 'em go insane","Buy my Range, make ‘em go insane"
|
||||
song-113,run1,evidence,"Tек and beams, go to those extremes","Tek and beams, go to those extremes"
|
||||
@@ -85,9 +85,9 @@ song-113,run3,evidence,"Buy my Range, make 'em go insane","Buy my Range, make
|
||||
song-120,run3,keyword,manipulation,**REMOVE**
|
||||
song-128,run2,evidence,So she tries to cover up her pain,"So, she tries to cover up her pain"
|
||||
song-128,run3,evidence,So she tries to cover up her pain,"So, she tries to cover up her pain"
|
||||
song-129,run1,evidence,"It's the lightness in the air\nWhen you're there, chest to chest with a lover","it's the lightness in the air\nWhen you're there, chest to chest with a lover"
|
||||
song-129,run2,evidence,"It's the lightness in the air\nWhen you're there, chest to chest with a lover","it's the lightness in the air\nWhen you're there, chest to chest with a lover"
|
||||
song-129,run3,evidence,"It's the lightness in the air\nWhen you're there, chest to chest with a lover","it's the lightness in the air\nWhen you're there, chest to chest with a lover"
|
||||
song-129,run1,evidence,"It's the lightness in the air / When you're there, chest to chest with a lover","it's the lightness in the air / When you're there, chest to chest with a lover"
|
||||
song-129,run2,evidence,"It's the lightness in the air / When you're there, chest to chest with a lover","it's the lightness in the air / When you're there, chest to chest with a lover"
|
||||
song-129,run3,evidence,"It's the lightness in the air / When you're there, chest to chest with a lover","it's the lightness in the air / When you're there, chest to chest with a lover"
|
||||
song-136,run2,keyword,reputation-and-gossess,reputation-and-gossip
|
||||
song-141,run1,keyword,sacrifice,**REMOVE**
|
||||
song-141,run2,keyword,sacrifice-and-surrender,**REMOVE**
|
||||
@@ -104,11 +104,11 @@ song-156,run2,evidence,Sleepin' in a villa,sleepin' in a villa
|
||||
song-156,run3,evidence,Pessimists never struck my nerve,pessimists never struck my nerve
|
||||
song-156,run3,evidence,Sleepin' in a villa,sleepin' in a villa
|
||||
song-159,run1,evidence,Cleansing my soul of addiction for now,Cleansin' my soul of addiction for now
|
||||
song-159,run1,evidence,Tension\nBetween us just like picket fences,tension\nBetween us just like picket fences
|
||||
song-159,run1,evidence,Tension / Between us just like picket fences,tension / Between us just like picket fences
|
||||
song-159,run2,evidence,Cleansing my soul of addiction for now,Cleansin' my soul of addiction for now
|
||||
song-159,run2,evidence,Tension\nBetween us just like picket fences,tension\nBetween us just like picket fences
|
||||
song-159,run2,evidence,Tension / Between us just like picket fences,tension / Between us just like picket fences
|
||||
song-159,run3,evidence,Cleansing my soul of addiction for now,Cleansin' my soul of addiction for now
|
||||
song-159,run3,evidence,Tension\nBetween us just like picket fences,tension\nBetween us just like picket fences
|
||||
song-159,run3,evidence,Tension / Between us just like picket fences,tension / Between us just like picket fences
|
||||
song-161,run1,evidence,"Some things, only God can forgive","some things, only God can forgive"
|
||||
song-161,run2,evidence,"Some things, only God can forgive","some things, only God can forgive"
|
||||
song-161,run3,evidence,"Some things, only God can forgive","some things, only God can forgive"
|
||||
@@ -117,8 +117,8 @@ song-162,run2,evidence,Back the fuck up off me,back the fuck up off me
|
||||
song-162,run3,evidence,Back the fuck up off me,back the fuck up off me
|
||||
song-165,run3,evidence,"What if I hurt you, what if I leave you","what if I hurt you, what if I leave you"
|
||||
song-172,run2,evidence,Bitch can't stop me,bitch can't stop me
|
||||
song-175,run2,evidence,But how you called the cops on me my nig? You grew up with me,But how you called the cops on me my nig?\nYou grew up with me
|
||||
song-175,run3,evidence,But how you called the cops on me my nig? You grew up with me,But how you called the cops on me my nig?\nYou grew up with me
|
||||
song-175,run2,evidence,But how you called the cops on me my nig? You grew up with me,But how you called the cops on me my nig? / You grew up with me
|
||||
song-175,run3,evidence,But how you called the cops on me my nig? You grew up with me,But how you called the cops on me my nig? / You grew up with me
|
||||
song-177,run1,evidence,All she wear is red bottom heels,all she wear is red bottom heels
|
||||
song-177,run2,evidence,All she wear is red bottom heels,all she wear is red bottom heels
|
||||
song-177,run3,evidence,All she wear is red bottom heels,all she wear is red bottom heels
|
||||
@@ -130,7 +130,7 @@ song-187,run1,evidence,He said there's a lot of girls I can do with,He said ther
|
||||
song-187,run2,evidence,"Half of my heart is in Havana, ooh-na-na (ayy)","Half of my heart is in Havana, ooh-na-na (ayy"
|
||||
song-187,run2,evidence,He said there's a lot of girls I can do with,He said there’s a lot of girls I can do with
|
||||
song-187,run3,evidence,"Half of my heart is in Havana, ooh-na-na (ayy)","Half of my heart is in Havana, ooh-na-na (ayy"
|
||||
song-187,run3,evidence,"Half of my heart is in Havana, ooh-na-na (ayy)\nHe took me back to East Atlanta, oh-na-na-na","Half of my heart is in Havana, ooh-na-na (ayy, ayy)\nHe took me back to East Atlanta, oh-na-na-na"
|
||||
song-187,run3,evidence,"Half of my heart is in Havana, ooh-na-na (ayy) / He took me back to East Atlanta, oh-na-na-na","Half of my heart is in Havana, ooh-na-na (ayy, ayy) / He took me back to East Atlanta, oh-na-na-na"
|
||||
song-187,run3,evidence,He said there's a lot of girls I can do with,He said there’s a lot of girls I can do with
|
||||
song-188,run1,evidence,Aren't we too grown to mess around? Yeah,Are we too grown to mess around? Yeah
|
||||
song-188,run2,evidence,Aren't we too grown to mess around? Yeah,Are we too grown to mess around? Yeah
|
||||
@@ -151,9 +151,9 @@ song-207,run2,evidence,"Just one hit of you, I knew I'll never ever, ever be the
|
||||
song-207,run3,evidence,"Just one hit of you, I knew I'll never ever, ever be the same","Just one hit of you, I knew I’ll never ever, ever be the same"
|
||||
song-210,run1,evidence,"I just gotta tell you how I feel, look","Just gotta tell you how I feel, look"
|
||||
song-210,run3,evidence,"I just gotta tell you how I feel, look","Just gotta tell you how I feel, look"
|
||||
song-211,run1,evidence,Pull up with that Draco (huh?) / Play with Drake and I'ma shoot (that's on my mama),pull up with that Draco (huh?)\nPlay with Drake and I'ma shoot (that's on my mama
|
||||
song-211,run1,evidence,Pull up with that Draco (huh?) / Play with Drake and I'ma shoot (that's on my mama),pull up with that Draco (huh?) / Play with Drake and I'ma shoot (that's on my mama
|
||||
song-211,run3,evidence,"Pull up broad day with a K, now he shiverin' (he shiverin')","pull up broad day with a K, now he shiverin' (he shiverin')"
|
||||
song-211,run3,evidence,Pull up with that Draco (huh?) / Play with Drake and I'ma shoot (that's on my mama),pull up with that Draco (huh?)\nPlay with Drake and I'ma shoot (that's on my mama
|
||||
song-211,run3,evidence,Pull up with that Draco (huh?) / Play with Drake and I'ma shoot (that's on my mama),pull up with that Draco (huh?) / Play with Drake and I'ma shoot (that's on my mama
|
||||
song-216,run2,evidence,Fuck what a nigga say,fuck what a nigga say
|
||||
song-217,run1,evidence,Let's put my fake face on and pretend now,let's put my fake face on and pretend now
|
||||
song-217,run3,evidence,Let's put my fake face on and pretend now,let's put my fake face on and pretend now
|
||||
@@ -161,7 +161,7 @@ song-218,run1,evidence,Pussy poppin' on the charts,Pussy poppin’ on the charts
|
||||
song-218,run2,evidence,Pussy poppin' on the charts,Pussy poppin’ on the charts
|
||||
song-218,run3,evidence,Pussy poppin' on the charts,Pussy poppin’ on the charts
|
||||
song-219,run1,evidence,Come through rockin' fashions,come through rockin' fashions
|
||||
song-219,run2,evidence,"Come through rockin' fashions\nThat got all these bitches like ""Yo, what's that?""","come through rockin' fashions\nThat got all these bitches like ""Yo, what's that?"""
|
||||
song-219,run2,evidence,"Come through rockin' fashions / That got all these bitches like ""Yo, what's that?""","come through rockin' fashions / That got all these bitches like ""Yo, what's that?"""
|
||||
song-219,run3,evidence,Come through rockin' fashions,come through rockin' fashions
|
||||
song-223,run1,evidence,So I'm just a dead man crawling tonight,So I’m just a dead man crawling tonight
|
||||
song-223,run1,evidence,"So who you've been calling, baby? Nobody could take my place","So who you’ve been calling, baby? Nobody could take my place"
|
||||
@@ -173,20 +173,20 @@ song-223,run3,evidence,"So who you've been calling, baby? Nobody could take my p
|
||||
song-223,run3,evidence,You used to call me baby now you're calling me by name,you used to call me baby now you're calling me by name
|
||||
song-226,run1,evidence,"She left me with a broken heart, yeah","she left me with a broken heart, yeah"
|
||||
song-226,run3,evidence,"She left me with a broken heart, yeah","she left me with a broken heart, yeah"
|
||||
song-227,run1,evidence,If I gotta be sacrificed for the greater good\nThen that's what it gotta be,if I gotta be sacrificed for the greater good\nThen that's what it gotta be
|
||||
song-227,run2,evidence,If I gotta be sacrificed for the greater good\nThen that's what it gotta be,if I gotta be sacrificed for the greater good\nThen that's what it gotta be
|
||||
song-227,run1,evidence,If I gotta be sacrificed for the greater good / Then that's what it gotta be,if I gotta be sacrificed for the greater good / Then that's what it gotta be
|
||||
song-227,run2,evidence,If I gotta be sacrificed for the greater good / Then that's what it gotta be,if I gotta be sacrificed for the greater good / Then that's what it gotta be
|
||||
song-228,run1,evidence,And I gotta convince myself I don't want it even though I do,And I gotta convince myself I don’t want it even though I do
|
||||
song-228,run2,evidence,And I gotta convince myself I don't want it even though I do,And I gotta convince myself I don’t want it even though I do
|
||||
song-228,run3,evidence,And I gotta convince myself I don't want it even though I do,And I gotta convince myself I don’t want it even though I do
|
||||
song-228,run3,evidence,Overthinking every word and I hate it 'cause it's not me,Overthinking every word and I hate it 'cause it’s not me
|
||||
song-229,run2,evidence,"Checks over stripes, that's what I like",Checks over stripes (yeah)\nThat's what I like
|
||||
song-229,run3,evidence,"Checks over stripes, that's what I like",Checks over stripes (yeah)\nThat's what I like
|
||||
song-230,run2,evidence,"Take my shoes and walk a mile, Something that you can't do",Take my shoes and walk a mile\nSomething that you can't do
|
||||
song-230,run2,evidence,"Think it came with stripes, But you ain't straight with the gang",Think it came with stripes\nBut you ain't straight with the gang
|
||||
song-230,run3,evidence,"I bought a 'Plain Jane' Rollie, These niggas bought they fame",I bought a 'Plain Jane' Rollie\nThese niggas bought they fame
|
||||
song-229,run2,evidence,"Checks over stripes, that's what I like",Checks over stripes (yeah) / That's what I like
|
||||
song-229,run3,evidence,"Checks over stripes, that's what I like",Checks over stripes (yeah) / That's what I like
|
||||
song-230,run2,evidence,"Take my shoes and walk a mile, Something that you can't do",Take my shoes and walk a mile / Something that you can't do
|
||||
song-230,run2,evidence,"Think it came with stripes, But you ain't straight with the gang",Think it came with stripes / But you ain't straight with the gang
|
||||
song-230,run3,evidence,"I bought a 'Plain Jane' Rollie, These niggas bought they fame",I bought a 'Plain Jane' Rollie / These niggas bought they fame
|
||||
song-230,run3,evidence,Quadruple the profit (Profit),quadruple the profit (Profit)
|
||||
song-230,run3,evidence,"Take my shoes and walk a mile, Something that you can't do",Take my shoes and walk a mile\nSomething that you can't do
|
||||
song-230,run3,evidence,"Think it came with stripes, But you ain't straight with the gang (Gang, gang!)","Think it came with stripes\nBut you ain't straight with the gang (Gang, gang"
|
||||
song-230,run3,evidence,"Take my shoes and walk a mile, Something that you can't do",Take my shoes and walk a mile / Something that you can't do
|
||||
song-230,run3,evidence,"Think it came with stripes, But you ain't straight with the gang (Gang, gang!)","Think it came with stripes / But you ain't straight with the gang (Gang, gang"
|
||||
song-232,run1,evidence,"What the fuck is love with no pain, no suffer","what the fuck is love with no pain, no suffer"
|
||||
song-232,run2,evidence,She gon' ride for me until this thing over,she gon' ride for me until this thing over
|
||||
song-232,run2,evidence,We'd both go crazy (crazy) if we was to sever,we'd both go crazy (crazy) if we was to sever
|
||||
@@ -207,15 +207,15 @@ song-242,run3,evidence,"Fuck 12, I'm a G, ain't no stoppin' me (ain't no stoppin
|
||||
song-247,run1,evidence,You love it how I move you,you love it how I move you
|
||||
song-247,run2,evidence,You love it how I move you,you love it how I move you
|
||||
song-247,run3,evidence,You love it how I move you,you love it how I move you
|
||||
song-252,run1,evidence,face up 'cause you're a natural,face up 'cause you're a...\n\nNatural
|
||||
song-252,run2,evidence,Will somebody let me see the light within the dark trees' shadows,Will somebody\nLet me see the light within the dark trees' shadows
|
||||
song-252,run2,evidence,"Will you hold the line when every one of them is giving up or giving in, tell me","Will you hold the line\nWhen every one of them is giving up or giving in, tell me"
|
||||
song-252,run2,evidence,You gotta be so cold to make it in this world,You gotta be so cold\nTo make it in this world
|
||||
song-252,run2,evidence,face up 'cause you're a natural,face up 'cause you're a...\n\nNatural
|
||||
song-252,run3,evidence,"I can taste it, the end is upon us, I swear gonna make it","I can taste it, the end is upon us, I swear\nGonna make it"
|
||||
song-252,run3,evidence,Will somebody let me see the light within the dark trees' shadows and,Will somebody\nLet me see the light within the dark trees' shadows and
|
||||
song-252,run3,evidence,You gotta be so cold to make it in this world,You gotta be so cold\nTo make it in this world
|
||||
song-252,run3,evidence,face up 'cause you're a natural,face up 'cause you're a...\n\nNatural
|
||||
song-252,run1,evidence,face up 'cause you're a natural,face up 'cause you're a... / / Natural
|
||||
song-252,run2,evidence,Will somebody let me see the light within the dark trees' shadows,Will somebody / Let me see the light within the dark trees' shadows
|
||||
song-252,run2,evidence,"Will you hold the line when every one of them is giving up or giving in, tell me","Will you hold the line / When every one of them is giving up or giving in, tell me"
|
||||
song-252,run2,evidence,You gotta be so cold to make it in this world,You gotta be so cold / To make it in this world
|
||||
song-252,run2,evidence,face up 'cause you're a natural,face up 'cause you're a... / / Natural
|
||||
song-252,run3,evidence,"I can taste it, the end is upon us, I swear gonna make it","I can taste it, the end is upon us, I swear / Gonna make it"
|
||||
song-252,run3,evidence,Will somebody let me see the light within the dark trees' shadows and,Will somebody / Let me see the light within the dark trees' shadows and
|
||||
song-252,run3,evidence,You gotta be so cold to make it in this world,You gotta be so cold / To make it in this world
|
||||
song-252,run3,evidence,face up 'cause you're a natural,face up 'cause you're a... / / Natural
|
||||
song-258,run1,evidence,Every day she found a way out of the window to sneak out late,every day she found a way out of the window to sneak out late
|
||||
song-258,run2,evidence,Every day she found a way out of the window to sneak out late,every day she found a way out of the window to sneak out late
|
||||
song-258,run3,evidence,Every day she found a way out of the window to sneak out late,every day she found a way out of the window to sneak out late
|
||||
@@ -244,8 +244,8 @@ song-282,run3,evidence,"See the igloo in my mouth when I be grinnin' (I be grinn
|
||||
song-283,run1,evidence,Breakfast at Tiffany's and bottles of bubbles,breakfast at Tiffany's and bottles of bubbles
|
||||
song-283,run2,evidence,Breakfast at Tiffany's and bottles of bubbles,breakfast at Tiffany's and bottles of bubbles
|
||||
song-283,run3,evidence,Breakfast at Tiffany's and bottles of bubbles,breakfast at Tiffany's and bottles of bubbles
|
||||
song-287,run2,evidence,I've learned from the pain\nTurned out amazing,I've learned from the pain (pain)\nTurned out amazing
|
||||
song-287,run3,evidence,Look what I got\nLook what you taught me,look what I got\nLook what you taught me
|
||||
song-287,run2,evidence,I've learned from the pain / Turned out amazing,I've learned from the pain (pain) / Turned out amazing
|
||||
song-287,run3,evidence,Look what I got / Look what you taught me,look what I got / Look what you taught me
|
||||
song-291,run1,evidence,But I'm told its where I'm supposed to be,But I’m told its where I’m supposed to be
|
||||
song-291,run1,evidence,Coz I don't care when I'm with my baby yeah,Coz I don’t care when I’m with my baby yeah
|
||||
song-291,run1,evidence,Don't think I fit in at this party,Don’t think I fit in at this party
|
||||
@@ -288,9 +288,9 @@ song-293,run3,evidence,Aren't you tired tryin' to fill that void?,Aren’t you t
|
||||
song-293,run3,evidence,"Crash through the surface, where they can't hurt us","Crash through the surface, where they can’t hurt us"
|
||||
song-293,run3,evidence,"I'm off the deep end, watch as I dive in","I’m off the deep end, watch as I dive in"
|
||||
song-293,run3,evidence,We're far from the shallow now,We’re far from the shallow now
|
||||
song-297,run3,evidence,That lil' nigga ain't gon' shoot shit with that gun\nHe just pull it out in his pictures,that lil' nigga ain't gon' shoot shit with that gun\nHe just pull it out in his pictures
|
||||
song-303,run1,evidence,There's no way I could save you\n'Cause I need to be saved too,There's no way I could save you (Save you)\n'Cause I need to be saved too
|
||||
song-303,run3,evidence,There's no way I could save you\n'Cause I need to be saved too,There's no way I could save you (Save you)\n'Cause I need to be saved too
|
||||
song-297,run3,evidence,That lil' nigga ain't gon' shoot shit with that gun / He just pull it out in his pictures,that lil' nigga ain't gon' shoot shit with that gun / He just pull it out in his pictures
|
||||
song-303,run1,evidence,There's no way I could save you / 'Cause I need to be saved too,There's no way I could save you (Save you) / 'Cause I need to be saved too
|
||||
song-303,run3,evidence,There's no way I could save you / 'Cause I need to be saved too,There's no way I could save you (Save you) / 'Cause I need to be saved too
|
||||
song-313,run1,evidence,"But I'm 21 4L, ain't no way I'ma switch","But I'm 21 4L, ain’t no way I'ma switch"
|
||||
song-313,run1,evidence,"Every day that I'm alive, I'ma ride with the stick","Every day that I'm alive, I’ma ride with the stick"
|
||||
song-313,run1,evidence,It's got to the point that these rappers don't even like rappin' with me,It’s got to the point that these rappers don't even like rappin' with me
|
||||
@@ -330,33 +330,33 @@ song-335,run2,evidence,"I like your ""poom poom"" girl",I like your “poom poom
|
||||
song-335,run3,evidence,Desde que te vi supe que eras pa' mi,Desde que te vi supe que eras pa’ mi
|
||||
song-335,run3,evidence,"I like your ""poom poom"" girl",I like your “poom poom” girl
|
||||
song-340,run1,evidence,"'Cause you different, you can't play your part (no damn, ay)","'Cause you different, you can’t play your part (no damn, ay)"
|
||||
song-340,run1,evidence,How could you\nMoving like you're crazy\nI ain't call you back (damn),How could you\nMoving like you’re crazy\nI ain’t call you back (damn)
|
||||
song-340,run1,evidence,How you just gon' play me\nI ain't fine with that,How you just gon’ play me\nI ain’t fine with that
|
||||
song-340,run1,evidence,How could you / Moving like you're crazy / I ain't call you back (damn),How could you / Moving like you’re crazy / I ain’t call you back (damn)
|
||||
song-340,run1,evidence,How you just gon' play me / I ain't fine with that,How you just gon’ play me / I ain’t fine with that
|
||||
song-340,run1,evidence,I can't sweat you I'm like who dat?,I can’t sweat you I’m like who dat?
|
||||
song-340,run1,evidence,I wanted you but I can't fuck with you,I wanted you but I can’t fuck with you
|
||||
song-340,run1,evidence,Play me you're my lady\nGot no time for that,Play me you’re my lady\nGot no time for that
|
||||
song-340,run1,evidence,Tell you the truth\nI ain't want you to depart (ay),Tell you the truth\nI ain’t want you to depart (ay)
|
||||
song-340,run1,evidence,Thinking 'bout you daily\nSmoking crazy while I'm off the tac (damn),Thinking ‘bout you daily\nSmoking crazy while I’m off the tac (damn)
|
||||
song-340,run1,evidence,Play me you're my lady / Got no time for that,Play me you’re my lady / Got no time for that
|
||||
song-340,run1,evidence,Tell you the truth / I ain't want you to depart (ay),Tell you the truth / I ain’t want you to depart (ay)
|
||||
song-340,run1,evidence,Thinking 'bout you daily / Smoking crazy while I'm off the tac (damn),Thinking ‘bout you daily / Smoking crazy while I’m off the tac (damn)
|
||||
song-340,run1,evidence,"You can't play me, I'm just wavy","You can’t play me, I’m just wavy"
|
||||
song-340,run2,evidence,Hit my bop like I'm Lil Kodak,Hit my bop like I’m Lil Kodak
|
||||
song-340,run2,evidence,How you just gon' play me\nI ain't fine with that,How you just gon’ play me\nI ain’t fine with that
|
||||
song-340,run2,evidence,I cannot fuck on no bitch\nI can't love when the bitch is not playing her part (like damn),I cannot fuck on no bitch\nI can’t love when the bitch is not playing her part (like damn)
|
||||
song-340,run2,evidence,"I wanted you but I can't fuck with you\n'Cause you different, you can't play your part (no damn, ay)","I wanted you but I can’t fuck with you\n'Cause you different, you can’t play your part (no damn, ay)"
|
||||
song-340,run2,evidence,Moving like you're crazy\nI ain't call you back (damn),Moving like you’re crazy\nI ain’t call you back (damn)
|
||||
song-340,run2,evidence,Tell you the truth\nI ain't want you to depart (ay),Tell you the truth\nI ain’t want you to depart (ay)
|
||||
song-340,run2,evidence,How you just gon' play me / I ain't fine with that,How you just gon’ play me / I ain’t fine with that
|
||||
song-340,run2,evidence,I cannot fuck on no bitch / I can't love when the bitch is not playing her part (like damn),I cannot fuck on no bitch / I can’t love when the bitch is not playing her part (like damn)
|
||||
song-340,run2,evidence,"I wanted you but I can't fuck with you / 'Cause you different, you can't play your part (no damn, ay)","I wanted you but I can’t fuck with you / 'Cause you different, you can’t play your part (no damn, ay)"
|
||||
song-340,run2,evidence,Moving like you're crazy / I ain't call you back (damn),Moving like you’re crazy / I ain’t call you back (damn)
|
||||
song-340,run2,evidence,Tell you the truth / I ain't want you to depart (ay),Tell you the truth / I ain’t want you to depart (ay)
|
||||
song-340,run2,evidence,Thinking 'bout you daily,Thinking ‘bout you daily
|
||||
song-340,run2,evidence,"You can't play me, I'm just wavy","You can’t play me, I’m just wavy"
|
||||
song-340,run3,evidence,"'Cause you different, you can't play your part (no damn, ay)","'Cause you different, you can’t play your part (no damn, ay)"
|
||||
song-340,run3,evidence,Hit my bop like I'm Lil Kodak,Hit my bop like I’m Lil Kodak
|
||||
song-340,run3,evidence,How you just gon' play me\nI ain't fine with that,How you just gon’ play me\nI ain’t fine with that
|
||||
song-340,run3,evidence,How you just gon' play me / I ain't fine with that,How you just gon’ play me / I ain’t fine with that
|
||||
song-340,run3,evidence,I ain't fine with that,I ain’t fine with that
|
||||
song-340,run3,evidence,I cannot fuck on no bitch\nI can't love when the bitch is not playing her part (like damn),I cannot fuck on no bitch\nI can’t love when the bitch is not playing her part (like damn)
|
||||
song-340,run3,evidence,I cannot fuck on no bitch / I can't love when the bitch is not playing her part (like damn),I cannot fuck on no bitch / I can’t love when the bitch is not playing her part (like damn)
|
||||
song-340,run3,evidence,I wanted you but I can't fuck with you,I wanted you but I can’t fuck with you
|
||||
song-340,run3,evidence,Leave and I'm gone (yah),Leave and I’m gone (yah)
|
||||
song-340,run3,evidence,Moving like you're crazy\nI ain't call you back (damn),Moving like you’re crazy\nI ain’t call you back (damn)
|
||||
song-340,run3,evidence,Tell you the truth\nI ain't want you to depart (ay),Tell you the truth\nI ain’t want you to depart (ay)
|
||||
song-340,run3,evidence,Moving like you're crazy / I ain't call you back (damn),Moving like you’re crazy / I ain’t call you back (damn)
|
||||
song-340,run3,evidence,Tell you the truth / I ain't want you to depart (ay),Tell you the truth / I ain’t want you to depart (ay)
|
||||
song-340,run3,evidence,Thinking 'bout you daily,Thinking ‘bout you daily
|
||||
song-340,run3,evidence,Thinking 'bout you daily\nSmoking crazy while I'm off the tac (damn),Thinking ‘bout you daily\nSmoking crazy while I’m off the tac (damn)
|
||||
song-340,run3,evidence,Thinking 'bout you daily / Smoking crazy while I'm off the tac (damn),Thinking ‘bout you daily / Smoking crazy while I’m off the tac (damn)
|
||||
song-340,run3,evidence,"You can't play me, I'm just wavy","You can’t play me, I’m just wavy"
|
||||
song-344,run1,evidence,"It's the end, doo doo doo doo doo doo","It’s the end, doo doo doo doo doo doo"
|
||||
song-344,run1,evidence,"Let's go hunt, doo doo doo doo doo doo","Let’s go hunt, doo doo doo doo doo doo"
|
||||
@@ -382,12 +382,12 @@ song-348,run1,evidence,Small town nights need both ends burnin',small town night
|
||||
song-348,run2,evidence,And ice needs whiskey,and ice needs whiskey
|
||||
song-348,run2,evidence,Back seats need I want you so bad,back seats need I want you so bad
|
||||
song-348,run2,evidence,Birds need bees and ice needs whiskey,birds need bees and ice needs whiskey
|
||||
song-348,run2,evidence,Friday nights need to do what Friday nights need to do,Friday nights need to do\nWhat Friday nights need to do
|
||||
song-348,run2,evidence,Friday nights need to do what Friday nights need to do,Friday nights need to do / What Friday nights need to do
|
||||
song-348,run2,evidence,Small town nights need both ends burnin',small town nights need both ends burnin'
|
||||
song-348,run3,evidence,And ice needs whiskey,and ice needs whiskey
|
||||
song-348,run3,evidence,Back seats need I want you so bad,back seats need I want you so bad
|
||||
song-348,run3,evidence,Birds need bees and ice needs whiskey,birds need bees and ice needs whiskey
|
||||
song-348,run3,evidence,Friday nights need to do what Friday nights need to do,Friday nights need to do\nWhat Friday nights need to do
|
||||
song-348,run3,evidence,Friday nights need to do what Friday nights need to do,Friday nights need to do / What Friday nights need to do
|
||||
song-348,run3,evidence,Small town nights need both ends burnin',small town nights need both ends burnin'
|
||||
song-350,run1,evidence,"I swear I ain't no killer, but test me if you want","I swear I ain’t no killer, but test me if you want"
|
||||
song-350,run1,evidence,"I thought everything was right, that's when you left, yeah","I thought everything was right, that’s when you left, yeah"
|
||||
@@ -403,7 +403,7 @@ song-356,run1,evidence,I've cheated and I've lied,I've cheated and I’ve lied
|
||||
song-356,run1,evidence,I've got nothing to hide no more,I’ve got nothing to hide no more
|
||||
song-356,run2,evidence,I've cheated and I've lied,I've cheated and I’ve lied
|
||||
song-356,run2,evidence,I've got nothing to hide no more,I’ve got nothing to hide no more
|
||||
song-356,run2,evidence,"When I was gettin' crazy, reckless, and wild\nActin' like my mama's little devilish child\nIt took a heart like yours to find its place","When I was gettin' crazy, reckless, and wild\nActin’ like my mama's little devilish child\nIt took a heart like yours to find its place"
|
||||
song-356,run2,evidence,"When I was gettin' crazy, reckless, and wild / Actin' like my mama's little devilish child / It took a heart like yours to find its place","When I was gettin' crazy, reckless, and wild / Actin’ like my mama's little devilish child / It took a heart like yours to find its place"
|
||||
song-356,run3,evidence,I've cheated and I've lied,I've cheated and I’ve lied
|
||||
song-356,run3,evidence,I've got nothing to hide no more,I’ve got nothing to hide no more
|
||||
song-357,run1,evidence,"and that's why every time you see me, I got some new shoes","And that's why every time you see me, I got some new shoes"
|
||||
@@ -411,21 +411,21 @@ song-357,run2,evidence,"and that's why every time you see me, I got some new sho
|
||||
song-357,run3,evidence,"and that's why every time you see me, I got some new shoes","And that's why every time you see me, I got some new shoes"
|
||||
song-359,run2,evidence,"College girl, but a freak on the weekend (On the weekend)","college girl, but a freak on the weekend (On the weekend)"
|
||||
song-360,run1,evidence,"I talked you into taking up my time, making up your mind","Talked you into taking up my time, making up your mind"
|
||||
song-360,run1,evidence,There's a look in your eyes\nLooks like we ain't leavin' now,there's a look in your eyes\nLooks like we ain't leavin' now
|
||||
song-360,run2,evidence,There's a look in your eyes\nLooks like we ain't leavin' now,there's a look in your eyes\nLooks like we ain't leavin' now
|
||||
song-360,run3,evidence,There's a look in your eyes\nLooks like we ain't leavin' now,there's a look in your eyes\nLooks like we ain't leavin' now
|
||||
song-360,run1,evidence,There's a look in your eyes / Looks like we ain't leavin' now,there's a look in your eyes / Looks like we ain't leavin' now
|
||||
song-360,run2,evidence,There's a look in your eyes / Looks like we ain't leavin' now,there's a look in your eyes / Looks like we ain't leavin' now
|
||||
song-360,run3,evidence,There's a look in your eyes / Looks like we ain't leavin' now,there's a look in your eyes / Looks like we ain't leavin' now
|
||||
song-362,run1,keyword,travel-and-adventure,**REMOVE**
|
||||
song-369,run2,evidence,"Aren't you the guy who tried to hurt me with the word ""goodbye""?","Aren't you the guy who tried to\nHurt me with the word ""goodbye""?"
|
||||
song-369,run2,evidence,"Aren't you the guy who tried to hurt me with the word ""goodbye""?","Aren't you the guy who tried to / Hurt me with the word ""goodbye""?"
|
||||
song-370,run2,evidence,She know that her youngest son was always guaranteed to get the money,she know that her youngest son was always guaranteed to get the money
|
||||
song-374,run1,evidence,"But we built this right, so nothing's ever gonna move it","but\nWe built this right, so nothing's ever gonna move it"
|
||||
song-374,run1,evidence,"But we built this right, so nothing's ever gonna move it","but / We built this right, so nothing's ever gonna move it"
|
||||
song-374,run1,evidence,The wolves came and went and we're still standing,the wolves came and went and we're still standing
|
||||
song-374,run2,evidence,The wolves came and went and we're still standing,the wolves came and went and we're still standing
|
||||
song-374,run3,evidence,The wolves came and went and we're still standing,the wolves came and went and we're still standing
|
||||
song-376,run2,evidence,I hope you make me smile the way you made me smile on the other end of a phone,I hope she makes you smile\nThe way you made me smile on the other end of a phone
|
||||
song-376,run2,evidence,I hope you make me smile the way you made me smile on the other end of a phone,I hope she makes you smile / The way you made me smile on the other end of a phone
|
||||
song-390,run2,evidence,Shit hit different when it's Thursday night,shit hit different when it's Thursday night
|
||||
song-397,run2,evidence,"I should've stayed at home, 'cause I was doing better alone","I whould've stayed at home, 'cause I was doing better alone"
|
||||
song-398,run1,evidence,Chasing that feeling that got gone too soon,chasing that feeling that got gone too soon
|
||||
song-399,run1,evidence,"Your savage love\nDid somebody, did somebody break your heart?\nLookin' like an angel but your savage love","your\n\nSavage love\nDid somebody, did somebody break your heart?\nLookin' like an angel but your savage love"
|
||||
song-399,run1,evidence,"Your savage love / Did somebody, did somebody break your heart? / Lookin' like an angel but your savage love","your / / Savage love / Did somebody, did somebody break your heart? / Lookin' like an angel but your savage love"
|
||||
song-400,run1,evidence,She drop a pin and I'd come met her,she drop a pin and I'd come met her
|
||||
song-400,run2,evidence,She drop a pin and I'd come met her,she drop a pin and I'd come met her
|
||||
song-406,run2,evidence,"Yeah, we still young, there's so much we haven't done","yeah, we still young, there's so much we haven't done"
|
||||
@@ -459,7 +459,7 @@ song-423,run3,evidence,"She drinkin' Four Lokos, I can't get with those","She dr
|
||||
song-423,run3,evidence,"She say: You say you love me, but I don't know what love means","She say: You say you love me, but I don’t know what love means"
|
||||
song-423,run3,evidence,"They say you ain't wifey type, but I don't care, I want you","They say you ain’t wifey type, but I don’t care, I want you"
|
||||
song-425,run1,evidence,"Shawty with the long text, I don't talk, ayy","shawty with the long text, I don't talk, ayy"
|
||||
song-426,run2,evidence,Make my wish come true\nBaby all I want for Christmas is you,Make my wish come true\nBaby all I want for Christmas is\nYou
|
||||
song-426,run2,evidence,Make my wish come true / Baby all I want for Christmas is you,Make my wish come true / Baby all I want for Christmas is / You
|
||||
song-427,run1,evidence,You broke every heart in your hometown,"You one of them girls, broke every heart in your hometown"
|
||||
song-427,run1,evidence,You're one of them girls that ain't tryna meet nobody,you're one of them girls that ain't tryna meet nobody
|
||||
song-427,run2,evidence,You're one of them girls that ain't tryna meet nobody,you're one of them girls that ain't tryna meet nobody
|
||||
@@ -475,11 +475,11 @@ song-435,run1,evidence,"She only liked the guap, red light these hoes","she only
|
||||
song-435,run1,evidence,"The Bentley came with the wings like a number nine, yeah","the Bentley came with the wings like a number nine, yeah"
|
||||
song-435,run2,evidence,"She only liked the guap, red light these hoes","she only liked the guap, red light these hoes"
|
||||
song-435,run3,evidence,"The Bentley came with the wings like a number nine, yeah","the Bentley came with the wings like a number nine, yeah"
|
||||
song-436,run1,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty\nI gotta be one of them greats"
|
||||
song-436,run1,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty / I gotta be one of them greats"
|
||||
song-436,run1,evidence,"Wake up every day, somebody harassin' me","Wake up every day, somebody harrassin' me"
|
||||
song-436,run2,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty\nI gotta be one of them greats"
|
||||
song-436,run2,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty / I gotta be one of them greats"
|
||||
song-436,run2,evidence,"Wake up every day, somebody harassin' me","Wake up every day, somebody harrassin' me"
|
||||
song-436,run3,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty\nI gotta be one of them greats"
|
||||
song-436,run3,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty / I gotta be one of them greats"
|
||||
song-437,run1,evidence,Lock the door and throw out the key,lock the door and throw out the key
|
||||
song-437,run2,evidence,Lock the door and throw out the key,lock the door and throw out the key
|
||||
song-437,run2,evidence,"You never let me down, no, no","you never let me down, no, no"
|
||||
@@ -512,13 +512,13 @@ song-465,run3,evidence,Remember when I couldn't hold her,Remember when I couldn
|
||||
song-467,run1,evidence,'Cause you ain't ever left me empty-handed,'Cause you ain’t ever left me empty-handed
|
||||
song-467,run2,evidence,'Cause you ain't ever left me empty-handed,'Cause you ain’t ever left me empty-handed
|
||||
song-467,run3,evidence,'Cause you ain't ever left me empty-handed,'Cause you ain’t ever left me empty-handed
|
||||
song-468,run1,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her\nThat we did that, too?"
|
||||
song-468,run2,evidence,"Play her piano, but she doesn't know that I was the one who taught you Billy Joel","Play her piano, but she doesn't know (oh, oh)\nThat I was the one who taught you Billy Joel"
|
||||
song-468,run2,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her\nThat we did that, too?"
|
||||
song-468,run3,evidence,I made the jokes you tell to her when she's with you,I made the jokes you tell to her\nWhen she's with you
|
||||
song-468,run3,evidence,"Play her piano, but she doesn't know that I was the one who taught you Billy Joel","Play her piano, but she doesn't know (oh, oh)\nThat I was the one who taught you Billy Joel"
|
||||
song-468,run3,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her\nThat we did that, too?"
|
||||
song-468,run3,evidence,"That was the show we talked about, played you the songs she's singing now",That was the show we talked about\nPlayed you the songs she's singing now
|
||||
song-468,run1,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her / That we did that, too?"
|
||||
song-468,run2,evidence,"Play her piano, but she doesn't know that I was the one who taught you Billy Joel","Play her piano, but she doesn't know (oh, oh) / That I was the one who taught you Billy Joel"
|
||||
song-468,run2,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her / That we did that, too?"
|
||||
song-468,run3,evidence,I made the jokes you tell to her when she's with you,I made the jokes you tell to her / When she's with you
|
||||
song-468,run3,evidence,"Play her piano, but she doesn't know that I was the one who taught you Billy Joel","Play her piano, but she doesn't know (oh, oh) / That I was the one who taught you Billy Joel"
|
||||
song-468,run3,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her / That we did that, too?"
|
||||
song-468,run3,evidence,"That was the show we talked about, played you the songs she's singing now",That was the show we talked about / Played you the songs she's singing now
|
||||
song-478,run2,evidence,"I turn my haters to consumers, I make vets feel like they juniors","Turn my haters to consumers, I make vets feel like they juniors"
|
||||
song-480,run1,evidence,Bitches ain't fucking with me now and I can see why,Bitches ain’t fucking with me now and I can see why
|
||||
song-480,run1,evidence,Broke boys don't deserve no pussy,Broke boys don’t deserve no pussy
|
||||
@@ -535,14 +535,14 @@ song-483,run1,evidence,"Best friend, you the baddest and you know it (You know)"
|
||||
song-483,run2,evidence,"Best friend, you the baddest and you know it (You know)","best friend, you the baddest and you know it (You know)"
|
||||
song-485,run3,evidence,Like when you walked out my life,like when you walked out my life
|
||||
song-487,run1,evidence,I fill my nights with broken dreams,And fill my nights with broken dreams
|
||||
song-487,run1,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best)\nBest you ever had and best you gon' get (Gon' get)
|
||||
song-487,run1,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best) / Best you ever had and best you gon' get (Gon' get)
|
||||
song-487,run2,evidence,I fill my nights with broken dreams,And fill my nights with broken dreams
|
||||
song-487,run2,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best)\nBest you ever had and best you gon' get (Gon' get)
|
||||
song-487,run2,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best) / Best you ever had and best you gon' get (Gon' get)
|
||||
song-487,run3,evidence,I fill my nights with broken dreams,And fill my nights with broken dreams
|
||||
song-487,run3,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best)\nBest you ever had and best you gon' get (Gon' get)
|
||||
song-491,run1,evidence,Ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it,ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it
|
||||
song-491,run2,evidence,Ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it,ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it
|
||||
song-491,run3,evidence,Ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it,ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it
|
||||
song-487,run3,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best) / Best you ever had and best you gon' get (Gon' get)
|
||||
song-491,run1,evidence,Ain't it funny / How you said you were friends? / Now it sure as hell don't look like it,ain't it funny / How you said you were friends? / Now it sure as hell don't look like it
|
||||
song-491,run2,evidence,Ain't it funny / How you said you were friends? / Now it sure as hell don't look like it,ain't it funny / How you said you were friends? / Now it sure as hell don't look like it
|
||||
song-491,run3,evidence,Ain't it funny / How you said you were friends? / Now it sure as hell don't look like it,ain't it funny / How you said you were friends? / Now it sure as hell don't look like it
|
||||
song-492,run1,evidence,"All that wolfin' on the net, nigga, I thought you was a thug","All that wolfin' on the net (Ugh), nigga, I thought you was a thug"
|
||||
song-492,run2,evidence,"All that wolfin' on the net, nigga, I thought you was a thug","All that wolfin' on the net (Ugh), nigga, I thought you was a thug"
|
||||
song-492,run3,evidence,"All that wolfin' on the net, nigga, I thought you was a thug","All that wolfin' on the net (Ugh), nigga, I thought you was a thug"
|
||||
@@ -556,9 +556,9 @@ song-501,run1,evidence,Kicked the PJs on a PJ (a PJ),"Kickin' my feet up, left t
|
||||
song-513,run2,evidence,love-as-fleeting-and-transient,**REMOVE**
|
||||
song-513,run3,evidence,love-as-fleeting-and-transient,**REMOVE**
|
||||
song-516,run1,evidence,"So put your loving hand out, baby",So put your loving hand out baby
|
||||
song-520,run1,evidence,"And she said, ""Take me to the country\nShow me where you from""","And she said, “Take me to the country\nShow me where you from”"
|
||||
song-520,run2,evidence,"And she said, ""Take me to the country\nShow me where you from""","And she said, “Take me to the country\nShow me where you from”"
|
||||
song-520,run3,evidence,"And she said, ""Take me to the country\nShow me where you from""","And she said, “Take me to the country\nShow me where you from”"
|
||||
song-520,run1,evidence,"And she said, ""Take me to the country / Show me where you from""","And she said, “Take me to the country / Show me where you from”"
|
||||
song-520,run2,evidence,"And she said, ""Take me to the country / Show me where you from""","And she said, “Take me to the country / Show me where you from”"
|
||||
song-520,run3,evidence,"And she said, ""Take me to the country / Show me where you from""","And she said, “Take me to the country / Show me where you from”"
|
||||
song-521,run1,evidence,None of these hoes finna see me at the bank,none of these hoes finna see me at the bank
|
||||
song-521,run1,evidence,"Order '42 for the table, let's pop shit","Order '42 for the table, let’s pop shit"
|
||||
song-521,run1,evidence,Why the fuck you in the club when niggas wildin'?,Why the fuck you in the club when niggas wildin’?
|
||||
@@ -568,9 +568,9 @@ song-521,run2,evidence,Why the fuck you in the club when niggas wildin'?,Why the
|
||||
song-521,run3,evidence,None of these hoes finna see me at the bank,none of these hoes finna see me at the bank
|
||||
song-521,run3,evidence,"Order '42 for the table, let's pop shit","Order '42 for the table, let’s pop shit"
|
||||
song-521,run3,evidence,Why the fuck you in the club when niggas wildin'?,Why the fuck you in the club when niggas wildin’?
|
||||
song-524,run1,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to\nLove you the way that I want
|
||||
song-524,run2,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to\nLove you the way that I want
|
||||
song-524,run3,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to\nLove you the way that I want
|
||||
song-524,run1,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to / Love you the way that I want
|
||||
song-524,run2,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to / Love you the way that I want
|
||||
song-524,run3,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to / Love you the way that I want
|
||||
song-532,run2,evidence,"si me da' tu cuenta de banco, un millón de peso'","Si me da' tu cuenta de banco, un millón de peso'"
|
||||
song-532,run3,evidence,"si me da' tu cuenta de banco, un millón de peso'","Si me da' tu cuenta de banco, un millón de peso'"
|
||||
song-538,run1,evidence,"Girl, I don't want to be the one who pays the price","Girl, I don’t want to be the one who pays the price"
|
||||
@@ -585,15 +585,15 @@ song-538,run3,evidence,"Girl, I don't want to be the one who pays the price","Gi
|
||||
song-538,run3,evidence,"It's like a dream, what she feels with me","It’s like a dream, what she feels with me"
|
||||
song-538,run3,evidence,You're offering yourself to me like sacrifice,You’re offering yourself to me like sacrifice
|
||||
song-538,run3,evidence,You're way too young to end your life,You’re way too young to end your life
|
||||
song-539,run1,evidence,How can I judge you when you're with somebody else as long as you swear,How can I judge you when you're with\nSomebody else as long as you swear
|
||||
song-539,run2,evidence,How can I judge you when you're with somebody else,How can I judge you when you're with\nSomebody else
|
||||
song-539,run3,evidence,How can I judge you when you're with somebody else as long as you swear,How can I judge you when you're with\nSomebody else as long as you swear
|
||||
song-540,run1,evidence,But I was your first and your last ticket outta there,But I was your first and your\nLast ticket outta there
|
||||
song-540,run1,evidence,Go out like shooting stars chasing what's in our hearts,Go out like shooting stars\nChasing what's in our hearts
|
||||
song-540,run1,evidence,I caught your wings on fire when I smoked my Bronco tires outta that town,I caught your wings on fire\nWhen I smoked my Bronco tires\nOutta that town
|
||||
song-540,run1,evidence,"We're livin' wreckless, nothin' to catch us, baby","We're livin' wreckless\nNothin' to catch us, baby"
|
||||
song-540,run1,evidence,"You holdin' me holdin' you, it's a hell of a view",You holdin' me holdin' you\nIt's a hell of a view
|
||||
song-540,run1,evidence,You liked the thought of chasin' life instead of dollar bills,You liked the thought of chasin'\nLife instead of dollar bills
|
||||
song-539,run1,evidence,How can I judge you when you're with somebody else as long as you swear,How can I judge you when you're with / Somebody else as long as you swear
|
||||
song-539,run2,evidence,How can I judge you when you're with somebody else,How can I judge you when you're with / Somebody else
|
||||
song-539,run3,evidence,How can I judge you when you're with somebody else as long as you swear,How can I judge you when you're with / Somebody else as long as you swear
|
||||
song-540,run1,evidence,But I was your first and your last ticket outta there,But I was your first and your / Last ticket outta there
|
||||
song-540,run1,evidence,Go out like shooting stars chasing what's in our hearts,Go out like shooting stars / Chasing what's in our hearts
|
||||
song-540,run1,evidence,I caught your wings on fire when I smoked my Bronco tires outta that town,I caught your wings on fire / When I smoked my Bronco tires / Outta that town
|
||||
song-540,run1,evidence,"We're livin' wreckless, nothin' to catch us, baby","We're livin' wreckless / Nothin' to catch us, baby"
|
||||
song-540,run1,evidence,"You holdin' me holdin' you, it's a hell of a view",You holdin' me holdin' you / It's a hell of a view
|
||||
song-540,run1,evidence,You liked the thought of chasin' life instead of dollar bills,You liked the thought of chasin' / Life instead of dollar bills
|
||||
song-543,run3,evidence,You only listen to your fucking friends,you only listen to your fucking friends
|
||||
song-544,run1,evidence,But damn if I didn't find what I wasn't even looking for,But damn if I didn’t find what I wasn't even looking for
|
||||
song-544,run1,evidence,I wasn't looking for love when I walked through the door,I wasn’t looking for love when I walked through the door
|
||||
@@ -611,22 +611,22 @@ song-547,run3,evidence,I'm a young nigga though,I’m a young nigga though
|
||||
song-547,run3,evidence,Just talked to pops about the feds,just talked to pops about the feds
|
||||
song-547,run3,evidence,"This shit comes with a lot, it's a lot of pressure, I'm a young nigga though","This shit comes with a lot, it’s a lot of pressure, I’m a young nigga though"
|
||||
song-548,run1,evidence,EVEN THOUGH IT'S A FRIDAY NIGHT,EVEN THOUGH IT’S A FRIDAY NIGHT
|
||||
song-548,run1,evidence,I AIN'T NEVER\nBEEN THE CHURCH GOING TYPE,I AIN’T NEVER\nBEEN THE CHURCH GOING TYPE
|
||||
song-548,run1,evidence,I AIN'T NEVER / BEEN THE CHURCH GOING TYPE,I AIN’T NEVER / BEEN THE CHURCH GOING TYPE
|
||||
song-548,run1,evidence,IF IT'S LIKE DOWN HERE UP THERE TONIGHT,IF IT’S LIKE DOWN HERE UP THERE TONIGHT
|
||||
song-548,run1,evidence,"SITTIN' HERE, DRINKIN' BEER, TALKIN' GOD, AMEN","SITTIN’ HERE, DRINKIN’ BEER, TALKIN’ GOD, AMEN"
|
||||
song-548,run1,evidence,WHEN THE WORLD'S GONE CRAZY MAN IT ALL MAKES SENSE,WHEN THE WORLD’S GONE CRAZY MAN IT ALL MAKES SENSE
|
||||
song-548,run2,evidence,EVEN THOUGH IT'S A FRIDAY NIGHT,EVEN THOUGH IT’S A FRIDAY NIGHT
|
||||
song-548,run2,evidence,I AIN'T NEVER\nBEEN THE CHURCH GOING TYPE,I AIN’T NEVER\nBEEN THE CHURCH GOING TYPE
|
||||
song-548,run2,evidence,I AIN'T NEVER / BEEN THE CHURCH GOING TYPE,I AIN’T NEVER / BEEN THE CHURCH GOING TYPE
|
||||
song-548,run2,evidence,IF IT'S LIKE DOWN HERE UP THERE TONIGHT,IF IT’S LIKE DOWN HERE UP THERE TONIGHT
|
||||
song-548,run2,evidence,"SITTIN' HERE, DRINKIN' BEER, TALKIN' GOD, AMEN","SITTIN’ HERE, DRINKIN’ BEER, TALKIN’ GOD, AMEN"
|
||||
song-548,run2,evidence,WHEN THE WORLD'S GONE CRAZY MAN IT ALL MAKES SENSE,WHEN THE WORLD’S GONE CRAZY MAN IT ALL MAKES SENSE
|
||||
song-548,run3,evidence,EVEN THOUGH IT'S A FRIDAY NIGHT,EVEN THOUGH IT’S A FRIDAY NIGHT
|
||||
song-548,run3,evidence,GOTTA COUNTRY ANGEL I DON'T DESERVE\nTHE KIND THAT YOU NEVER LET GO OF,GOTTA COUNTRY ANGEL I DON’T DESERVE\nTHE KIND THAT YOU NEVER LET GO OF
|
||||
song-548,run3,evidence,I AIN'T NEVER\nBEEN THE CHURCH GOING TYPE,I AIN’T NEVER\nBEEN THE CHURCH GOING TYPE
|
||||
song-548,run3,evidence,GOTTA COUNTRY ANGEL I DON'T DESERVE / THE KIND THAT YOU NEVER LET GO OF,GOTTA COUNTRY ANGEL I DON’T DESERVE / THE KIND THAT YOU NEVER LET GO OF
|
||||
song-548,run3,evidence,I AIN'T NEVER / BEEN THE CHURCH GOING TYPE,I AIN’T NEVER / BEEN THE CHURCH GOING TYPE
|
||||
song-548,run3,evidence,IF IT'S LIKE DOWN HERE UP THERE TONIGHT,IF IT’S LIKE DOWN HERE UP THERE TONIGHT
|
||||
song-548,run3,evidence,"SITTIN' HERE, DRINKIN' BEER, TALKIN' GOD, AMEN","SITTIN’ HERE, DRINKIN’ BEER, TALKIN’ GOD, AMEN"
|
||||
song-548,run3,evidence,WHEN THE WORLD'S GONE CRAZY MAN IT ALL MAKES SENSE,WHEN THE WORLD’S GONE CRAZY MAN IT ALL MAKES SENSE
|
||||
song-550,run1,evidence,Nothing to say\nAnd everything gets in the way,Nothin' to say\nAnd everything gets in the way
|
||||
song-550,run1,evidence,Nothing to say / And everything gets in the way,Nothin' to say / And everything gets in the way
|
||||
song-560,run1,evidence,"Tell me: That's life, when I'm stressin' at night","tell me: That's life, when I'm stressin' at night"
|
||||
song-560,run3,evidence,"Tell me: That's life, when I'm stressin' at night","tell me: That's life, when I'm stressin' at night"
|
||||
song-563,run1,evidence,All of the these sorries I don't owe you honey,All of the these sorries I don’t owe you honey
|
||||
@@ -649,8 +649,8 @@ song-563,run3,evidence,My heart wouldn't listen to my head and these boots on my
|
||||
song-563,run3,evidence,Sure as hell can't keep leanin' on you,Sure as hell can’t keep leanin’ on you
|
||||
song-563,run3,evidence,You're gone and I've gone 3 sheets to the wind,You’re gone and I’ve gone 3 sheets to the wind
|
||||
song-566,run2,evidence,Las de PR que todita' son mía',las de PR que todita' son mía'
|
||||
song-567,run1,evidence,"And if I only could, I'd make a deal with God,","And if I only could,\nI'd make a deal with God,"
|
||||
song-567,run2,evidence,"And if I only could, I'd make a deal with God,","And if I only could,\nI'd make a deal with God,"
|
||||
song-567,run1,evidence,"And if I only could, I'd make a deal with God,","And if I only could, / I'd make a deal with God,"
|
||||
song-567,run2,evidence,"And if I only could, I'd make a deal with God,","And if I only could, / I'd make a deal with God,"
|
||||
song-570,run1,evidence,"Stolen the pussy, you ain't get sued for that (Sued)","Stole the pussy, you ain't get sued for that (Sued)"
|
||||
song-570,run3,evidence,"Stolen the pussy, you ain't get sued for that (Sued)","Stole the pussy, you ain't get sued for that (Sued)"
|
||||
song-575,run1,evidence,Guess I'm just broken and broke,Guess I’m just broken and broke
|
||||
@@ -658,9 +658,9 @@ song-575,run2,evidence,Guess I'm just broken and broke,Guess I’m just broken a
|
||||
song-575,run3,evidence,Guess I'm just broken and broke,Guess I’m just broken and broke
|
||||
song-581,run1,evidence,To me you're all I am,to me you're all I am
|
||||
song-581,run2,evidence,To me you're all I am,to me you're all I am
|
||||
song-582,run1,evidence,I hope that your triflin' ass\nIs walkin' 'round barefoot in these streets,I also hope that your triflin' ass\nIs walkin' 'round barefoot in these streets
|
||||
song-582,run2,evidence,I hope that your triflin' ass\nIs walkin' 'round barefoot in these streets,I also hope that your triflin' ass\nIs walkin' 'round barefoot in these streets
|
||||
song-582,run3,evidence,I hope that your triflin' ass\nIs walkin' 'round barefoot in these streets,I also hope that your triflin' ass\nIs walkin' 'round barefoot in these streets
|
||||
song-582,run1,evidence,I hope that your triflin' ass / Is walkin' 'round barefoot in these streets,I also hope that your triflin' ass / Is walkin' 'round barefoot in these streets
|
||||
song-582,run2,evidence,I hope that your triflin' ass / Is walkin' 'round barefoot in these streets,I also hope that your triflin' ass / Is walkin' 'round barefoot in these streets
|
||||
song-582,run3,evidence,I hope that your triflin' ass / Is walkin' 'round barefoot in these streets,I also hope that your triflin' ass / Is walkin' 'round barefoot in these streets
|
||||
song-584,run1,evidence,Aún te debo una noche en la suite,aún te debo una noche en la suite
|
||||
song-584,run1,evidence,"Hoy tú no va' a trabajar, jeje, no","hoy tú no va' a trabajar, jeje, no"
|
||||
song-584,run1,evidence,"Yo no sé tú, pero yo quisiera amanecer esnú'","yo no sé tú, pero yo quisiera amanecer esnú'"
|
||||
@@ -670,15 +670,15 @@ song-584,run3,evidence,"Yo no sé tú, pero yo quisiera amanecer esnú'","yo no
|
||||
song-587,run1,evidence,"Bought her a P, not a pill, a Porsche","bought her a P, not a pill, a Porsche"
|
||||
song-587,run2,evidence,"Bought her a P, not a pill, a Porsche","bought her a P, not a pill, a Porsche"
|
||||
song-587,run3,evidence,"Bought her a P, not a pill, a Porsche","bought her a P, not a pill, a Porsche"
|
||||
song-588,run1,evidence,'Cause the truth about it is\nIt all goes by real quick,‘Cause the truth about it is\nIt all goes by real quick
|
||||
song-588,run1,evidence,'Cause the truth about it is / It all goes by real quick,‘Cause the truth about it is / It all goes by real quick
|
||||
song-588,run1,evidence,Find the one you can't live without,Find the one you can’t live without
|
||||
song-588,run1,evidence,You can't buy happiness\nBut you can buy dirt,You can’t buy happiness\nBut you can buy dirt
|
||||
song-588,run2,evidence,'Cause the truth about it is\nIt all goes by real quick,‘Cause the truth about it is\nIt all goes by real quick
|
||||
song-588,run1,evidence,You can't buy happiness / But you can buy dirt,You can’t buy happiness / But you can buy dirt
|
||||
song-588,run2,evidence,'Cause the truth about it is / It all goes by real quick,‘Cause the truth about it is / It all goes by real quick
|
||||
song-588,run2,evidence,Find the one you can't live without,Find the one you can’t live without
|
||||
song-588,run2,evidence,You can't buy happiness\nBut you can buy dirt,You can’t buy happiness\nBut you can buy dirt
|
||||
song-588,run3,evidence,'Cause the truth about it is\nIt all goes by real quick,‘Cause the truth about it is\nIt all goes by real quick
|
||||
song-588,run2,evidence,You can't buy happiness / But you can buy dirt,You can’t buy happiness / But you can buy dirt
|
||||
song-588,run3,evidence,'Cause the truth about it is / It all goes by real quick,‘Cause the truth about it is / It all goes by real quick
|
||||
song-588,run3,evidence,Find the one you can't live without,Find the one you can’t live without
|
||||
song-588,run3,evidence,You can't buy happiness\nBut you can buy dirt,You can’t buy happiness\nBut you can buy dirt
|
||||
song-588,run3,evidence,You can't buy happiness / But you can buy dirt,You can’t buy happiness / But you can buy dirt
|
||||
song-590,run1,evidence,He's not with you,he's not with you
|
||||
song-593,run1,evidence,Love's a smoke ring wrapped around your finger,love's a smoke ring wrapped around your finger
|
||||
song-593,run2,evidence,Love's a smoke ring wrapped around your finger,love's a smoke ring wrapped around your finger
|
||||
@@ -710,20 +710,20 @@ song-617,run3,evidence,"Hold up a minute, don't go","hold up a minute, don't go"
|
||||
song-622,run1,evidence,"Iба por mi camino y me perdí (Ey, ey)","Iba por mi camino y me perdí (Ey, ey)"
|
||||
song-622,run2,evidence,"Iба por mi camino y me perdí (Ey, ey)","Iba por mi camino y me perdí (Ey, ey)"
|
||||
song-622,run3,evidence,"Iба por mi camino y me perdí (Ey, ey)","Iba por mi camino y me perdí (Ey, ey)"
|
||||
song-625,run1,evidence,When I already know\nWhat she's thinkin'\nShe don't have to say it yeah,When I already know\n\nWhat she's thinkin'\nShe don't have to say it yeah
|
||||
song-625,run2,evidence,When I already know\nWhat she's thinkin'\nShe don't have to say it yeah,When I already know\n\nWhat she's thinkin'\nShe don't have to say it yeah
|
||||
song-625,run3,evidence,When I already know\nWhat she's thinkin'\nShe don't have to say it yeah,When I already know\n\nWhat she's thinkin'\nShe don't have to say it yeah
|
||||
song-625,run1,evidence,When I already know / What she's thinkin' / She don't have to say it yeah,When I already know / / What she's thinkin' / She don't have to say it yeah
|
||||
song-625,run2,evidence,When I already know / What she's thinkin' / She don't have to say it yeah,When I already know / / What she's thinkin' / She don't have to say it yeah
|
||||
song-625,run3,evidence,When I already know / What she's thinkin' / She don't have to say it yeah,When I already know / / What she's thinkin' / She don't have to say it yeah
|
||||
song-627,run1,evidence,"Damn Strait, you're killing me man","Damn Strait, you’re killing me man"
|
||||
song-627,run1,evidence,I couldn't turn it off fast enough,I couldn’t turn it off fast enough
|
||||
song-627,run1,evidence,I know it ain't your fault\nThat she left me,I know it ain’t your fault\nThat she left me
|
||||
song-627,run1,evidence,Now I can't even listen\n'Cause I'll get to missin' her,Now I can’t even listen\n‘Cause I’ll get to missin’ her
|
||||
song-627,run2,evidence,'Cause I'll get to missin' her\nThen thehurt gets worse,‘Cause I’ll get to missin’ her\nThen thehurt gets worse
|
||||
song-627,run2,evidence,I know it ain't your fault\nThat she left me,I know it ain’t your fault\nThat she left me
|
||||
song-627,run2,evidence,Now I can't even listen\n'Cause I'll get to missin' her\nThen thehurt gets worse,Now I can’t even listen\n‘Cause I’ll get to missin’ her\nThen thehurt gets worse
|
||||
song-627,run3,evidence,'Cause I'll get to missin' her\nThen thehurt gets worse,‘Cause I’ll get to missin’ her\nThen thehurt gets worse
|
||||
song-627,run1,evidence,I know it ain't your fault / That she left me,I know it ain’t your fault / That she left me
|
||||
song-627,run1,evidence,Now I can't even listen / 'Cause I'll get to missin' her,Now I can’t even listen / ‘Cause I’ll get to missin’ her
|
||||
song-627,run2,evidence,'Cause I'll get to missin' her / Then thehurt gets worse,‘Cause I’ll get to missin’ her / Then thehurt gets worse
|
||||
song-627,run2,evidence,I know it ain't your fault / That she left me,I know it ain’t your fault / That she left me
|
||||
song-627,run2,evidence,Now I can't even listen / 'Cause I'll get to missin' her / Then thehurt gets worse,Now I can’t even listen / ‘Cause I’ll get to missin’ her / Then thehurt gets worse
|
||||
song-627,run3,evidence,'Cause I'll get to missin' her / Then thehurt gets worse,‘Cause I’ll get to missin’ her / Then thehurt gets worse
|
||||
song-627,run3,evidence,"Damn Strait, you're killing me man","Damn Strait, you’re killing me man"
|
||||
song-627,run3,evidence,I know it ain't your fault\nThat she left me,I know it ain’t your fault\nThat she left me
|
||||
song-627,run3,evidence,Now I can't even listen\n'Cause I'll get to missin' her\nThen thehurt gets worse,Now I can’t even listen\n‘Cause I’ll get to missin’ her\nThen thehurt gets worse
|
||||
song-627,run3,evidence,I know it ain't your fault / That she left me,I know it ain’t your fault / That she left me
|
||||
song-627,run3,evidence,Now I can't even listen / 'Cause I'll get to missin' her / Then thehurt gets worse,Now I can’t even listen / ‘Cause I’ll get to missin’ her / Then thehurt gets worse
|
||||
song-630,run1,evidence,It's all gone to hell she's gone to her mom's,it's all gone to hell she's gone to her mom's
|
||||
song-630,run3,evidence,It's a bad day for love but a good day for flower shops,it's a bad day for love but a good day for flower shops
|
||||
song-630,run3,evidence,It's all gone to hell she's gone to her mom's,it's all gone to hell she's gone to her mom's
|
||||
@@ -747,41 +747,41 @@ song-641,run3,evidence,I'm findin' ways to manipulate the feelin' you're goin' t
|
||||
song-645,run1,evidence,I'm a Slaughter Gang CEO,It's a Slaughter Gang CEO
|
||||
song-645,run2,evidence,I'm a Slaughter Gang CEO,It's a Slaughter Gang CEO
|
||||
song-650,run1,evidence,See you're tired thinkin' 'bout if he cheat,see you're tired thinkin' 'bout if he cheat
|
||||
song-650,run1,evidence,Somebody who can open up those gates to your heart,Somebody who can open up those gates\nOpen up those gates to your heart
|
||||
song-650,run1,evidence,Somebody who can open up those gates to your heart,Somebody who can open up those gates / Open up those gates to your heart
|
||||
song-650,run1,evidence,"Someone to bring you peace, uh","someone to bring you peace, uh"
|
||||
song-650,run2,evidence,See you're tired thinkin' 'bout if he cheat,see you're tired thinkin' 'bout if he cheat
|
||||
song-650,run2,evidence,Somebody who can open up those gates to your heart,Somebody who can open up those gates\nOpen up those gates to your heart
|
||||
song-650,run2,evidence,Somebody who can open up those gates to your heart,Somebody who can open up those gates / Open up those gates to your heart
|
||||
song-650,run2,evidence,"Someone to bring you peace, uh","someone to bring you peace, uh"
|
||||
song-650,run3,evidence,See you're tired thinkin' 'bout if he cheat,see you're tired thinkin' 'bout if he cheat
|
||||
song-650,run3,evidence,"Someone to bring you peace, uh","someone to bring you peace, uh"
|
||||
song-654,run1,evidence,All my life\nThey been tryin' to keep me down,All my life)\nThey been tryin' to keep me down
|
||||
song-654,run2,evidence,All my life\nThey been tryin' to keep me down,All my life)\nThey been tryin' to keep me down
|
||||
song-654,run3,evidence,All my life\nThey been tryin' to keep me down,All my life)\nThey been tryin' to keep me down
|
||||
song-655,run3,evidence,"Le dije\n""Voy a conquistar tu familia""","Le dije\n""Voy a conquistar tu familia"
|
||||
song-661,run1,evidence,All they keep asking me\nIs if I'm gonna be your bride,all they keep asking me)\nIs if I'm gonna be your bride
|
||||
song-661,run1,evidence,The only kind of girl they see\nIs a one-night or a wife,the only kind of girl they see)\nIs a one-night or a wife
|
||||
song-661,run2,evidence,All they keep asking me is if I'm gonna be your bride,all they keep asking me)\nIs if I'm gonna be your bride
|
||||
song-661,run2,evidence,The only kind of girl they see is a one-night or a wife,the only kind of girl they see)\nIs a one-night or a wife
|
||||
song-661,run3,evidence,All they keep asking me is if I'm gonna be your bride,all they keep asking me)\nIs if I'm gonna be your bride
|
||||
song-661,run3,evidence,The only kind of girl they see is a one-night or a wife,the only kind of girl they see)\nIs a one-night or a wife
|
||||
song-666,run3,evidence,If you want me to stop some of that\nOr you want me to stop lovin' you?,You want me to stop some of that\nOr you want me to stop lovin' you?
|
||||
song-654,run1,evidence,All my life / They been tryin' to keep me down,All my life) / They been tryin' to keep me down
|
||||
song-654,run2,evidence,All my life / They been tryin' to keep me down,All my life) / They been tryin' to keep me down
|
||||
song-654,run3,evidence,All my life / They been tryin' to keep me down,All my life) / They been tryin' to keep me down
|
||||
song-655,run3,evidence,"Le dije / ""Voy a conquistar tu familia""","Le dije / ""Voy a conquistar tu familia"
|
||||
song-661,run1,evidence,All they keep asking me / Is if I'm gonna be your bride,all they keep asking me) / Is if I'm gonna be your bride
|
||||
song-661,run1,evidence,The only kind of girl they see / Is a one-night or a wife,the only kind of girl they see) / Is a one-night or a wife
|
||||
song-661,run2,evidence,All they keep asking me is if I'm gonna be your bride,all they keep asking me) / Is if I'm gonna be your bride
|
||||
song-661,run2,evidence,The only kind of girl they see is a one-night or a wife,the only kind of girl they see) / Is a one-night or a wife
|
||||
song-661,run3,evidence,All they keep asking me is if I'm gonna be your bride,all they keep asking me) / Is if I'm gonna be your bride
|
||||
song-661,run3,evidence,The only kind of girl they see is a one-night or a wife,the only kind of girl they see) / Is a one-night or a wife
|
||||
song-666,run3,evidence,If you want me to stop some of that / Or you want me to stop lovin' you?,You want me to stop some of that / Or you want me to stop lovin' you?
|
||||
song-671,run1,evidence,Your lovin' so deep,your lovin' so deep
|
||||
song-671,run2,evidence,Your lovin' so deep,your lovin' so deep
|
||||
song-672,run1,evidence,I'm feeling lonely (lonely),I’m feeling lonely (lonely)
|
||||
song-672,run1,evidence,I'm gonna make it mineI'm gonna make it mine,I’m gonna make it mineI’m gonna make it mine
|
||||
song-672,run2,evidence,I'm feeling lonely (lonely)I'm feeling lonely (lonely),I’m feeling lonely (lonely)I’m feeling lonely (lonely)
|
||||
song-672,run3,evidence,I'm feeling lonely (lonely)I'm feeling lonely (lonely),I’m feeling lonely (lonely)I’m feeling lonely (lonely)
|
||||
song-675,run1,evidence,Your left hand's gettin' used to that ring,your\nLeft hand's gettin' used to that ring
|
||||
song-675,run2,evidence,Your left hand's gettin' used to that ring,your\nLeft hand's gettin' used to that ring
|
||||
song-675,run1,evidence,Your left hand's gettin' used to that ring,your / Left hand's gettin' used to that ring
|
||||
song-675,run2,evidence,Your left hand's gettin' used to that ring,your / Left hand's gettin' used to that ring
|
||||
song-680,run1,evidence,I'm goin' to glow up one more time,I’m goin’ to glow up one more time
|
||||
song-680,run1,evidence,You gon' see me sleepin' in courtside,You gon' see me sleepin’ in courtside
|
||||
song-680,run2,evidence,I'm goin' to glow up one more time,I’m goin’ to glow up one more time
|
||||
song-680,run2,evidence,You gon' see me sleepin' in courtside,You gon' see me sleepin’ in courtside
|
||||
song-680,run3,evidence,I'm goin' to glow up one more time,I’m goin’ to glow up one more time
|
||||
song-680,run3,evidence,You gon' see me sleepin' in courtside,You gon' see me sleepin’ in courtside
|
||||
song-690,run2,evidence,So I'll keep dancing with my eyes closed,"So I'll keep dancing with my\nEy-ey-ey-eyes, ey-ey-ey-eyes closed"
|
||||
song-691,run2,evidence,Lo que ella no sabe es que tú todavía\nMe estás viendo toa' la' historia',Lo que ella no sabe es que tú todavía (au)\nMe estás viendo toa' la' historia'
|
||||
song-691,run3,evidence,Lo que ella no sabe es que tú todavía\nMe estás viendo toa' la' historia',Lo que ella no sabe es que tú todavía (au)\nMe estás viendo toa' la' historia'
|
||||
song-690,run2,evidence,So I'll keep dancing with my eyes closed,"So I'll keep dancing with my / Ey-ey-ey-eyes, ey-ey-ey-eyes closed"
|
||||
song-691,run2,evidence,Lo que ella no sabe es que tú todavía / Me estás viendo toa' la' historia',Lo que ella no sabe es que tú todavía (au) / Me estás viendo toa' la' historia'
|
||||
song-691,run3,evidence,Lo que ella no sabe es que tú todavía / Me estás viendo toa' la' historia',Lo que ella no sabe es que tú todavía (au) / Me estás viendo toa' la' historia'
|
||||
song-693,run2,evidence,He's got a smile that makes me forget,he's got a smile that makes me forget
|
||||
song-694,run1,evidence,and I just fell in love with a gangsta (like),And I just fell in love with a gangsta (like)
|
||||
song-694,run1,evidence,"and I'm young, still gettin' money my pockets is chubby, nothin' was the same (huh)","And I'm young, still gettin' money my pockets is chubby, nothin' was the same (huh)"
|
||||
@@ -811,17 +811,17 @@ song-695,run3,evidence,"All they doin' is talkin' down, 'cause they can't get up
|
||||
song-695,run3,evidence,"I can't put you in my business, you might wish me dead tomorrow","I can't put you in my business (No), you might wish me dead tomorrow"
|
||||
song-695,run3,evidence,"Ridin' with my twin and 'nem, and we all look good as fuck","Ridin' with my twin and 'nem (Skrrt), and we all look good as fuck"
|
||||
song-696,run3,evidence,"Desde que nos vimo' pienso en cómo nos comimo', ey","desde que nos vimo' pienso en cómo nos comimo', ey"
|
||||
song-697,run1,evidence,No quisiera que\nPase otro día y no te vea al amanecer,no quisiera que\nPase otro día y no te vea al amanecer
|
||||
song-697,run2,evidence,No quisiera que\nPase otro día y no te vea al amanecer,no quisiera que\nPase otro día y no te vea al amanecer
|
||||
song-697,run3,evidence,No quisiera que\nPase otro día y no te vea al amanecer,no quisiera que\nPase otro día y no te vea al amanecer
|
||||
song-697,run1,evidence,No quisiera que / Pase otro día y no te vea al amanecer,no quisiera que / Pase otro día y no te vea al amanecer
|
||||
song-697,run2,evidence,No quisiera que / Pase otro día y no te vea al amanecer,no quisiera que / Pase otro día y no te vea al amanecer
|
||||
song-697,run3,evidence,No quisiera que / Pase otro día y no te vea al amanecer,no quisiera que / Pase otro día y no te vea al amanecer
|
||||
song-703,run3,evidence,"Looks so alive, turns out, I'm not real","Looked so alive, turns out, I'm not real"
|
||||
song-705,run1,evidence,But if you kissed me now I know you'd fool me again,But if you kissed me now\nI know you'd fool me again
|
||||
song-705,run1,evidence,Last Christmas I gave you my heart,Last Christmas\nI gave you my heart
|
||||
song-705,run1,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone\nI'll give it to someone special
|
||||
song-705,run2,evidence,Last Christmas I gave you my heart,Last Christmas\nI gave you my heart
|
||||
song-705,run2,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone\nI'll give it to someone special
|
||||
song-705,run3,evidence,Last Christmas I gave you my heart,Last Christmas\nI gave you my heart
|
||||
song-705,run3,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone\nI'll give it to someone special
|
||||
song-705,run1,evidence,But if you kissed me now I know you'd fool me again,But if you kissed me now / I know you'd fool me again
|
||||
song-705,run1,evidence,Last Christmas I gave you my heart,Last Christmas / I gave you my heart
|
||||
song-705,run1,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone / I'll give it to someone special
|
||||
song-705,run2,evidence,Last Christmas I gave you my heart,Last Christmas / I gave you my heart
|
||||
song-705,run2,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone / I'll give it to someone special
|
||||
song-705,run3,evidence,Last Christmas I gave you my heart,Last Christmas / I gave you my heart
|
||||
song-705,run3,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone / I'll give it to someone special
|
||||
song-708,run3,evidence,"We'd never fade, never fade","we'd never fade, never fade"
|
||||
song-709,run1,evidence,He designered down (down),he designered down (down)
|
||||
song-711,run1,evidence,Y bien jalados con La Doble P,y bien jalados con La Doble P
|
||||
@@ -838,22 +838,22 @@ song-737,run3,evidence,When you wake up next to him in the middle of the night,w
|
||||
song-737,run3,evidence,You don't wanna call it love,you don't wanna call it love
|
||||
song-744,run2,evidence,She got a cold heart but she got a warm smile,she got a cold heart but she got a warm smile
|
||||
song-744,run3,evidence,She got a cold heart but she got a warm smile,she got a cold heart but she got a warm smile
|
||||
song-746,run1,evidence,Rugged whiskey\n'Cause we survivin',rugged whiskey)\n'Cause we survivin
|
||||
song-746,run2,evidence,Rugged whiskey\n'Cause we survivin',rugged whiskey)\n'Cause we survivin
|
||||
song-746,run3,evidence,Rugged whiskey\n'Cause we survivin',rugged whiskey)\n'Cause we survivin
|
||||
song-746,run1,evidence,Rugged whiskey / 'Cause we survivin',rugged whiskey) / 'Cause we survivin
|
||||
song-746,run2,evidence,Rugged whiskey / 'Cause we survivin',rugged whiskey) / 'Cause we survivin
|
||||
song-746,run3,evidence,Rugged whiskey / 'Cause we survivin',rugged whiskey) / 'Cause we survivin
|
||||
song-747,run1,evidence,Before it called you a lying traitor,before it called you a lying traitor
|
||||
song-747,run2,evidence,"Oh, lord, I think about jumpin' / Off of very tall somethings","Oh, lord, I think about jumpin'\nOff of very tall somethings"
|
||||
song-747,run2,evidence,"Oh, lord, I think about jumpin' / Off of very tall somethings","Oh, lord, I think about jumpin' / Off of very tall somethings"
|
||||
song-747,run2,evidence,You called you a lying traitor,You dream of my mouth before it called you a lying traitor
|
||||
song-750,run1,keyword,alcohol-and-substance-use,alcohol-and-substance-abuse
|
||||
song-750,run2,keyword,alcohol-and-substance-use,alcohol-and-substance-abuse
|
||||
song-750,run3,keyword,alcohol-and-substance-use,**REMOVE**
|
||||
song-753,run1,evidence,You're never gon' see me\nCaught sleepin',you're never gon' see me\nCaught sleepin'
|
||||
song-753,run1,evidence,You're never gon' see me / Caught sleepin',you're never gon' see me / Caught sleepin'
|
||||
song-753,run3,evidence,"You debate who the best, but opps, I'm white chalkin' when","you debate who the best, but opps, I'm white chalkin' when"
|
||||
song-755,run2,keyword,guilt-and-remorse,**REMOVE**
|
||||
song-755,run2,evidence,I'm\nIn my head right now,I'm\n\nIn my head right now
|
||||
song-759,run1,evidence,You just might get that G-Wagon out of me,You just might\nJust might get that G-Wagon out of me
|
||||
song-759,run2,evidence,You just might get that G-Wagon out of me,You just might\nJust might get that G-Wagon out of me
|
||||
song-759,run3,evidence,You just might get that G-Wagon out of me,You just might\nJust might get that G-Wagon out of me
|
||||
song-755,run2,evidence,I'm / In my head right now,I'm / / In my head right now
|
||||
song-759,run1,evidence,You just might get that G-Wagon out of me,You just might / Just might get that G-Wagon out of me
|
||||
song-759,run2,evidence,You just might get that G-Wagon out of me,You just might / Just might get that G-Wagon out of me
|
||||
song-759,run3,evidence,You just might get that G-Wagon out of me,You just might / Just might get that G-Wagon out of me
|
||||
song-763,run1,evidence,It wasn't no thing to give you up,it wasn't no thing to give you up
|
||||
song-775,run1,evidence,"Fuck y'all niggas, I don't trust y'all niggas","fuck y'all niggas, I don't trust y'all niggas"
|
||||
song-777,run1,evidence,They said he hit that guardrail at half past three,they said he hit that guardrail at half past three
|
||||
@@ -867,37 +867,37 @@ song-784,run2,evidence,"I'll be shooting that shot like 2K, girl, I know","I’l
|
||||
song-784,run2,evidence,"So I don't give a hoot what your dude say, girl, I know","So I don’t give a hoot what your dude say, girl, I know"
|
||||
song-784,run3,evidence,"I'll be shooting that shot like 2K, girl, I know","I’ll be shooting that shot like 2K, girl, I know"
|
||||
song-784,run3,evidence,"So I don't give a hoot what your dude say, girl, I know","So I don’t give a hoot what your dude say, girl, I know"
|
||||
song-785,run3,evidence,You always been a real one\nEven though we ain't together,you always been a real one\nEven though we ain't together
|
||||
song-785,run3,evidence,You always been a real one / Even though we ain't together,you always been a real one / Even though we ain't together
|
||||
song-787,run1,evidence,"If I catch you with her, you gon' catch me with him","If I catch you with her, you gon’ catch me with him"
|
||||
song-787,run1,evidence,Since the day that we met\nIt's always who cut first and never who bleeds last,Since the day that we met\nIt’s always who cut first and never who bleeds last
|
||||
song-787,run1,evidence,Since the day that we met / It's always who cut first and never who bleeds last,Since the day that we met / It’s always who cut first and never who bleeds last
|
||||
song-787,run1,evidence,"You think I don't hear about it, you better think again","You think I don’t hear about it, you better think again"
|
||||
song-787,run2,evidence,"If I catch you with her, you gon' catch me with him","If I catch you with her, you gon’ catch me with him"
|
||||
song-787,run2,evidence,Since the day that we met\nIt's always who cut first and never who bleeds last,Since the day that we met\nIt’s always who cut first and never who bleeds last
|
||||
song-787,run2,evidence,Since the day that we met / It's always who cut first and never who bleeds last,Since the day that we met / It’s always who cut first and never who bleeds last
|
||||
song-787,run2,evidence,"You think I don't hear about it, you better think again","You think I don’t hear about it, you better think again"
|
||||
song-787,run3,evidence,"If I catch you with her, you gon' catch me with him","If I catch you with her, you gon’ catch me with him"
|
||||
song-787,run3,evidence,It's always who cut first and never who bleeds last,It’s always who cut first and never who bleeds last
|
||||
song-787,run3,evidence,Since the day that we met\nIt's always who cut first and never who bleeds last,Since the day that we met\nIt’s always who cut first and never who bleeds last
|
||||
song-787,run3,evidence,Since the day that we met / It's always who cut first and never who bleeds last,Since the day that we met / It’s always who cut first and never who bleeds last
|
||||
song-787,run3,evidence,"You think I don't hear about it, you better think again","You think I don’t hear about it, you better think again"
|
||||
song-791,run1,evidence,"Singin' 'bout it don't mean I care\nYeah, I know I've been known to share","singin' 'bout it don't mean I care\nYeah, I know I've been known to share"
|
||||
song-791,run2,evidence,"Singin' 'bout it don't mean I care\nYeah, I know I've been known to share","singin' 'bout it don't mean I care\nYeah, I know I've been known to share"
|
||||
song-791,run1,evidence,"Singin' 'bout it don't mean I care / Yeah, I know I've been known to share","singin' 'bout it don't mean I care / Yeah, I know I've been known to share"
|
||||
song-791,run2,evidence,"Singin' 'bout it don't mean I care / Yeah, I know I've been known to share","singin' 'bout it don't mean I care / Yeah, I know I've been known to share"
|
||||
song-793,run1,evidence,Who wanna play with Nicki?,who wanna play with Nicki?
|
||||
song-793,run2,evidence,Who wanna play with Nicki?,who wanna play with Nicki?
|
||||
song-794,run1,evidence,Fell out of love and you both let go,fell out of love and you both let go
|
||||
song-794,run1,evidence,She couldn't be more different from me\nHappy and free in leather,she couldn't be more different from me\nHappy and free in leather
|
||||
song-794,run1,evidence,She couldn't be more different from me / Happy and free in leather,she couldn't be more different from me / Happy and free in leather
|
||||
song-794,run2,evidence,"Every time you touch me, I just wonder how she felt","every time you touch me, I just wonder how she felt"
|
||||
song-801,run1,evidence,"Pistols all in the kitchen, can't give the zip code up, hold up, yeah (Wow)","pistols all in the kitchen, can't give the zip code up, hold up, yeah (Wow)"
|
||||
song-802,run3,evidence,I don't remember life before she came into the picture,I don't remember\nLife before she came into the picture
|
||||
song-807,run2,evidence,I'm gonna keep on dancing at the Pink Pony Club,I'm gonna keep on dancing at the\nPink Pony Club
|
||||
song-807,run3,evidence,I'm gonna keep on dancing at the Pink Pony Club,I'm gonna keep on dancing at the\nPink Pony Club
|
||||
song-802,run3,evidence,I don't remember life before she came into the picture,I don't remember / Life before she came into the picture
|
||||
song-807,run2,evidence,I'm gonna keep on dancing at the Pink Pony Club,I'm gonna keep on dancing at the / Pink Pony Club
|
||||
song-807,run3,evidence,I'm gonna keep on dancing at the Pink Pony Club,I'm gonna keep on dancing at the / Pink Pony Club
|
||||
song-812,run2,evidence,"They'll play it one day, it's a hell of a show","They'll play it one day (Yeah), it's a hell of a show"
|
||||
song-812,run3,evidence,"They'll play it one day, it's a hell of a show","They'll play it one day (Yeah), it's a hell of a show"
|
||||
song-818,run1,evidence,We got sticks in the club illegally,we got sticks in the club illegally
|
||||
song-818,run2,evidence,We got sticks in the club illegally,we got sticks in the club illegally
|
||||
song-818,run3,evidence,We got sticks in the club illegally,we got sticks in the club illegally
|
||||
song-819,run2,evidence,Given the throne i don't know\nHow to believe,Given the throne i don't know (hah)\nHow to believe
|
||||
song-819,run3,evidence,Given the throne i don't know\nHow to believe,Given the throne i don't know (hah)\nHow to believe
|
||||
song-819,run2,evidence,Given the throne i don't know / How to believe,Given the throne i don't know (hah) / How to believe
|
||||
song-819,run3,evidence,Given the throne i don't know / How to believe,Given the throne i don't know (hah) / How to believe
|
||||
song-819,run3,evidence,Waisted so long to break these walls down,Waited so long to break these walls down
|
||||
song-819,run3,evidence,Waisted so long to break these walls down\nTo make up and feel like me,Waited so long to break these walls down\nTo make up and feel like me
|
||||
song-819,run3,evidence,Waisted so long to break these walls down / To make up and feel like me,Waited so long to break these walls down / To make up and feel like me
|
||||
song-821,run1,evidence,"okay, so yeah, I smoke like a chimney","Okay, so yeah, I smoke like a chimney"
|
||||
song-821,run2,evidence,"okay, so yeah, I smoke like a chimney","Okay, so yeah, I smoke like a chimney"
|
||||
song-821,run3,evidence,"okay, so yeah, I smoke like a chimney","Okay, so yeah, I smoke like a chimney"
|
||||
@@ -905,31 +905,31 @@ song-824,run2,evidence,"Said you'd never leave, we would fight 'til it's due","S
|
||||
song-829,run1,evidence,"It's my anxiety, can't let it conquer me","it's my anxiety, can't let it conquer me"
|
||||
song-829,run2,evidence,"It's my anxiety, can't let it conquer me","it's my anxiety, can't let it conquer me"
|
||||
song-829,run3,evidence,"It's my anxiety, can't let it conquer me","it's my anxiety, can't let it conquer me"
|
||||
song-833,run3,evidence,You met someone\nYour dad says he's okay,you met someone\nYour dad says he's okay
|
||||
song-833,run3,evidence,You met someone / Your dad says he's okay,you met someone / Your dad says he's okay
|
||||
song-842,run1,evidence,Pull off in a Lam',pull off in a Lam'
|
||||
song-847,run3,evidence,"You got me all, all, now I'm nodding my head","you got me all, all, now I'm nodding my head"
|
||||
song-849,run3,evidence,How could I ever miss something\nThat I'd never had?,How could I ever miss something (go)\nThat I'd never had?
|
||||
song-849,run3,evidence,How could I ever miss something / That I'd never had?,How could I ever miss something (go) / That I'd never had?
|
||||
song-850,run1,evidence,Made it clear you didn't wanna see the sequel,Made it clear you didn’t wanna see the sequel
|
||||
song-850,run2,evidence,Can't recall my mornings ever being this faded,Can’t recall my mornings ever being this faded
|
||||
song-850,run2,evidence,Made it clear you didn't wanna see the sequel,Made it clear you didn’t wanna see the sequel
|
||||
song-850,run3,evidence,Made it clear you didn't wanna see the sequel,Made it clear you didn’t wanna see the sequel
|
||||
song-852,run2,evidence,"He walked in\nLike a 6'2"" dream, heaven-sent","he walked in\nLike a 6'2"" dream, heaven-sent"
|
||||
song-852,run2,evidence,"He walked in / Like a 6'2"" dream, heaven-sent","he walked in / Like a 6'2"" dream, heaven-sent"
|
||||
song-853,run3,evidence,"Nothing to us, run up, you're done up, we come up from sunup to sundown, so come out to play","Nothin' to us, run up, you're done up, we come up from sunup to sundown, so come out to play"
|
||||
song-854,run2,evidence,She's in here chasing tequila with High Noon,she's in here chasing tequila with High Noon
|
||||
song-854,run2,evidence,"We did that ""What's your name"" thing\nWhere you from and what's your favorite drink","we did that ""What's your name"" thing\nWhere you from and what's your favorite drink"
|
||||
song-854,run2,evidence,"We did that ""What's your name"" thing / Where you from and what's your favorite drink","we did that ""What's your name"" thing / Where you from and what's your favorite drink"
|
||||
song-856,run1,evidence,If it was a different time,if it was a different time
|
||||
song-856,run2,evidence,If it was a different time,if it was a different time
|
||||
song-856,run3,evidence,If it was a different time,if it was a different time
|
||||
song-857,run1,evidence,Might be a lot of things\nBut I ain't your savin' grace,might be a lot of things\nBut I ain't your savin' grace
|
||||
song-857,run1,evidence,Might be a lot of things / But I ain't your savin' grace,might be a lot of things / But I ain't your savin' grace
|
||||
song-857,run1,evidence,"The night I said, ""I'm leavin',"" I turned into Richard Petty","the night I said, ""I'm leavin',"" I turned into Richard Petty"
|
||||
song-857,run2,evidence,Might be a lot of things\nBut I ain't your savin' grace,might be a lot of things\nBut I ain't your savin' grace
|
||||
song-857,run2,evidence,Might be a lot of things / But I ain't your savin' grace,might be a lot of things / But I ain't your savin' grace
|
||||
song-857,run2,evidence,"The night I said, ""I'm leavin',"" I turned into Richard Petty","the night I said, ""I'm leavin',"" I turned into Richard Petty"
|
||||
song-857,run3,evidence,Might be a lot of things\nBut I ain't your savin' grace,might be a lot of things\nBut I ain't your savin' grace
|
||||
song-857,run3,evidence,Might be a lot of things / But I ain't your savin' grace,might be a lot of things / But I ain't your savin' grace
|
||||
song-857,run3,evidence,"The night I said, ""I'm leavin',"" I turned into Richard Petty","the night I said, ""I'm leavin',"" I turned into Richard Petty"
|
||||
song-861,run2,evidence,All I ask is don't make my pull up and get to dumping,All I ask is don't make me pull up and get to dumping
|
||||
song-863,run1,evidence,"And I'm gonna love you, yeah","I'm gonna love you, yeah"
|
||||
song-867,run1,evidence,The struggle keeps me honest\nAnd it breaks down the walls of my pride,the struggle keeps me honest\nAnd it breaks down the walls of my pride
|
||||
song-867,run2,evidence,The struggle keeps me honest\nAnd it breaks down the walls of my pride,the struggle keeps me honest\nAnd it breaks down the walls of my pride
|
||||
song-867,run1,evidence,The struggle keeps me honest / And it breaks down the walls of my pride,the struggle keeps me honest / And it breaks down the walls of my pride
|
||||
song-867,run2,evidence,The struggle keeps me honest / And it breaks down the walls of my pride,the struggle keeps me honest / And it breaks down the walls of my pride
|
||||
song-872,run1,evidence,"Con reggaetón y dembow, sí, con reggaetón y dembow","con reggaetón y dembow, sí, con reggaetón y dembow"
|
||||
song-872,run2,evidence,"Con reggaetón y dembow, sí, con reggaetón y dembow","con reggaetón y dembow, sí, con reggaetón y dembow"
|
||||
song-872,run2,evidence,Pasan los año' y sigo dando palo',pasan los año' y sigo dando palo'
|
||||
|
||||
|
+106
-10
@@ -99,8 +99,8 @@
|
||||
|
||||
## 2026-08-02
|
||||
|
||||
- **`import-lyrics` 不設為子命令,pilot 歌詞改以私人腳本
|
||||
匯入**。理由:pilot 捕捉檔不隨論文發布,子命令
|
||||
- **`import-lyrics` 不設為子命令,pilot 歌詞改以 `excludes/`
|
||||
私人腳本匯入**。理由:pilot 捕捉檔不隨論文發布,子命令
|
||||
形式會在發布的 CLI 裡留下讀者無法執行的死命令——要交待的
|
||||
是「沿用 pilot 捕捉」的事實(記於 lyrics-provenance.csv 與
|
||||
論文方法節),不是工具本身;工具移出專案,發布管線即
|
||||
@@ -178,8 +178,8 @@
|
||||
來源公開可稽核,快照乾淨、overrides 縮小;論文方法節揭露
|
||||
「捕捉前經研究者查證補完」。性別以公開自我認同為準,
|
||||
推測不確定且無佐證者列疑慮清單;查證屬資料策展而非
|
||||
分析,以 Claude Code 輔助、不走分析 API;QS 批次以
|
||||
私人工作檔留存,不隨論文發布。
|
||||
分析,以 Claude Code 輔助、不走分析 API;QS 批次存
|
||||
`excludes/`(私人工作檔,不隨論文發布)。
|
||||
|
||||
## 2026-08-04
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
- **Markdown 檔名一律以 dash 連接**(decision-log.md、
|
||||
research-plan.md、project-structure.md 等;與 data/ 層
|
||||
CSV 檔名慣例一致),定義檔命名慣例同步改為
|
||||
`prompts/<task>-v<N>.md`(如 screen-v1.md),版本庫外的
|
||||
`prompts/<task>-v<N>.md`(如 screen-v1.md),`excludes/`
|
||||
私人工作檔一併改名;`conference_abstract.md` 改名並搬入
|
||||
`paper/`——它是本次年會實際送出的摘要,與全文同屬投稿
|
||||
血脈,不是 `docs/` 的內部工作文件。全 repo 指涉同步更新。
|
||||
@@ -583,8 +583,8 @@
|
||||
Billboard 署名 Pinkfong 為品牌(Wikidata Q55735607,型態
|
||||
brand),非演唱者;其唯一上榜曲 Baby Shark(2019#75)
|
||||
的實際演唱者為 Hope Segoine(KTVB 2019-03-06 報導、
|
||||
Songfacts、經紀簡介,出處詳私人留存的
|
||||
QuickStatements 草稿)。藉既有的
|
||||
Songfacts、經紀簡介,出處詳
|
||||
`excludes/quickstatements/hope-segoine.md`)。藉既有的
|
||||
署名正規化機制(`ArtistImporter.CANONICAL_ARTIST_NAMES`)
|
||||
指認:歌曲的署名字串維持榜單所印的 "Pinkfong",解析出
|
||||
的演出者實體為 Hope Segoine。品牌無性別可言,人有;
|
||||
@@ -637,9 +637,10 @@
|
||||
(sentence-transformers/all-mpnet-base-v2, revision
|
||||
e8c3b32e)對 `runs/02-cluster/source-keywords.txt` 的
|
||||
5,999 個關鍵字重新計算。組內一致性定義為組內成員兩兩
|
||||
餘弦相似度之平均。k=50 直接取自私人留存的分群結果;
|
||||
k=30 以同參數重跑(確定性演算法),重算所得最大組恰為
|
||||
491 詞,與當時粗算紀錄吻合,佐證重算與原實驗一致。數表:
|
||||
餘弦相似度之平均。k=50 直接取自留存的分群結果
|
||||
(`excludes/k50/02-cluster/groups.csv`);k=30 以同參數
|
||||
重跑(確定性演算法),重算所得最大組恰為 491 詞,與
|
||||
當時粗算紀錄吻合,佐證重算與原實驗一致。數表:
|
||||
|
||||
| | k=30 | k=50 | k=100 |
|
||||
|---|---|---|---|
|
||||
@@ -688,3 +689,98 @@
|
||||
檢定(women-power/female-empowerment 對三群之 2×2,
|
||||
Fisher 精確檢定,6 檢定一族之 BH-FDR 校正 q)之數字
|
||||
以本條所載分群為據,論文之編碼群表與群關聯表同此。
|
||||
|
||||
- **步驟 4:語意編碼群以三票制定案(claude-fable-5),
|
||||
取代草稿分群**:更正前條——所稱「研究者審定」實未
|
||||
發生,研究者僅將盲選輸出整理歸檔,未作實質裁決;草稿
|
||||
分群(單次 Claude Code 盲選)不具方法學地位。裁定
|
||||
步驟 4 為語意分群的正式程序。任務與盲選同構:每筆輸入
|
||||
為群名加 101 碼字母序清單,輸出為入選碼的單層 JSON
|
||||
陣列;定義檔 `prompts/04-group.md` 只定格式、不含群的
|
||||
語意定義。模型裁定 claude-fable-5:模型對照實驗(同
|
||||
定義檔、同輸入、Batch API)顯示分群對模型高度敏感——
|
||||
claude-sonnet-4-6 將群名成份式拆讀(women+power,凡
|
||||
力量語意即入選,women-power 群 11 碼,並產詞彙表外
|
||||
幻覺碼一筆),claude-fable-5 讀為詞彙化概念(要求女性
|
||||
標記,women-power 群 2 碼),與草稿盲選及深度閱讀輔助
|
||||
判讀同讀法;sonnet 對照執行歸檔備份於
|
||||
`excludes/experiments/`,支出留帳。claude-fable-5 不
|
||||
受理 temperature 與 thinking 參數(均不送出),無法釘
|
||||
temperature=0;執行間變異實測存在(run1/run2 於陽剛、
|
||||
脆弱邊緣碼分歧),由三票多數決吸收;詞彙表外輸出項
|
||||
無效。三次執行(`runs/04-group/run1`–`run3`)多數決
|
||||
定案(22 個(群,碼)中 21 個三次全票,
|
||||
family-and-fatherhood 以 2:1 入群):女性力量群 2 碼
|
||||
——female-empowerment、women-power;厭女群 1 碼——
|
||||
rejection-of-women;陽剛男性氣質群 9 碼——
|
||||
dominance-and-power、family-and-fatherhood、
|
||||
hustle-and-money、rivalry-and-superiority、
|
||||
self-confidence-and-braggadocio、
|
||||
showing-off-and-impressing、street-loyalty-and-danger、
|
||||
violence-and-street-danger、wealth-and-flexing;脆弱群
|
||||
10 碼——disappointment-and-failure、
|
||||
fear-of-losing-love、heartbreak-and-grief、
|
||||
hidden-emotional-struggle、inner-mental-turmoil、
|
||||
loneliness-and-isolation、longing-and-loss、
|
||||
past-trauma-and-healing、self-worth-and-insecurity、
|
||||
vulnerability-and-betrayal。計票由確定性子命令
|
||||
`tally-groups` 重現,定案寫入 `results/groups.csv`
|
||||
(群、編碼、票數);論文之編碼群表、上標註記與群層次
|
||||
檢定改以本定案為據,相關數表隨之重算。
|
||||
|
||||
## 2026-08-15
|
||||
|
||||
- **引述換行表示法改為歌詞慣例「 / 」,全鏈路一致、不再
|
||||
還原**:原設計以兩字元 `\n` 轉義表示引述內換行(定案表
|
||||
與更正表),build-db 匯入時還原為換行字元。改為:執行
|
||||
紀錄載入時一次將換行換成「 / 」,此後更正表比對、定案
|
||||
表(`results/codings.csv`)與工作儲存皆同一表示法,
|
||||
`tally-codings` 的轉義與 `build-db` 的還原一併移除。
|
||||
查核:全 883 首歌詞窮舉不含「 / 」,慣例於本語料無歧義
|
||||
(語料事實,非結構保證,換語料須重查);模型輸出本就有
|
||||
自發以「 / 」連接跨行的引述(song-211、song-747,原以
|
||||
更正表改回換行,今其方向與慣例一致,該三列僅餘大小寫與
|
||||
括號修正之效);兩首歌之演出者署名含「 / 」,惟欄位
|
||||
各自獨立,不涉引述欄。遷移:更正表 192 列 334 處轉義
|
||||
逐一替換;定案表重新計票,與舊檔之逐位元差異恰為
|
||||
`\n`→「 / 」(14,664 列不變,含「 / 」之引述 1,658
|
||||
筆);工作儲存重建後引述零換行字元。
|
||||
|
||||
- **定案分群匯入工作儲存**:`build-db` 增 `--groups` 選項,
|
||||
將 `results/groups.csv` 逐欄照存入 `groups` 資料表(群、
|
||||
編碼、票數),納入重建摘要與清空範圍,供群層次查詢;
|
||||
重建命令自此帶 `--groups results/groups.csv`。
|
||||
|
||||
- **Fable 5 輔助判讀實驗總錄(非正式編碼;結果檔於
|
||||
gitignored 之 `excludes/`,本條為其版本庫內的程序
|
||||
錨點)**:2026-08-08 起以 Claude Code subagent(模型
|
||||
Fable 5)進行七項深度閱讀實驗。共同程序:每首歌一個
|
||||
獨立會話、提示最少化且逐字統一、判讀者互不知情、不經
|
||||
三票制;定位為研究者的輔助判讀(初篩),不改動任何
|
||||
定案資料。各項(日期依結果檔時間):
|
||||
(1) women-power 66 首深度閱讀,含網路脈絡重讀與研究者
|
||||
註記(至 2026-08-09;`women-power-66-deep-reading.ods`)。
|
||||
(2) 145 首(wp∪fe 聯集)雙任務盲讀:每首兩個獨立
|
||||
subagent,任務一純文本、任務二上網查演唱者歷史與創作
|
||||
脈絡(2026-08-09;`women-power-145-blind-readings.ods`)。
|
||||
(3) 全語料 883 首純文本深讀:摘要、女性主義解讀、
|
||||
wp 判定,判「真」76 首(2026-08-10)。
|
||||
(4) 脈絡深讀合計 152 首(145 聯集+文本深讀新增 7 首),
|
||||
判「真」98 首(含聯集外 5 首);三層判定(管線 66/
|
||||
文本 76/脈絡 98)與八種分歧樣態記於
|
||||
`blind-readings-883.ods`;(3)(4) 合計 1,035 個獨立會話
|
||||
(145×2+738+7)。
|
||||
(5) pussy 作女性代稱判讀:字串比對 85 首候選,逐首
|
||||
判讀 41 首成立;判準(資源型轉喻)與邊界案例由研究者
|
||||
裁決(2026-08-10;`pussy-metonymy-85.csv` 與主檔該欄)。
|
||||
(6) wp+fe 65 首 vs 僅 fe 79 首之敘事差異分析:歸納七條
|
||||
系統性差異,引句全數逐字校對(2026-08-14;
|
||||
`wp65-vs-fe79-analysis.md`);論文研究結果之差異列點與
|
||||
例證出於此。
|
||||
(7) wp/fe 中演唱者 male/mixed 47 首之女性主義問題深讀:
|
||||
每首獨立 subagent、提示逐字相同、只讀歌詞欄,42 首回報
|
||||
問題、5 首「無」,問題歸納為八樣態(2026-08-15;
|
||||
`male-mixed-wp-fe-feminist-reading.md` 與同名 .ods)。
|
||||
此系列即論文方法節「最後編碼的結果,再由研究者與 LLM
|
||||
(Claude Code)輔助判讀」之所指;結果檔含大量歌詞引文,
|
||||
依著作權紀律留置 `excludes/`,不入版本庫。
|
||||
|
||||
+47
-14
@@ -6,17 +6,18 @@
|
||||
|
||||
## 自然編碼管線總覽
|
||||
|
||||
三個步驟:步驟 1 自由標註(兩次執行進池)→ 步驟 2 詞彙表
|
||||
四個步驟:步驟 1 自由標註(兩次執行進池)→ 步驟 2 詞彙表
|
||||
建構(詞向量分群,確定性)→ 步驟 3 全量編碼(三次執行+
|
||||
多數決)。歌詞只出現在步驟 1 與步驟 3;步驟 2 完全不接觸
|
||||
歌詞,也不呼叫 LLM。設計原則見 `research-plan.md`;本檔
|
||||
多數決)→ 步驟 4 語意編碼群(三次執行+多數決)。歌詞只
|
||||
出現在步驟 1 與步驟 3;步驟 2 與步驟 4 完全不接觸歌詞,
|
||||
步驟 2 亦不呼叫 LLM。設計原則見 `research-plan.md`;本檔
|
||||
記載可重現的演算法細節。
|
||||
|
||||
編號的所指為**研究程序的工序**,不是定義檔:步驟 1 與
|
||||
步驟 3 有定義檔(`prompts/`),步驟 2 沒有——它是單一
|
||||
確定性計算,由 `cluster-keywords` 一個子命令完成。有無
|
||||
定義檔的區別即「該步是否為 LLM 判斷」,由 `prompts/` 是
|
||||
否存在同號檔案直接可見。
|
||||
編號的所指為**研究程序的工序**,不是定義檔:步驟 1、
|
||||
步驟 3 與步驟 4 有定義檔(`prompts/`),步驟 2 沒有——
|
||||
它是單一確定性計算,由 `cluster-keywords` 一個子命令
|
||||
完成。有無定義檔的區別即「該步是否為 LLM 判斷」,由
|
||||
`prompts/` 是否存在同號檔案直接可見。
|
||||
|
||||
## 步驟 2 詞彙表建構——詞向量分群
|
||||
|
||||
@@ -113,6 +114,34 @@
|
||||
0.7 者為 0.78,0.9 者為 0.97),程序重跑的一致性因而
|
||||
高於單次執行,唯獨恰半處無從改善。
|
||||
|
||||
## 步驟 4 語意編碼群
|
||||
|
||||
- **對象**:將 101 個編碼依語意劃入研究者命名的四個編碼
|
||||
群——女性力量(women-power group)、反女性力量/厭女
|
||||
(misogyny group)、陽剛男性氣質(masculine group)、
|
||||
脆弱(vulnerable group)。群只有名字,沒有定義;歸屬
|
||||
由 LLM 依編碼名的字面語意判斷。
|
||||
- **任務**:每筆輸入為一個群名加 101 個編碼的字母序
|
||||
清單,輸出為入選編碼的單層 JSON 陣列;定義檔
|
||||
`prompts/04-group.md` 只定格式,不含任何群的語意定義。
|
||||
- **模型**:`claude-fable-5`(步驟 1、3 為
|
||||
`claude-sonnet-4-6`)。該模型不受理 `temperature` 與
|
||||
`thinking` 參數,兩者均不送出;取樣變異由多數決吸收。
|
||||
模型裁定的理由與對照實驗見決策日誌。
|
||||
- **三次執行**:同一份定義檔、同一份輸入檔,獨立執行
|
||||
三次,歸檔並列(`runs/04-group/run1`、`run2`、`run3`)。
|
||||
- **多數決**:一個(群,編碼)配對,三次執行中至少兩次
|
||||
入選即屬該群;不在 101 碼詞彙表內的輸出項無效,每筆
|
||||
丟棄印於標準錯誤。計票由確定性子命令 `tally-groups`
|
||||
完成:`tally-groups <執行歸檔 1> <執行歸檔 2> <執行歸檔
|
||||
3> <合法碼清單> <輸出 CSV>`,合法碼清單之產法同步驟 3。
|
||||
定案分群寫入 `results/groups.csv`,欄位 `Group`、
|
||||
`Keyword`、`Votes`,列序先依群名、再依編碼,一律以
|
||||
Unicode 碼位比較,換行為 CRLF。
|
||||
- **工作儲存**:`build-db --groups <定案分群 CSV>` 將定案
|
||||
分群逐欄照存入 `groups` 資料表(群、編碼、票數),供
|
||||
群層次查詢。
|
||||
|
||||
## 女性力量候選集
|
||||
|
||||
候選集為兩類歌曲的合集:定案編碼含 `women-power` 者,
|
||||
@@ -159,8 +188,9 @@
|
||||
或 `evidence`,分別更正標籤與引述;`Correct Term` 為
|
||||
替代字串,或 `**REMOVE**` 表示刪去該筆標籤指派(`keyword`)
|
||||
或該句引述(`evidence`)。一筆 `evidence` 更正套用於該
|
||||
首歌該次執行的所有出現處。兩個文字欄以兩字元 `\n` 表示
|
||||
換行,故一列一行,純文字工具可逐列處理。表中任一列若
|
||||
首歌該次執行的所有出現處。兩個文字欄以歌詞慣例「 / 」
|
||||
表示換行(與載入後的執行紀錄同一表示法,逐字比對、不再
|
||||
轉換),故一列一行,純文字工具可逐列處理。表中任一列若
|
||||
在資料中找不到對應者,即中止;校定的判準記於
|
||||
`decision-log.md`。
|
||||
- **合法碼清單**:純文字、一行一個碼,自詞彙表產出:
|
||||
@@ -172,9 +202,12 @@
|
||||
`build-db` 之後執行。`Quote` 為該標籤在計票中各份執行
|
||||
所引的歌詞行:各份的引述串接後逐字去重,按 Unicode
|
||||
碼位排序,以單一 `|` 相接(三份執行彼此無先後主從之
|
||||
別,引述之序取決於引述本身);`Quote` 欄以兩字元 `\n`
|
||||
表示換行,故一列一行,還原 `\n` 後即為該首歌歌詞的逐字
|
||||
片段。列序依印出的前三欄依序排:歌名、演出者名銜、
|
||||
別,引述之序取決於引述本身);引述內的換行於執行紀錄
|
||||
載入時一次換成歌詞慣例「 / 」,此後更正表、定案表與
|
||||
工作儲存全鏈路同一表示法,不再還原。「 / 」的無歧義性
|
||||
是語料事實而非結構保證:全 883 首歌詞經窮舉查核不含
|
||||
「 / 」;換語料須重查。列序依印出的前三欄依序排:
|
||||
歌名、演出者名銜、
|
||||
標籤,一律以 Unicode 碼位比較,換行為 CRLF(同專案
|
||||
其他 CSV)。
|
||||
- **序列化通則**:所有中間檔為 UTF-8,欄序、鍵序與元素
|
||||
@@ -188,7 +221,7 @@
|
||||
|
||||
- LLM 步驟以 `run-llm <定義檔> <輸入檔> <歸檔目錄>`
|
||||
執行;一步的 N 次執行=重現命令清單上的 N 行命令,
|
||||
各自歸檔(`runs/<步驟>/run1`、`run2`,編碼步驟另有
|
||||
各自歸檔(`runs/<步驟>/run1`、`run2`,三票制步驟另有
|
||||
`run3`)。
|
||||
- 確定性步驟(進池、分群、計票、對映)為子命令,其
|
||||
輸入輸出檔同隨 `runs/` 歸檔;因無執行變異,歸檔目錄
|
||||
|
||||
@@ -81,7 +81,7 @@ pop-fem-audit/
|
||||
│ └── methodology.md # 方法細節(全文方法節底稿;
|
||||
│ # 映射分析方法須在看結果前寫定)
|
||||
└── paper/
|
||||
├── abstract.md # 摘要
|
||||
├── conference-abstract.md # pilot 摘要(投稿版)
|
||||
└── full-paper.md # 全文
|
||||
```
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
- **研究敘事**:全文為獨立完整的正式研究(2016–2025 十年語料
|
||||
共 1000 筆榜單紀錄,凍結程序後全量執行),**不與先導研究
|
||||
做比較**;全文數字一律以正式研究
|
||||
(paper/conference-abstract.md)做比較**;全文數字一律以正式研究
|
||||
結果為準。先導研究僅作為 codebook v0 與假說的內部來源,
|
||||
記於決策日誌,不進入論文敘事。
|
||||
- **執行原則**:主會話只做討論;所有分析由 deterministic script
|
||||
@@ -75,8 +75,8 @@
|
||||
候選歌曲的歌手另做深度背景(族裔以公開自我認同為準、音樂
|
||||
場景),script 輔助、人工核定。
|
||||
- **Pilot 歌詞沿用(私人匯入,不進發布管線)**:先導研究
|
||||
捕捉檔(lyrics.json,684 首,2018–2025)以私人腳本
|
||||
匯入歌詞快取——只取識別欄位與歌詞本文,以
|
||||
捕捉檔(lyrics.json,684 首,2018–2025)以 `excludes/` 的
|
||||
私人腳本匯入歌詞快取——只取識別欄位與歌詞本文,以
|
||||
(year, rank) 精確匹配 song_id。匯入工具不屬於專案交付物
|
||||
(讀者拿不到其輸入),讀者的重現路徑純粹是 `fetch-lyrics`;
|
||||
沿用之**事實**記於 `data/captures/lyrics-provenance.csv`(進 git):
|
||||
@@ -164,11 +164,15 @@
|
||||
與「貶低其他女性/以男性指標定義權力」。
|
||||
- 流程:v0 → 校準樣本試編 → 修訂 → 凍結 v1 → 全量編碼;
|
||||
中途修訂須記決策日誌並回檢已編歌曲。
|
||||
- Positionality statement 寫入論文(53 歲、長年婦運者、資深
|
||||
工程師、離開學術圈多年、因整理榜單而起)。
|
||||
|
||||
## 其他已定案事項
|
||||
|
||||
- 歌詞受版權保護:完整歌詞不進 git(`data/captures/lyrics/` gitignored),
|
||||
論文與 repo 只留分類所引摘錄。
|
||||
- 工程支援(寫 script、style check、審稿)用公司訂閱的
|
||||
Claude Code;進論文的分析 token 由個人 API 帳號支付。
|
||||
- Fable 5 不用於 pipeline:成本高、thinking 無法關閉且不可稽核、
|
||||
無 temperature 控制,且會混淆「盲點是提示問題」的核心主張。
|
||||
(2026-08-05 實測確認:Claude 5 系模型拒收 temperature
|
||||
|
||||
+6
-1
@@ -39,5 +39,10 @@ $3/$15、opus-4-6 $5/$25、opus-5 與 fable-5 $10/$50)
|
||||
| 2026-08-06 | 03-02-arbitration | — | claude-sonnet-4-6 | msgbatch_019xcQXwrbwDGFc9nE5M8AjE | 4 分 0 秒 | 763,193 | 42,389 | $1.46 | 已取代(2 首遭內容過濾攔阻、13 首輸出夾帶散文;定義檔修訂後重跑) |
|
||||
| 2026-08-06 | 03-02-arbitration | — | claude-sonnet-4-6 | msgbatch_01N7bDbXRSfAVUzzaj2thKeR | 4 分 20 秒 | 781,037 | 39,315 | $1.47 | 現行(644 首全數有效,零攔阻;保留 1,481/送裁 1,699) |
|
||||
| 2026-08-06 | 03-code | run3 | claude-sonnet-4-6 | msgbatch_01KnkCaGETnFJrPddrxZTYHA | 6 分 26 秒 | 1,625,458 | 363,840 | $5.17 | 現行(101 碼;883 首全數有效,零攔阻) |
|
||||
| 2026-08-14 | 04-group | run1 | claude-sonnet-4-6 | msgbatch_01UPNedog6feQzJ9WVfSAxBD | 1 分 1 秒 | 3,129 | 470 | $0.01 | 已取代(僅 3 群;改納 women-power 群後重跑) |
|
||||
| 2026-08-14 | 04-group | run1 | claude-sonnet-4-6 | msgbatch_01KntJgxdicStaMjNL12P3zi | 1 分 25 秒 | 4,170 | 558 | $0.01 | 已取代(改以 claude-fable-5 執行;vulnerable 輸出含詞彙表外碼 1 筆;歸檔備份於 excludes/experiments/) |
|
||||
| 2026-08-14 | 04-group | run1 | claude-fable-5 | msgbatch_01Mr6goBb2Efa4YrqCprbP4U | 55 秒 | 5,553 | 2,049 | $0.08 | 現行(4 群;零違規碼;temperature 與 thinking 參數不適用於本模型,未送出) |
|
||||
| 2026-08-14 | 04-group | run2 | claude-fable-5 | msgbatch_01C17xW3YBefThTYZ83g7KkL | 1 分 21 秒 | 5,553 | 1,891 | $0.08 | 現行(4 群;零違規碼) |
|
||||
| 2026-08-14 | 04-group | run3 | claude-fable-5 | msgbatch_01DveEMYyjCAYe6wxpcCD87V | 2 分 9 秒 | 5,553 | 1,975 | $0.08 | 現行(4 群;零違規碼) |
|
||||
|
||||
累計支出:$63.22。
|
||||
累計支出:$63.48。
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
You are selecting thematic keywords that belong to a named
|
||||
group.
|
||||
|
||||
Input: a JSON object with the name of one group and the
|
||||
keywords — the complete set of codes; use these and no
|
||||
others:
|
||||
|
||||
{
|
||||
"group": "the name of the group",
|
||||
"keywords": ["first-keyword", "second-keyword"]
|
||||
}
|
||||
|
||||
Task: list every given keyword that belongs to the named
|
||||
group, judged by the literal meaning of the keyword itself.
|
||||
|
||||
Rules:
|
||||
|
||||
- Use only the given keywords, spelled exactly as given.
|
||||
- A group may match any number of keywords, including none.
|
||||
- Judge each keyword only by the literal meaning of its own
|
||||
wording.
|
||||
|
||||
Do not wrap the output in a Markdown code fence.
|
||||
The output must be strictly valid JSON.
|
||||
|
||||
Output a single JSON array of the keywords that belong to
|
||||
the group (an empty array when none belongs), and nothing
|
||||
else:
|
||||
|
||||
["first-keyword", "second-keyword"]
|
||||
+1658
-1658
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
Group,Keyword,Votes
|
||||
masculine,dominance-and-power,3
|
||||
masculine,family-and-fatherhood,2
|
||||
masculine,hustle-and-money,3
|
||||
masculine,rivalry-and-superiority,3
|
||||
masculine,self-confidence-and-braggadocio,3
|
||||
masculine,showing-off-and-impressing,3
|
||||
masculine,street-loyalty-and-danger,3
|
||||
masculine,violence-and-street-danger,3
|
||||
masculine,wealth-and-flexing,3
|
||||
misogyny,rejection-of-women,3
|
||||
vulnerable,disappointment-and-failure,3
|
||||
vulnerable,fear-of-losing-love,3
|
||||
vulnerable,heartbreak-and-grief,3
|
||||
vulnerable,hidden-emotional-struggle,3
|
||||
vulnerable,inner-mental-turmoil,3
|
||||
vulnerable,loneliness-and-isolation,3
|
||||
vulnerable,longing-and-loss,3
|
||||
vulnerable,past-trauma-and-healing,3
|
||||
vulnerable,self-worth-and-insecurity,3
|
||||
vulnerable,vulnerability-and-betrayal,3
|
||||
women-power,female-empowerment,3
|
||||
women-power,women-power,3
|
||||
|
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"script_version": "run_llm.py 3.0.0",
|
||||
"model": "claude-fable-5",
|
||||
"temperature": null,
|
||||
"thinking": null,
|
||||
"max_tokens": 8192,
|
||||
"prompt_path": "../prompts/04-group.md",
|
||||
"prompt_sha256": "50e1d5d6c4115d090ae4ab1e801ea74db0b2dcdd47213ce0feb6749e034a41e9",
|
||||
"input_path": "instance/llm-input-group.jsonl",
|
||||
"input_sha256": "7fd97ae165270cb91461aedf411050892667b928d8584fceffea6f9649e003c7",
|
||||
"item_count": 4,
|
||||
"dry_run": false,
|
||||
"started_at": "2026-08-14T22:30:32+08:00",
|
||||
"batch": {
|
||||
"batch_id": "msgbatch_01Mr6goBb2Efa4YrqCprbP4U",
|
||||
"submitted_at": "2026-08-14T22:30:34+08:00",
|
||||
"ended_at": "2026-08-14T14:31:27.547545+00:00"
|
||||
},
|
||||
"usage": {
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0,
|
||||
"input_tokens": 5553,
|
||||
"output_tokens": 2049
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{"id": "group-women-power", "text": "[\"female-empowerment\", \"women-power\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1385, "output_tokens": 53, "output_tokens_details": {"thinking_tokens": 37}, "service_tier": "batch"}}
|
||||
{"id": "group-misogyny", "text": "[\"rejection-of-women\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1391, "output_tokens": 118, "output_tokens_details": {"thinking_tokens": 106}, "service_tier": "batch"}}
|
||||
{"id": "group-masculine", "text": "[\"avoiding-commitment\", \"dominance-and-power\", \"hustle-and-money\", \"rejection-of-women\", \"rivalry-and-superiority\", \"self-confidence-and-braggadocio\", \"showing-off-and-impressing\", \"street-loyalty-and-danger\", \"violence-and-street-danger\", \"wealth-and-flexing\", \"wealth-and-material-success\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1390, "output_tokens": 1201, "output_tokens_details": {"thinking_tokens": 1076}, "service_tier": "batch"}}
|
||||
{"id": "group-vulnerable", "text": "[\"disappointment-and-failure\", \"fear-of-losing-love\", \"heartbreak-and-grief\", \"hidden-emotional-struggle\", \"inner-mental-turmoil\", \"loneliness-and-isolation\", \"longing-and-loss\", \"past-trauma-and-healing\", \"self-worth-and-insecurity\", \"vulnerability-and-betrayal\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1387, "output_tokens": 677, "output_tokens_details": {"thinking_tokens": 555}, "service_tier": "batch"}}
|
||||
@@ -0,0 +1,30 @@
|
||||
You are selecting thematic keywords that belong to a named
|
||||
group.
|
||||
|
||||
Input: a JSON object with the name of one group and the
|
||||
keywords — the complete set of codes; use these and no
|
||||
others:
|
||||
|
||||
{
|
||||
"group": "the name of the group",
|
||||
"keywords": ["first-keyword", "second-keyword"]
|
||||
}
|
||||
|
||||
Task: list every given keyword that belongs to the named
|
||||
group, judged by the literal meaning of the keyword itself.
|
||||
|
||||
Rules:
|
||||
|
||||
- Use only the given keywords, spelled exactly as given.
|
||||
- A group may match any number of keywords, including none.
|
||||
- Judge each keyword only by the literal meaning of its own
|
||||
wording.
|
||||
|
||||
Do not wrap the output in a Markdown code fence.
|
||||
The output must be strictly valid JSON.
|
||||
|
||||
Output a single JSON array of the keywords that belong to
|
||||
the group (an empty array when none belongs), and nothing
|
||||
else:
|
||||
|
||||
["first-keyword", "second-keyword"]
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"script_version": "run_llm.py 3.1.0",
|
||||
"model": "claude-fable-5",
|
||||
"temperature": null,
|
||||
"thinking": null,
|
||||
"max_tokens": 8192,
|
||||
"prompt_path": "../prompts/04-group.md",
|
||||
"prompt_sha256": "50e1d5d6c4115d090ae4ab1e801ea74db0b2dcdd47213ce0feb6749e034a41e9",
|
||||
"input_path": "instance/llm-input-group.jsonl",
|
||||
"input_sha256": "7fd97ae165270cb91461aedf411050892667b928d8584fceffea6f9649e003c7",
|
||||
"item_count": 4,
|
||||
"dry_run": false,
|
||||
"started_at": "2026-08-14T23:36:03+08:00",
|
||||
"batch": {
|
||||
"batch_id": "msgbatch_01C17xW3YBefThTYZ83g7KkL",
|
||||
"submitted_at": "2026-08-14T23:36:04+08:00",
|
||||
"ended_at": "2026-08-14T15:37:24.008527+00:00"
|
||||
},
|
||||
"usage": {
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0,
|
||||
"input_tokens": 5553,
|
||||
"output_tokens": 1891
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{"id": "group-women-power", "text": "[\"female-empowerment\", \"women-power\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1385, "output_tokens": 62, "output_tokens_details": {"thinking_tokens": 46}, "service_tier": "batch"}}
|
||||
{"id": "group-misogyny", "text": "[\"rejection-of-women\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1391, "output_tokens": 129, "output_tokens_details": {"thinking_tokens": 117}, "service_tier": "batch"}}
|
||||
{"id": "group-masculine", "text": "[\"ambition-and-self-determination\", \"confidence-and-self-assurance\", \"dominance-and-power\", \"family-and-fatherhood\", \"hustle-and-money\", \"relentless-ambition\", \"rivalry-and-superiority\", \"self-confidence-and-braggadocio\", \"showing-off-and-impressing\", \"street-loyalty-and-danger\", \"violence-and-street-danger\", \"wealth-and-flexing\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1390, "output_tokens": 684, "output_tokens_details": {"thinking_tokens": 544}, "service_tier": "batch"}}
|
||||
{"id": "group-vulnerable", "text": "[\"addiction-and-obsession\", \"alcohol-and-substance-abuse\", \"clinging-to-love\", \"disappointment-and-failure\", \"fear-of-losing-love\", \"heartbreak-and-grief\", \"hidden-emotional-struggle\", \"inner-mental-turmoil\", \"loneliness-and-isolation\", \"longing-and-loss\", \"past-trauma-and-healing\", \"self-worth-and-insecurity\", \"vulnerability-and-betrayal\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1387, "output_tokens": 1016, "output_tokens_details": {"thinking_tokens": 859}, "service_tier": "batch"}}
|
||||
@@ -0,0 +1,30 @@
|
||||
You are selecting thematic keywords that belong to a named
|
||||
group.
|
||||
|
||||
Input: a JSON object with the name of one group and the
|
||||
keywords — the complete set of codes; use these and no
|
||||
others:
|
||||
|
||||
{
|
||||
"group": "the name of the group",
|
||||
"keywords": ["first-keyword", "second-keyword"]
|
||||
}
|
||||
|
||||
Task: list every given keyword that belongs to the named
|
||||
group, judged by the literal meaning of the keyword itself.
|
||||
|
||||
Rules:
|
||||
|
||||
- Use only the given keywords, spelled exactly as given.
|
||||
- A group may match any number of keywords, including none.
|
||||
- Judge each keyword only by the literal meaning of its own
|
||||
wording.
|
||||
|
||||
Do not wrap the output in a Markdown code fence.
|
||||
The output must be strictly valid JSON.
|
||||
|
||||
Output a single JSON array of the keywords that belong to
|
||||
the group (an empty array when none belongs), and nothing
|
||||
else:
|
||||
|
||||
["first-keyword", "second-keyword"]
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"script_version": "run_llm.py 3.1.0",
|
||||
"model": "claude-fable-5",
|
||||
"temperature": null,
|
||||
"thinking": null,
|
||||
"max_tokens": 8192,
|
||||
"prompt_path": "../prompts/04-group.md",
|
||||
"prompt_sha256": "50e1d5d6c4115d090ae4ab1e801ea74db0b2dcdd47213ce0feb6749e034a41e9",
|
||||
"input_path": "instance/llm-input-group.jsonl",
|
||||
"input_sha256": "7fd97ae165270cb91461aedf411050892667b928d8584fceffea6f9649e003c7",
|
||||
"item_count": 4,
|
||||
"dry_run": false,
|
||||
"started_at": "2026-08-14T23:39:37+08:00",
|
||||
"batch": {
|
||||
"batch_id": "msgbatch_01DveEMYyjCAYe6wxpcCD87V",
|
||||
"submitted_at": "2026-08-14T23:39:43+08:00",
|
||||
"ended_at": "2026-08-14T15:41:46.778015+00:00"
|
||||
},
|
||||
"usage": {
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0,
|
||||
"input_tokens": 5553,
|
||||
"output_tokens": 1975
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{"id": "group-women-power", "text": "[\"female-empowerment\", \"women-power\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1385, "output_tokens": 77, "output_tokens_details": {"thinking_tokens": 61}, "service_tier": "batch"}}
|
||||
{"id": "group-misogyny", "text": "[\"rejection-of-women\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1391, "output_tokens": 207, "output_tokens_details": {"thinking_tokens": 195}, "service_tier": "batch"}}
|
||||
{"id": "group-masculine", "text": "[\"dominance-and-power\", \"family-and-fatherhood\", \"hustle-and-money\", \"rivalry-and-superiority\", \"self-confidence-and-braggadocio\", \"showing-off-and-impressing\", \"street-loyalty-and-danger\", \"violence-and-street-danger\", \"wealth-and-flexing\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1390, "output_tokens": 846, "output_tokens_details": {"thinking_tokens": 740}, "service_tier": "batch"}}
|
||||
{"id": "group-vulnerable", "text": "[\"disappointment-and-failure\", \"fear-of-losing-love\", \"heartbreak-and-grief\", \"hidden-emotional-struggle\", \"inner-mental-turmoil\", \"loneliness-and-isolation\", \"longing-and-loss\", \"past-trauma-and-healing\", \"self-worth-and-insecurity\", \"vulnerability-and-betrayal\"]", "stop_reason": "end_turn", "usage": {"cache_creation": {"ephemeral_1h_input_tokens": 0, "ephemeral_5m_input_tokens": 0}, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "inference_geo": "global", "input_tokens": 1387, "output_tokens": 845, "output_tokens_details": {"thinking_tokens": 723}, "service_tier": "batch"}}
|
||||
@@ -0,0 +1,30 @@
|
||||
You are selecting thematic keywords that belong to a named
|
||||
group.
|
||||
|
||||
Input: a JSON object with the name of one group and the
|
||||
keywords — the complete set of codes; use these and no
|
||||
others:
|
||||
|
||||
{
|
||||
"group": "the name of the group",
|
||||
"keywords": ["first-keyword", "second-keyword"]
|
||||
}
|
||||
|
||||
Task: list every given keyword that belongs to the named
|
||||
group, judged by the literal meaning of the keyword itself.
|
||||
|
||||
Rules:
|
||||
|
||||
- Use only the given keywords, spelled exactly as given.
|
||||
- A group may match any number of keywords, including none.
|
||||
- Judge each keyword only by the literal meaning of its own
|
||||
wording.
|
||||
|
||||
Do not wrap the output in a Markdown code fence.
|
||||
The output must be strictly valid JSON.
|
||||
|
||||
Output a single JSON array of the keywords that belong to
|
||||
the group (an empty array when none belongs), and nothing
|
||||
else:
|
||||
|
||||
["first-keyword", "second-keyword"]
|
||||
@@ -23,6 +23,7 @@ from .commands import (
|
||||
fetch_lyrics_command,
|
||||
run_llm_command,
|
||||
tally_codings_command,
|
||||
tally_groups_command,
|
||||
)
|
||||
|
||||
MODULE_PROG: str = "python -m pop_fem_audit_tools"
|
||||
@@ -36,6 +37,7 @@ SUBCOMMANDS: dict[str, Callable[[list[str] | None], int]] = {
|
||||
"fetch-lyrics": fetch_lyrics_command,
|
||||
"run-llm": run_llm_command,
|
||||
"tally-codings": tally_codings_command,
|
||||
"tally-groups": tally_groups_command,
|
||||
}
|
||||
"""The dispatch table from the subcommand name to the tool main."""
|
||||
|
||||
|
||||
@@ -116,3 +116,23 @@ def tally_codings_command(argv: list[str] | None = None) -> int:
|
||||
"""
|
||||
from .tally_codings import main
|
||||
return main(argv)
|
||||
|
||||
|
||||
def tally_groups_command(argv: list[str] | None = None) -> int:
|
||||
"""Settle the code groups by a majority of the three runs.
|
||||
|
||||
Writes the final group table as the given CSV file, holding
|
||||
the header row ``Group,Keyword,Votes`` and one row per
|
||||
(group, keyword) pair at least two of the three selection
|
||||
runs select, ordered by the group name and then by the
|
||||
keyword. A selected item that is not in the valid keyword
|
||||
list casts no vote. Nothing is written when the three
|
||||
archives do not cover the same groups or a record is
|
||||
malformed; the error message names what failed.
|
||||
|
||||
:param argv: The command-line arguments, or None for
|
||||
``sys.argv``.
|
||||
:return: The exit status: 0 on success, non-zero on failure.
|
||||
"""
|
||||
from .tally_groups import main
|
||||
return main(argv)
|
||||
|
||||
@@ -72,6 +72,7 @@ from ..database import Base, ds
|
||||
from ..models import (
|
||||
Artist,
|
||||
ChartEntry,
|
||||
CodeGroup,
|
||||
Coding,
|
||||
Role,
|
||||
Song,
|
||||
@@ -118,6 +119,9 @@ def parse_args(argv: list[str] | None) -> argparse.Namespace:
|
||||
parser.add_argument(
|
||||
"--codings", type=Path, default=None,
|
||||
help="the settled coding table CSV file to import")
|
||||
parser.add_argument(
|
||||
"--groups", type=Path, default=None,
|
||||
help="the settled code group table CSV file to import")
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
@@ -690,9 +694,6 @@ class CodingImporter:
|
||||
COLUMNS: tuple[str, ...] = (
|
||||
"Song", "Artist Credit", "Keyword", "Quote")
|
||||
"""The required columns of the coding CSV file."""
|
||||
NEWLINE_ESCAPE: str = "\\n"
|
||||
"""The two characters standing for a newline in the quote
|
||||
column, so that the CSV file is one row per line."""
|
||||
|
||||
def __init__(self, session: Session) -> None:
|
||||
"""Initialize the importer.
|
||||
@@ -707,10 +708,11 @@ class CodingImporter:
|
||||
A None input leaves the coding unloaded. Otherwise every
|
||||
row of the CSV file yields one coding of the song named by
|
||||
its title and artist credit, with the quote column stored
|
||||
verbatim except that each two-character ``\\n`` escape
|
||||
becomes a newline; an empty quote column stores an empty
|
||||
string. When the method returns, the imported codings are
|
||||
queryable in the session.
|
||||
verbatim; a quote carries the lyric line-break convention
|
||||
``" / "`` where the lyric has a line break, and an empty
|
||||
quote column stores an empty string. When the method
|
||||
returns, the imported codings are queryable in the
|
||||
session.
|
||||
|
||||
:param path: The settled coding table CSV file to import,
|
||||
or None to skip the coding.
|
||||
@@ -766,7 +768,7 @@ class CodingImporter:
|
||||
seen.add(coding_key)
|
||||
self.__session.add(Coding(
|
||||
song=song, keyword=row["Keyword"],
|
||||
quotes=row["Quote"].replace(self.NEWLINE_ESCAPE, "\n")))
|
||||
quotes=row["Quote"]))
|
||||
|
||||
@classmethod
|
||||
def __check_columns(cls, path: Path,
|
||||
@@ -787,6 +789,101 @@ class CodingImporter:
|
||||
f"{path}: missing column(s): {', '.join(missing)}")
|
||||
|
||||
|
||||
class GroupImporter:
|
||||
"""The group-import job: loads the settled code group table
|
||||
into the working store."""
|
||||
|
||||
COLUMNS: tuple[str, ...] = ("Group", "Keyword", "Votes")
|
||||
"""The required columns of the group CSV file."""
|
||||
|
||||
def __init__(self, session: Session) -> None:
|
||||
"""Initialize the importer.
|
||||
|
||||
:param session: The database session.
|
||||
"""
|
||||
self.__session: Session = session
|
||||
|
||||
def import_groups(self, path: Path | None) -> None:
|
||||
"""Load the settled code group table into the store.
|
||||
|
||||
A None input leaves the groups unloaded. Otherwise every
|
||||
row of the CSV file yields one member keyword of one
|
||||
group, with the group name, the keyword, and the integer
|
||||
vote count stored verbatim. When the method returns, the
|
||||
imported groups are queryable in the session.
|
||||
|
||||
:param path: The settled code group table CSV file to
|
||||
import, or None to skip the groups.
|
||||
:return: None.
|
||||
:raises BuildError: When the file lacks a required
|
||||
column, a votes field is not an integer, or two rows
|
||||
name the same group and keyword.
|
||||
:raises OSError: When the file cannot be read.
|
||||
"""
|
||||
if path is None:
|
||||
return
|
||||
seen: set[tuple[str, str]] = set()
|
||||
with open(path, encoding="utf-8", newline="") as file:
|
||||
reader: csv.DictReader[str] = csv.DictReader(file)
|
||||
self.__check_columns(path, reader.fieldnames)
|
||||
row: dict[str, str]
|
||||
for row in reader:
|
||||
self.__import_group_row(path, seen, row)
|
||||
self.__session.flush()
|
||||
|
||||
def __import_group_row(self, path: Path,
|
||||
seen: set[tuple[str, str]],
|
||||
row: dict[str, str]) -> None:
|
||||
"""Store one group member row.
|
||||
|
||||
:param path: The group CSV file, for the error messages.
|
||||
:param seen: The (group, keyword) pairs already stored,
|
||||
updated with the pair of this row.
|
||||
:param row: The group CSV row.
|
||||
:return: None.
|
||||
:raises BuildError: When the votes field is not an
|
||||
integer, or the group and keyword repeat an earlier
|
||||
row.
|
||||
"""
|
||||
key: tuple[str, str] = (row["Group"], row["Keyword"])
|
||||
if key in seen:
|
||||
raise BuildError(
|
||||
f"{path}: duplicated group member: group"
|
||||
f" \"{row['Group']}\", keyword"
|
||||
f" \"{row['Keyword']}\"")
|
||||
seen.add(key)
|
||||
votes: int
|
||||
try:
|
||||
votes = int(row["Votes"])
|
||||
except ValueError as error:
|
||||
raise BuildError(
|
||||
f"{path}: group \"{row['Group']}\", keyword"
|
||||
f" \"{row['Keyword']}\": votes"
|
||||
f" \"{row['Votes']}\" is not an integer"
|
||||
) from error
|
||||
self.__session.add(CodeGroup(
|
||||
group=row["Group"], keyword=row["Keyword"],
|
||||
votes=votes))
|
||||
|
||||
@classmethod
|
||||
def __check_columns(cls, path: Path,
|
||||
fieldnames: Sequence[str] | None) -> None:
|
||||
"""Verify the group CSV file has the required columns.
|
||||
|
||||
:param path: The group CSV file.
|
||||
:param fieldnames: The header row of the file, or None
|
||||
when the file is empty.
|
||||
:return: None.
|
||||
:raises BuildError: When a required column is absent.
|
||||
"""
|
||||
header: Sequence[str] = fieldnames or ()
|
||||
missing: list[str] = [
|
||||
x for x in cls.COLUMNS if x not in header]
|
||||
if len(missing) > 0:
|
||||
raise BuildError(
|
||||
f"{path}: missing column(s): {', '.join(missing)}")
|
||||
|
||||
|
||||
@dataclass
|
||||
class StoreCounts:
|
||||
"""The row counts of the working store, for the build summary."""
|
||||
@@ -797,6 +894,8 @@ class StoreCounts:
|
||||
"""The number of the artists."""
|
||||
codings: int
|
||||
"""The number of the settled codings."""
|
||||
groups: int
|
||||
"""The number of the settled code group members."""
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls, session: Session) -> Self:
|
||||
@@ -817,7 +916,9 @@ class StoreCounts:
|
||||
artists=count(
|
||||
sa.select(sa.func.count()).select_from(Artist)),
|
||||
codings=count(
|
||||
sa.select(sa.func.count()).select_from(Coding)))
|
||||
sa.select(sa.func.count()).select_from(Coding)),
|
||||
groups=count(
|
||||
sa.select(sa.func.count()).select_from(CodeGroup)))
|
||||
|
||||
|
||||
def reset_store(session: Session) -> None:
|
||||
@@ -827,7 +928,8 @@ def reset_store(session: Session) -> None:
|
||||
:return: None.
|
||||
"""
|
||||
model: type[Base]
|
||||
for model in (Coding, SongArtist, ChartEntry, Song, Artist):
|
||||
for model in (CodeGroup, Coding, SongArtist, ChartEntry, Song,
|
||||
Artist):
|
||||
session.execute(sa.delete(model))
|
||||
|
||||
|
||||
@@ -990,6 +1092,7 @@ def main(argv: list[str] | None = None) -> int:
|
||||
args.lyrics_dir, args.wikidata_csv)
|
||||
PerformerGenderDeriver(session).derive_performer_genders()
|
||||
CodingImporter(session).import_codings(args.codings)
|
||||
GroupImporter(session).import_groups(args.groups)
|
||||
counts = StoreCounts.get_instance(session)
|
||||
CSVExporter(session, args.derived_dir).write()
|
||||
session.commit()
|
||||
@@ -1001,6 +1104,7 @@ def main(argv: list[str] | None = None) -> int:
|
||||
session.close()
|
||||
elapsed: str = format_duration(time.monotonic() - started)
|
||||
print(f"Done. {counts.songs} songs/{counts.artists} artists"
|
||||
f"/{counts.codings} codings. {elapsed} elapsed.",
|
||||
f"/{counts.codings} codings/{counts.groups} group"
|
||||
f" members. {elapsed} elapsed.",
|
||||
file=sys.stderr)
|
||||
return 0
|
||||
|
||||
@@ -35,10 +35,18 @@ import anthropic
|
||||
from ..config import get_settings
|
||||
from ..utils import format_duration
|
||||
|
||||
MODEL: str = "claude-sonnet-4-6"
|
||||
TEMPERATURE: float = 0.0
|
||||
THINKING: dict[str, str] = {"type": "disabled"}
|
||||
SCRIPT_VERSION: str = "run_llm.py 3.0.0"
|
||||
# claude-fable-5 accepts neither "temperature" nor "thinking";
|
||||
# a model's entry holds exactly the extra request parameters it
|
||||
# accepts.
|
||||
MODELS: dict[str, dict[str, Any]] = {
|
||||
"claude-sonnet-4-6": {
|
||||
"temperature": 0.0,
|
||||
"thinking": {"type": "disabled"},
|
||||
},
|
||||
"claude-fable-5": {},
|
||||
}
|
||||
DEFAULT_MODEL: str = "claude-sonnet-4-6"
|
||||
SCRIPT_VERSION: str = "run_llm.py 3.1.0"
|
||||
POLL_INTERVAL_SECONDS: float = 60.0
|
||||
|
||||
|
||||
@@ -179,6 +187,9 @@ def parse_args(argv: list[str] | None) -> argparse.Namespace:
|
||||
parser.add_argument(
|
||||
"archive_dir", type=Path,
|
||||
help="the destination archive directory")
|
||||
parser.add_argument(
|
||||
"--model", choices=sorted(MODELS), default=DEFAULT_MODEL,
|
||||
help=f"the model ID (default {DEFAULT_MODEL})")
|
||||
parser.add_argument(
|
||||
"--max-tokens", type=int, default=2048,
|
||||
help="the maximum output tokens per request (default 2048)")
|
||||
@@ -225,21 +236,21 @@ def load_items(path: Path) -> list[InputItem]:
|
||||
|
||||
|
||||
def build_request(item: InputItem, system_prompt: str,
|
||||
max_tokens: int) -> dict[str, Any]:
|
||||
max_tokens: int, model: str) -> dict[str, Any]:
|
||||
"""Build one Message Batches request for an input item.
|
||||
|
||||
:param item: The input item.
|
||||
:param system_prompt: The system prompt text.
|
||||
:param max_tokens: The maximum output tokens.
|
||||
:param model: The model ID, a key of ``MODELS``.
|
||||
:return: The batch request with "custom_id" and "params".
|
||||
"""
|
||||
return {
|
||||
"custom_id": item.id,
|
||||
"params": {
|
||||
"model": MODEL,
|
||||
"model": model,
|
||||
"max_tokens": max_tokens,
|
||||
"temperature": TEMPERATURE,
|
||||
"thinking": THINKING,
|
||||
**MODELS[model],
|
||||
"system": system_prompt,
|
||||
"messages": [
|
||||
{"role": "user", "content": item.content},
|
||||
@@ -418,7 +429,7 @@ def now_iso() -> str:
|
||||
|
||||
def execute_run(
|
||||
client: anthropic.Anthropic, items: list[InputItem],
|
||||
system_prompt: str, max_tokens: int,
|
||||
system_prompt: str, max_tokens: int, model: str,
|
||||
meta: dict[str, Any],
|
||||
) -> Results:
|
||||
"""Submit the batch of this run and await its results.
|
||||
@@ -430,11 +441,13 @@ def execute_run(
|
||||
:param items: The input items.
|
||||
:param system_prompt: The system prompt text.
|
||||
:param max_tokens: The maximum output tokens per request.
|
||||
:param model: The model ID, a key of ``MODELS``.
|
||||
:param meta: The metadata to record the batch bookkeeping into.
|
||||
:return: The results of this run, keyed by item ID.
|
||||
"""
|
||||
requests: list[dict[str, Any]] = [
|
||||
build_request(x, system_prompt, max_tokens) for x in items]
|
||||
build_request(x, system_prompt, max_tokens, model)
|
||||
for x in items]
|
||||
info: BatchInfo = BatchInfo(
|
||||
batch_id=submit_batch(client, requests),
|
||||
submitted_at=now_iso())
|
||||
@@ -469,9 +482,9 @@ def main(argv: list[str] | None = None) -> int:
|
||||
(archive_dir / "prompt.md").write_bytes(args.prompt.read_bytes())
|
||||
meta: dict[str, Any] = {
|
||||
"script_version": SCRIPT_VERSION,
|
||||
"model": MODEL,
|
||||
"temperature": TEMPERATURE,
|
||||
"thinking": THINKING,
|
||||
"model": args.model,
|
||||
"temperature": MODELS[args.model].get("temperature"),
|
||||
"thinking": MODELS[args.model].get("thinking"),
|
||||
"max_tokens": args.max_tokens,
|
||||
"prompt_path": str(args.prompt),
|
||||
"prompt_sha256": sha256_of(args.prompt),
|
||||
@@ -486,7 +499,8 @@ def main(argv: list[str] | None = None) -> int:
|
||||
if args.dry_run:
|
||||
write_json(meta_path, meta)
|
||||
print(json.dumps(
|
||||
build_request(items[0], prompt_text, args.max_tokens),
|
||||
build_request(items[0], prompt_text, args.max_tokens,
|
||||
args.model),
|
||||
ensure_ascii=False, indent=2))
|
||||
elapsed: str = format_duration(time.monotonic() - started)
|
||||
print(f"Done. {len(items)} jobs finished."
|
||||
@@ -495,7 +509,8 @@ def main(argv: list[str] | None = None) -> int:
|
||||
client: anthropic.Anthropic = anthropic.Anthropic(
|
||||
api_key=get_settings().ANTHROPIC_API_KEY)
|
||||
results: Results = execute_run(
|
||||
client, items, prompt_text, args.max_tokens, meta)
|
||||
client, items, prompt_text, args.max_tokens, args.model,
|
||||
meta)
|
||||
item_ids: list[str] = [x.id for x in items]
|
||||
write_jsonl(
|
||||
archive_dir / "output.jsonl",
|
||||
|
||||
@@ -15,10 +15,13 @@ three runs assign it, so three votes never tie, and it carries
|
||||
the lyric quotes of every run that assigned it, pooled,
|
||||
deduplicated, sorted by Unicode code point, and joined with a
|
||||
single ``|``: the three runs are peers, so the quote order
|
||||
follows the text alone. The written quote carries the two
|
||||
characters ``\n`` where the lyric has a newline, the mirror of
|
||||
the unescaping the correction table loader does, so the coding
|
||||
table holds one row per line. The three
|
||||
follows the text alone. A quote carries the lyric line-break
|
||||
convention ``" / "`` where the lyric has a newline, applied once
|
||||
when the run records load, so the corrections, the coding table,
|
||||
and the database all share the one representation and nothing is
|
||||
ever converted back. No lyric of the 883-song corpus contains
|
||||
``" / "`` -- a corpus fact checked exhaustively, not a structural
|
||||
guarantee -- so the convention is unambiguous here. The three
|
||||
archives must cover exactly the same set of song IDs, every
|
||||
record must be a successful result, and every record's "text"
|
||||
must parse to a JSON object; otherwise the tally fails and
|
||||
@@ -161,11 +164,10 @@ class CorrectionsLoader:
|
||||
of the runs the command was given, and a known type. The
|
||||
file is read with the CSV reader, so a quoted field may
|
||||
hold a comma or a double quote. No field holds a line
|
||||
break: the two text fields carry the two characters
|
||||
``\n`` where the text has a newline, so the file holds one
|
||||
row per line, and each of them is unescaped to a single LF
|
||||
before the repair is matched or applied, as that is what
|
||||
the archived records carry. Nothing is written.
|
||||
break: the two text fields carry the lyric line-break
|
||||
convention ``" / "`` where the text has a newline -- the
|
||||
same representation the loaded run records carry -- and
|
||||
are matched and applied verbatim. Nothing is written.
|
||||
|
||||
:return: The repairs, in file order.
|
||||
:raises TallyError: When the file cannot be read, the
|
||||
@@ -249,21 +251,7 @@ class CorrectionsLoader:
|
||||
raise ValueError(f"{label}: unknown type \"{row[2]}\"")
|
||||
return Correction(
|
||||
line=line, song_id=song_id, run=row[1], type=row[2],
|
||||
to_be_replaced=cls.__unescape(row[3]),
|
||||
correct_term=cls.__unescape(row[4]))
|
||||
|
||||
@staticmethod
|
||||
def __unescape(text: str) -> str:
|
||||
r"""Unescape the newlines of a text field.
|
||||
|
||||
The mirror of the escaping :meth:`CodingTable.write` does
|
||||
to the ``Quote`` field it writes out.
|
||||
|
||||
:param text: The field as the CSV reader gave it.
|
||||
:return: The field with every two-character ``\n``
|
||||
sequence turned into a single LF.
|
||||
"""
|
||||
return text.replace("\\n", "\n")
|
||||
to_be_replaced=row[3], correct_term=row[4])
|
||||
|
||||
@staticmethod
|
||||
def __parse_song_id(item_id: str, label: str) -> int:
|
||||
@@ -361,6 +349,11 @@ class CodingTallier:
|
||||
__QUOTE_SEPARATOR: str = "|"
|
||||
"""The separator between the distinct lyric quotes of one
|
||||
settled code."""
|
||||
__LINE_BREAK: str = " / "
|
||||
"""The lyric line-break convention replacing every LF inside a
|
||||
quote. Unambiguous for this corpus only: none of the 883
|
||||
songs' lyrics contains the three characters, checked
|
||||
exhaustively; a new corpus must be re-checked."""
|
||||
|
||||
def __init__(self, run_dir_1: Path, run_dir_2: Path,
|
||||
run_dir_3: Path,
|
||||
@@ -645,8 +638,8 @@ class CodingTallier:
|
||||
keywords, f"{path}: id {item_id}")
|
||||
return records
|
||||
|
||||
@staticmethod
|
||||
def __quote_lists(keywords: dict[str, Any], label: str) \
|
||||
@classmethod
|
||||
def __quote_lists(cls, keywords: dict[str, Any], label: str) \
|
||||
-> dict[str, list[str]]:
|
||||
"""Validate the lyric quote list of every keyword.
|
||||
|
||||
@@ -654,7 +647,8 @@ class CodingTallier:
|
||||
:param label: The location of the record, for the error
|
||||
message.
|
||||
:return: The lyric quotes of every keyword, in the given
|
||||
order.
|
||||
order, every LF inside a quote turned into the lyric
|
||||
line-break convention ``" / "``.
|
||||
:raises ValueError: When a keyword's value is not a list
|
||||
of strings.
|
||||
"""
|
||||
@@ -667,7 +661,8 @@ class CodingTallier:
|
||||
raise ValueError(
|
||||
f"{label}: keyword \"{keyword}\": the quotes"
|
||||
" are not a list of strings")
|
||||
quotes[keyword] = value
|
||||
quotes[keyword] = [
|
||||
x.replace("\n", cls.__LINE_BREAK) for x in value]
|
||||
return quotes
|
||||
|
||||
@classmethod
|
||||
@@ -832,18 +827,17 @@ class CodingTable:
|
||||
keyword, by Unicode code point."""
|
||||
|
||||
def write(self, output_csv: Path) -> None:
|
||||
r"""Write the coding table CSV file.
|
||||
"""Write the coding table CSV file.
|
||||
|
||||
Writes an RFC 4180 CSV file, UTF-8, with CRLF line
|
||||
endings, carrying the header row
|
||||
``Song,Artist Credit,Keyword,Quote`` and one row per
|
||||
settled keyword, in the row order. The ``Quote`` field
|
||||
carries the two characters ``\n`` where the quotes have a
|
||||
newline, so no field holds a line break and the file
|
||||
holds one row per line; the correction table loader
|
||||
unescapes its own two text fields the same way, and
|
||||
restoring a single LF gives the lyric text back. The
|
||||
parent directory is created when it does not exist.
|
||||
settled keyword, in the row order. Every field is
|
||||
written verbatim; a quote carries the lyric line-break
|
||||
convention ``" / "`` where the lyric has a line break, so
|
||||
no field holds a line break and the file holds one row
|
||||
per line. The parent directory is created when it does
|
||||
not exist.
|
||||
|
||||
:param output_csv: The output CSV file.
|
||||
:return: None.
|
||||
@@ -854,22 +848,7 @@ class CodingTable:
|
||||
newline="") as file:
|
||||
writer: Any = csv.writer(file)
|
||||
writer.writerow(self.__HEADER)
|
||||
writer.writerows(
|
||||
(*x[:3], self.__escape(x[3])) for x in self.rows)
|
||||
|
||||
@staticmethod
|
||||
def __escape(text: str) -> str:
|
||||
r"""Escape the newlines of the quote field.
|
||||
|
||||
The mirror of the unescaping the correction table loader
|
||||
does to its own two text fields.
|
||||
|
||||
:param text: The joined lyric quotes of one settled
|
||||
keyword.
|
||||
:return: The quotes with every LF turned into the two
|
||||
characters ``\n``.
|
||||
"""
|
||||
return text.replace("\n", "\\n")
|
||||
writer.writerows(self.rows)
|
||||
|
||||
|
||||
class CodingTableBuilder:
|
||||
@@ -1017,9 +996,9 @@ def main(argv: list[str] | None = None) -> int:
|
||||
song named by its title and its stored artist credit from the
|
||||
SQLite working store, and the keyword carrying the pooled,
|
||||
deduplicated, and sorted lyric quotes of the runs that
|
||||
assigned it, joined with a single ``|`` and written with the
|
||||
two characters ``\n`` where the quotes have a newline, so the
|
||||
table holds one row per line. The records are
|
||||
assigned it, joined with a single ``|`` and carrying the
|
||||
lyric line-break convention ``" / "`` where the lyric has a
|
||||
newline, so the table holds one row per line. The records are
|
||||
repaired from the ``--corrections`` table and then checked
|
||||
against the ``--valid-keywords`` list, when either is given.
|
||||
Nothing is written when the three archives do not cover the
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
# Tools for A Feminist Audit of Pop Music.
|
||||
# Copyright 2026 imacat. All rights reserved.
|
||||
# Authors:
|
||||
# imacat@mail.imacat.idv.tw (imacat), 2026/8/15
|
||||
# AI assistance: Claude Code (Anthropic)
|
||||
"""The majority tally of the three group-selection runs.
|
||||
|
||||
Settles the semantic code groups of step 4: the same group
|
||||
selection definition file is run three times independently, and
|
||||
this command counts the votes and writes the final group table
|
||||
the paper cites, as the CSV file given as the last positional
|
||||
command-line argument. A (group, keyword) pair is written out
|
||||
when at least two of the three runs select it, so three votes
|
||||
never tie. A selected item that is not in the valid keyword
|
||||
list is invalid and casts no vote; every dropped occurrence is
|
||||
reported on standard error. The group name is the record ID
|
||||
with its ``group-`` prefix dropped. The rows are ordered by the
|
||||
group name and then by the keyword, by Unicode code point, and
|
||||
the file carries the header row ``Group,Keyword,Votes`` with
|
||||
CRLF line endings per RFC 4180.
|
||||
|
||||
The three archives must cover exactly the same set of group IDs,
|
||||
every record ID must carry the ``group-`` prefix, and every
|
||||
record's "text" must parse to a JSON array of strings; otherwise
|
||||
the tally fails and nothing is written.
|
||||
"""
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from ..utils import format_duration
|
||||
|
||||
GROUP_ID_PREFIX: str = "group-"
|
||||
"""The prefix every group record ID must carry; the group name
|
||||
is the rest of the ID."""
|
||||
MAJORITY: int = 2
|
||||
"""The number of runs that must select a keyword for a group for
|
||||
that pair to be settled."""
|
||||
HEADER: tuple[str, str, str] = ("Group", "Keyword", "Votes")
|
||||
"""The header row of the group table CSV file."""
|
||||
|
||||
|
||||
class TallyError(Exception):
|
||||
"""An error that fails the group tally."""
|
||||
|
||||
|
||||
def parse_args(argv: list[str] | None) -> argparse.Namespace:
|
||||
"""Parse the command-line arguments.
|
||||
|
||||
:param argv: The command-line arguments, or None for
|
||||
``sys.argv``.
|
||||
:return: The parsed arguments.
|
||||
"""
|
||||
parser: argparse.ArgumentParser = argparse.ArgumentParser(
|
||||
description="Settle the semantic code groups by a"
|
||||
" majority of the three selection runs.")
|
||||
parser.add_argument(
|
||||
"run_dir_1", type=Path,
|
||||
help="the first selection run's archive directory")
|
||||
parser.add_argument(
|
||||
"run_dir_2", type=Path,
|
||||
help="the second selection run's archive directory")
|
||||
parser.add_argument(
|
||||
"run_dir_3", type=Path,
|
||||
help="the third selection run's archive directory")
|
||||
parser.add_argument(
|
||||
"valid_keywords", type=Path,
|
||||
help="a plain text file of the allowed keywords, one per"
|
||||
" line")
|
||||
parser.add_argument(
|
||||
"output_csv", type=Path,
|
||||
help="the output CSV file, by convention"
|
||||
" results/groups.csv")
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def load_valid_keywords(path: Path) -> set[str]:
|
||||
"""Load the valid keyword list.
|
||||
|
||||
:param path: The plain text file of the allowed keywords, one
|
||||
per line.
|
||||
:return: The allowed keywords.
|
||||
:raises TallyError: When the file cannot be read or holds no
|
||||
keyword.
|
||||
"""
|
||||
text: str
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
except OSError as error:
|
||||
raise TallyError(str(error)) from error
|
||||
keywords: set[str] = {x.strip() for x in text.split("\n")
|
||||
if x.strip() != ""}
|
||||
if len(keywords) == 0:
|
||||
raise TallyError(f"{path}: no keywords")
|
||||
return keywords
|
||||
|
||||
|
||||
def load_run(run_dir: Path) -> dict[str, set[str]]:
|
||||
"""Load and validate the selection records of one run.
|
||||
|
||||
:param run_dir: The run's archive directory, containing
|
||||
``output.jsonl``.
|
||||
:return: The selected keywords of every group of the run,
|
||||
keyed by the group name, the duplicates within one
|
||||
record's selection collapsed.
|
||||
:raises TallyError: When the file cannot be read, a line is
|
||||
not a well-formed output record, a record is not a
|
||||
successful result, an ID lacks the ``group-`` prefix, a
|
||||
group has two records, or a "text" does not parse to a
|
||||
JSON array of strings.
|
||||
"""
|
||||
path: Path = run_dir / "output.jsonl"
|
||||
text: str
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
except OSError as error:
|
||||
raise TallyError(str(error)) from error
|
||||
records: dict[str, set[str]] = {}
|
||||
line: str
|
||||
for line in text.split("\n"):
|
||||
if line.strip() == "":
|
||||
continue
|
||||
record: Any
|
||||
try:
|
||||
record = json.loads(line)
|
||||
except json.JSONDecodeError as error:
|
||||
raise TallyError(
|
||||
f"{path}: malformed JSON: {error}") from error
|
||||
if not isinstance(record, dict) or "id" not in record:
|
||||
raise TallyError(
|
||||
f"{path}: record without \"id\": {line}")
|
||||
item_id: Any = record["id"]
|
||||
if "error" in record or "text" not in record:
|
||||
raise TallyError(
|
||||
f"{path}: id {item_id}: not a successful result")
|
||||
if not isinstance(item_id, str) \
|
||||
or not item_id.startswith(GROUP_ID_PREFIX) \
|
||||
or item_id == GROUP_ID_PREFIX:
|
||||
raise TallyError(
|
||||
f"{path}: id {item_id}: not in the"
|
||||
f" \"{GROUP_ID_PREFIX}<name>\" form")
|
||||
group: str = item_id[len(GROUP_ID_PREFIX):]
|
||||
if group in records:
|
||||
raise TallyError(
|
||||
f"{path}: id {item_id}: duplicate record")
|
||||
records[group] = _selection(
|
||||
record["text"], f"{path}: id {item_id}")
|
||||
if len(records) == 0:
|
||||
raise TallyError(f"{path}: no records")
|
||||
return records
|
||||
|
||||
|
||||
def _selection(text: Any, label: str) -> set[str]:
|
||||
"""Parse and validate the selected keywords of one record.
|
||||
|
||||
:param text: The "text" field of the record.
|
||||
:param label: The location of the record, for the error
|
||||
message.
|
||||
:return: The selected keywords, the duplicates collapsed.
|
||||
:raises TallyError: When the text does not parse to a JSON
|
||||
array of strings.
|
||||
"""
|
||||
if not isinstance(text, str):
|
||||
raise TallyError(f"{label}: \"text\" is not a string")
|
||||
selected: Any
|
||||
try:
|
||||
selected = json.loads(text)
|
||||
except json.JSONDecodeError as error:
|
||||
raise TallyError(
|
||||
f"{label}: \"text\" is malformed JSON:"
|
||||
f" {error}") from error
|
||||
if not isinstance(selected, list) \
|
||||
or not all(isinstance(x, str) for x in selected):
|
||||
raise TallyError(
|
||||
f"{label}: \"text\" does not parse to a JSON array"
|
||||
" of strings")
|
||||
return set(selected)
|
||||
|
||||
|
||||
def drop_invalid(runs: list[dict[str, set[str]]],
|
||||
run_dirs: list[Path],
|
||||
valid: set[str]) -> None:
|
||||
"""Drop the out-of-vocabulary selections of every run.
|
||||
|
||||
Every dropped occurrence is reported on standard error as an
|
||||
observable side effect.
|
||||
|
||||
:param runs: The runs' records, filtered in place.
|
||||
:param run_dirs: The run directories, for the messages.
|
||||
:param valid: The allowed keywords.
|
||||
:return: None.
|
||||
"""
|
||||
records: dict[str, set[str]]
|
||||
run_dir: Path
|
||||
for records, run_dir in zip(runs, run_dirs):
|
||||
group: str
|
||||
selected: set[str]
|
||||
for group, selected in records.items():
|
||||
keyword: str
|
||||
for keyword in sorted(selected - valid):
|
||||
print(
|
||||
f"note: {run_dir.name} group-{group}:"
|
||||
f" dropped out-of-vocabulary item"
|
||||
f" \"{keyword}\"", file=sys.stderr)
|
||||
records[group] = selected & valid
|
||||
|
||||
|
||||
def tally(runs: list[dict[str, set[str]]]) \
|
||||
-> list[tuple[str, str, int]]:
|
||||
"""Tally the keyword votes of the runs, group by group.
|
||||
|
||||
:param runs: The runs' records, all covering the same set of
|
||||
groups.
|
||||
:return: The settled rows, each the group name, the keyword,
|
||||
and the number of votes, ordered by the group name and
|
||||
then by the keyword, by Unicode code point.
|
||||
:raises TallyError: When the runs do not cover the same set
|
||||
of groups.
|
||||
"""
|
||||
groups: set[str] = set(runs[0])
|
||||
records: dict[str, set[str]]
|
||||
for records in runs[1:]:
|
||||
if set(records) != groups:
|
||||
raise TallyError(
|
||||
"the three runs do not cover the same groups: "
|
||||
+ ", ".join(sorted(
|
||||
groups.symmetric_difference(set(records)))))
|
||||
rows: list[tuple[str, str, int]] = []
|
||||
group: str
|
||||
for group in sorted(groups):
|
||||
votes: dict[str, int] = {}
|
||||
for records in runs:
|
||||
keyword: str
|
||||
for keyword in records[group]:
|
||||
votes[keyword] = votes.get(keyword, 0) + 1
|
||||
rows.extend(
|
||||
(group, x, votes[x])
|
||||
for x in sorted(votes) if votes[x] >= MAJORITY)
|
||||
return rows
|
||||
|
||||
|
||||
def write_csv(output_csv: Path,
|
||||
rows: list[tuple[str, str, int]]) -> None:
|
||||
"""Write the group table CSV file.
|
||||
|
||||
Writes an RFC 4180 CSV file, UTF-8, with CRLF line endings,
|
||||
carrying the header row ``Group,Keyword,Votes`` and one row
|
||||
per settled (group, keyword) pair, in the row order. The
|
||||
parent directory is created when it does not exist.
|
||||
|
||||
:param output_csv: The output CSV file.
|
||||
:param rows: The settled rows, in the output order.
|
||||
:return: None.
|
||||
:raises OSError: When the file cannot be written.
|
||||
"""
|
||||
output_csv.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(output_csv, "w", encoding="utf-8",
|
||||
newline="") as file:
|
||||
writer: Any = csv.writer(file)
|
||||
writer.writerow(HEADER)
|
||||
writer.writerows(rows)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
"""Settle the code groups by a majority of the three runs.
|
||||
|
||||
Writes the final group table as the given CSV file, holding
|
||||
the header row ``Group,Keyword,Votes`` and one row per
|
||||
(group, keyword) pair at least two of the three runs select,
|
||||
ordered by the group name and then by the keyword. A
|
||||
selected item that is not in the valid keyword list casts no
|
||||
vote, each dropped occurrence reported on standard error.
|
||||
Nothing is written when the three archives do not cover the
|
||||
same groups, a record is not a successful result, an ID lacks
|
||||
the ``group-`` prefix, or a record's "text" does not parse to
|
||||
a JSON array of strings; the error message names what failed.
|
||||
|
||||
:param argv: The command-line arguments, or None for
|
||||
``sys.argv``.
|
||||
:return: The exit status: 0 on success, non-zero on failure.
|
||||
"""
|
||||
started: float = time.monotonic()
|
||||
args: argparse.Namespace = parse_args(argv)
|
||||
run_dirs: list[Path] = [
|
||||
args.run_dir_1, args.run_dir_2, args.run_dir_3]
|
||||
try:
|
||||
valid: set[str] = load_valid_keywords(args.valid_keywords)
|
||||
runs: list[dict[str, set[str]]] = [
|
||||
load_run(x) for x in run_dirs]
|
||||
drop_invalid(runs, run_dirs, valid)
|
||||
rows: list[tuple[str, str, int]] = tally(runs)
|
||||
write_csv(args.output_csv, rows)
|
||||
except (TallyError, OSError) as error:
|
||||
print(f"error: {error}", file=sys.stderr)
|
||||
return 1
|
||||
elapsed: str = format_duration(time.monotonic() - started)
|
||||
print(
|
||||
f"Done. Settled {len(rows)} codes across"
|
||||
f" {len(runs[0])} groups. {elapsed} elapsed.",
|
||||
file=sys.stderr)
|
||||
return 0
|
||||
@@ -139,3 +139,17 @@ class Coding(Base):
|
||||
single "|", empty when the keyword carries no evidence."""
|
||||
song: Mapped[Song] = relationship(back_populates="codings")
|
||||
"""The coded song."""
|
||||
|
||||
|
||||
class CodeGroup(Base):
|
||||
"""A settled member keyword of a semantic code group."""
|
||||
__tablename__ = "groups"
|
||||
"""The table name."""
|
||||
|
||||
group: Mapped[str] = mapped_column(primary_key=True)
|
||||
"""The group name, as the settled group table carries it."""
|
||||
keyword: Mapped[str] = mapped_column(primary_key=True)
|
||||
"""The member coding keyword."""
|
||||
votes: Mapped[int] = mapped_column()
|
||||
"""The number of the selection runs that selected the
|
||||
keyword for the group."""
|
||||
|
||||
@@ -21,6 +21,7 @@ from pop_fem_audit_tools.database import DataSource
|
||||
from pop_fem_audit_tools.models import (
|
||||
Artist,
|
||||
ChartEntry,
|
||||
CodeGroup,
|
||||
Coding,
|
||||
Role,
|
||||
Song,
|
||||
@@ -268,6 +269,7 @@ class TestBuildDB(unittest.TestCase):
|
||||
self.__wikidata: Path = \
|
||||
self.__dir / "artists_wikidata.csv"
|
||||
self.__codings: Path = self.__dir / "codings.csv"
|
||||
self.__groups: Path = self.__dir / "groups.csv"
|
||||
self.__write_chart(self.CHART_CSV)
|
||||
config.set_settings(config.Settings(
|
||||
SQLALCHEMY_DATABASE_URL="sqlite://",
|
||||
@@ -984,12 +986,13 @@ class TestBuildDB(unittest.TestCase):
|
||||
|
||||
CODINGS_CSV: str = (
|
||||
"Song,Artist Credit,Keyword,Quote\n"
|
||||
"Hello,Adele,longing,\"Hello from the other side\\nI must"
|
||||
"Hello,Adele,longing,\"Hello from the other side / I must"
|
||||
" have called a thousand times\"\n"
|
||||
"Hello,Adele,regret,I'm sorry|It's no secret\n"
|
||||
"One Dance,Drake featuring Wizkid,desire,\n")
|
||||
"""The coding CSV fixture: a two-line quote, two quotes joined
|
||||
by "|", and an empty quote."""
|
||||
"""The coding CSV fixture: a quote carrying the " / "
|
||||
line-break convention, two quotes joined by "|", and an empty
|
||||
quote."""
|
||||
|
||||
def __stored_codings(self) -> dict[tuple[str, str], str]:
|
||||
"""Read the stored codings keyed by the song and keyword.
|
||||
@@ -1003,8 +1006,7 @@ class TestBuildDB(unittest.TestCase):
|
||||
|
||||
def test_codings_imported(self) -> None:
|
||||
"""Test that the coding CSV imports one row per song and
|
||||
keyword, restoring the newline and keeping the "|"-joined
|
||||
quotes verbatim."""
|
||||
keyword, storing the quote column verbatim."""
|
||||
self.__write_codings(self.CODINGS_CSV)
|
||||
status: int
|
||||
stderr: str
|
||||
@@ -1015,8 +1017,8 @@ class TestBuildDB(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
self.__stored_codings(),
|
||||
{("Hello", "longing"):
|
||||
"Hello from the other side\n"
|
||||
"I must have called a thousand times",
|
||||
"Hello from the other side / I must have called"
|
||||
" a thousand times",
|
||||
("Hello", "regret"): "I'm sorry|It's no secret",
|
||||
("One Dance", "desire"): ""})
|
||||
|
||||
@@ -1121,3 +1123,102 @@ class TestBuildDB(unittest.TestCase):
|
||||
self.__stored_codings(),
|
||||
{("Shape of You", "attraction"):
|
||||
"I'm in love with your body"})
|
||||
|
||||
GROUPS_CSV: str = (
|
||||
"Group,Keyword,Votes\n"
|
||||
"masculine,dominance-and-power,3\n"
|
||||
"masculine,family-and-fatherhood,2\n"
|
||||
"women-power,women-power,3\n")
|
||||
"""The group CSV fixture: two groups, one two-vote member."""
|
||||
|
||||
def __write_groups(self, content: str) -> None:
|
||||
"""Write the group CSV fixture.
|
||||
|
||||
:param content: The CSV content.
|
||||
:return: None.
|
||||
"""
|
||||
self.__groups.write_text(content, encoding="utf-8")
|
||||
|
||||
def __stored_groups(self) -> dict[tuple[str, str], int]:
|
||||
"""Read the stored group members keyed by group and keyword.
|
||||
|
||||
:return: The stored votes, keyed by the group name and the
|
||||
keyword.
|
||||
"""
|
||||
session: Session = self.__session()
|
||||
return {(x.group, x.keyword): x.votes
|
||||
for x in session.scalars(sa.select(CodeGroup))}
|
||||
|
||||
def test_groups_imported(self) -> None:
|
||||
"""Test that the group CSV imports one row per group and
|
||||
keyword, the votes stored as integers."""
|
||||
self.__write_groups(self.GROUPS_CSV)
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_build(
|
||||
"--groups", str(self.__groups))
|
||||
self.assertEqual(status, 0)
|
||||
self.assertIn("3 group members", stderr)
|
||||
self.assertEqual(
|
||||
self.__stored_groups(),
|
||||
{("masculine", "dominance-and-power"): 3,
|
||||
("masculine", "family-and-fatherhood"): 2,
|
||||
("women-power", "women-power"): 3})
|
||||
|
||||
def test_groups_replaced_on_rebuild(self) -> None:
|
||||
"""Test that a rebuild replaces the previous groups rather
|
||||
than adding to them."""
|
||||
self.__write_groups(self.GROUPS_CSV)
|
||||
self.assertEqual(
|
||||
self.__run_build("--groups", str(self.__groups))[0], 0)
|
||||
self.__write_groups(
|
||||
"Group,Keyword,Votes\n"
|
||||
"vulnerable,longing-and-loss,3\n")
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_build(
|
||||
"--groups", str(self.__groups))
|
||||
self.assertEqual(status, 0)
|
||||
self.assertIn("1 group members", stderr)
|
||||
self.assertEqual(
|
||||
self.__stored_groups(),
|
||||
{("vulnerable", "longing-and-loss"): 3})
|
||||
|
||||
def test_duplicated_group_member_fails(self) -> None:
|
||||
"""Test that two rows naming the same group and keyword
|
||||
fail the build."""
|
||||
self.__write_groups(
|
||||
"Group,Keyword,Votes\n"
|
||||
"masculine,dominance-and-power,3\n"
|
||||
"masculine,dominance-and-power,2\n")
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_build(
|
||||
"--groups", str(self.__groups))
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertIn("duplicated group member", stderr)
|
||||
|
||||
def test_group_votes_not_an_integer_fails(self) -> None:
|
||||
"""Test that a non-integer votes field fails the build."""
|
||||
self.__write_groups(
|
||||
"Group,Keyword,Votes\n"
|
||||
"masculine,dominance-and-power,three\n")
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_build(
|
||||
"--groups", str(self.__groups))
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertIn("is not an integer", stderr)
|
||||
|
||||
def test_groups_missing_column_fails(self) -> None:
|
||||
"""Test that a group CSV without a required column fails
|
||||
the build."""
|
||||
self.__write_groups(
|
||||
"Group,Keyword\n"
|
||||
"masculine,dominance-and-power\n")
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_build(
|
||||
"--groups", str(self.__groups))
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertIn("missing column(s): Votes", stderr)
|
||||
|
||||
@@ -169,7 +169,7 @@ class TestRequestBuilding(RunLLMTestCase):
|
||||
"""Test the shape of a batch request."""
|
||||
request: dict[str, Any] = run_llm.build_request(
|
||||
run_llm.InputItem(id="song-1", content="the lyrics"),
|
||||
"the system prompt", 2048)
|
||||
"the system prompt", 2048, "claude-sonnet-4-6")
|
||||
self.assertEqual(request["custom_id"], "song-1")
|
||||
params: dict[str, Any] = request["params"]
|
||||
self.assertEqual(params["model"], "claude-sonnet-4-6")
|
||||
@@ -180,6 +180,20 @@ class TestRequestBuilding(RunLLMTestCase):
|
||||
self.assertEqual(params["messages"],
|
||||
[{"role": "user", "content": "the lyrics"}])
|
||||
|
||||
def test_build_request_fable_5(self) -> None:
|
||||
"""Test the request shape for the claude-fable-5 model."""
|
||||
request: dict[str, Any] = run_llm.build_request(
|
||||
run_llm.InputItem(id="group-1", content="the groups"),
|
||||
"the system prompt", 8192, "claude-fable-5")
|
||||
params: dict[str, Any] = request["params"]
|
||||
self.assertEqual(params["model"], "claude-fable-5")
|
||||
self.assertNotIn("temperature", params)
|
||||
self.assertNotIn("thinking", params)
|
||||
self.assertEqual(params["max_tokens"], 8192)
|
||||
self.assertEqual(params["system"], "the system prompt")
|
||||
self.assertEqual(params["messages"],
|
||||
[{"role": "user", "content": "the groups"}])
|
||||
|
||||
|
||||
class TestCollectResults(RunLLMTestCase):
|
||||
"""Test cases for the batch result collection."""
|
||||
|
||||
@@ -251,11 +251,10 @@ class TestTallyCodings(unittest.TestCase):
|
||||
b"Alpha,A Singer,kw,"
|
||||
b"\"she said \"\"no\"\", twice\"\r\n")
|
||||
|
||||
def test_newline_in_quote_written_as_two_characters(
|
||||
self) -> None:
|
||||
r"""Test that a quote spanning two lyric lines is written
|
||||
with the two characters ``\n`` where the newline is,
|
||||
needing no RFC 4180 quoting."""
|
||||
def test_newline_in_quote_written_as_line_break(self) -> None:
|
||||
"""Test that a quote spanning two lyric lines is written
|
||||
with the lyric line-break convention " / " where the
|
||||
newline is, needing no RFC 4180 quoting."""
|
||||
self.__seed([("Alpha", "A Singer")])
|
||||
codings: dict[int, dict[str, list[str]]] = {
|
||||
1: {"kw": ["You needed me\nTo feel a little more"]}}
|
||||
@@ -267,13 +266,12 @@ class TestTallyCodings(unittest.TestCase):
|
||||
self.__output_csv.read_bytes(),
|
||||
b"Song,Artist Credit,Keyword,Quote\r\n"
|
||||
b"Alpha,A Singer,kw,"
|
||||
b"You needed me\\nTo feel a little more\r\n")
|
||||
b"You needed me / To feel a little more\r\n")
|
||||
|
||||
def test_multi_line_quotes_keep_one_row_per_line(self) -> None:
|
||||
r"""Test that the file holds exactly one line per row, no
|
||||
field carrying a line break, and that turning the two
|
||||
characters ``\n`` back into a single LF gives the quotes
|
||||
as the runs wrote them."""
|
||||
"""Test that the file holds exactly one line per row, no
|
||||
field carrying a line break, every LF inside a quote
|
||||
carried as the line-break convention " / " verbatim."""
|
||||
self.__seed([("Alpha", "A Singer")])
|
||||
codings: dict[int, dict[str, list[str]]] = {
|
||||
1: {"kw1": ["one line"],
|
||||
@@ -289,8 +287,9 @@ class TestTallyCodings(unittest.TestCase):
|
||||
rows: list[list[str]] = self.__read_rows()
|
||||
self.assertEqual(len(rows), 4)
|
||||
self.assertEqual(
|
||||
[x[3].replace("\\n", "\n") for x in rows[1:]],
|
||||
["one line", "first line\nsecond line", "a\nb\nc|d\ne"])
|
||||
[x[3] for x in rows[1:]],
|
||||
["one line", "first line / second line",
|
||||
"a / b / c|d / e"])
|
||||
|
||||
def test_empty_quote_lists_yield_an_empty_cell(self) -> None:
|
||||
"""Test that a settled keyword whose runs all gave an empty
|
||||
@@ -711,11 +710,11 @@ class TestTallyCodings(unittest.TestCase):
|
||||
self.assertEqual(self.__read_rows()[1:], [
|
||||
["Alpha", "A Singer", "kw", ""]])
|
||||
|
||||
def test_correction_with_an_escaped_newline(self) -> None:
|
||||
r"""Test that a correction whose two text fields carry the
|
||||
two characters ``\n`` matches and replaces a quote that
|
||||
genuinely spans two lines, the file itself holding one row
|
||||
per line."""
|
||||
def test_correction_with_a_line_break_quote(self) -> None:
|
||||
"""Test that a correction whose two text fields carry the
|
||||
line-break convention " / " matches and replaces a quote
|
||||
that genuinely spans two lines, the file itself holding
|
||||
one row per line."""
|
||||
self.__seed([("Alpha", "A Singer")])
|
||||
quote: str = "You needed me\nTo feel a little more"
|
||||
codings: dict[int, dict[str, list[str]]] \
|
||||
@@ -725,16 +724,16 @@ class TestTallyCodings(unittest.TestCase):
|
||||
path.write_bytes(
|
||||
b"Song ID,Run,Type,To Be Replaced,Correct Term\r\n"
|
||||
b"song-1,run1,evidence,"
|
||||
b"You needed me\\nTo feel a little more,"
|
||||
b"you needed me\\nTo feel a little more\r\n")
|
||||
b"You needed me / To feel a little more,"
|
||||
b"you needed me / To feel a little more\r\n")
|
||||
self.assertEqual(len(path.read_bytes().split(b"\r\n")), 3)
|
||||
status: int
|
||||
status, _ = self.__run_tally("--corrections", str(path))
|
||||
self.assertEqual(status, 0)
|
||||
self.assertEqual(self.__read_rows()[1:], [
|
||||
["Alpha", "A Singer", "kw",
|
||||
"You needed me\\nTo feel a little more"
|
||||
"|you needed me\\nTo feel a little more"]])
|
||||
"You needed me / To feel a little more"
|
||||
"|you needed me / To feel a little more"]])
|
||||
|
||||
def test_stale_correction_row_rejected(self) -> None:
|
||||
"""Test that a correction matching nothing fails the run,
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
# Tools for A Feminist Audit of Pop Music.
|
||||
# Copyright 2026 imacat. All rights reserved.
|
||||
# Authors:
|
||||
# imacat@mail.imacat.idv.tw (imacat), 2026/8/15
|
||||
# AI assistance: Claude Code (Anthropic)
|
||||
"""Unit tests for the group tally module."""
|
||||
import csv
|
||||
import io
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from contextlib import redirect_stderr
|
||||
from pathlib import Path
|
||||
|
||||
from pop_fem_audit_tools.commands import tally_groups
|
||||
|
||||
|
||||
class TestTallyGroups(unittest.TestCase):
|
||||
"""Test cases for the group tally."""
|
||||
|
||||
def setUp(self) -> None:
|
||||
"""Create the run directories and the input files."""
|
||||
tmp: tempfile.TemporaryDirectory[str] \
|
||||
= tempfile.TemporaryDirectory()
|
||||
self.addCleanup(tmp.cleanup)
|
||||
self.__dir: Path = Path(tmp.name)
|
||||
self.__runs: list[Path] = []
|
||||
number: int
|
||||
for number in (1, 2, 3):
|
||||
run_dir: Path = self.__dir / f"run{number}"
|
||||
run_dir.mkdir()
|
||||
self.__runs.append(run_dir)
|
||||
self.__valid: Path = self.__dir / "valid-keywords.txt"
|
||||
self.__valid.write_text(
|
||||
"alpha\nbeta\ngamma\ndelta\n", encoding="utf-8")
|
||||
self.__output_csv: Path \
|
||||
= self.__dir / "results" / "groups.csv"
|
||||
|
||||
def __write_runs(
|
||||
self, runs: list[dict[str, list[str]]]) -> None:
|
||||
"""Write the three runs' output.jsonl files.
|
||||
|
||||
:param runs: The selections of each run, keyed by the
|
||||
group record ID.
|
||||
:return: None.
|
||||
"""
|
||||
run_dir: Path
|
||||
selections: dict[str, list[str]]
|
||||
for run_dir, selections in zip(self.__runs, runs):
|
||||
lines: list[str] = [
|
||||
json.dumps({"id": x, "text": json.dumps(y),
|
||||
"stop_reason": "end_turn"})
|
||||
for x, y in selections.items()]
|
||||
(run_dir / "output.jsonl").write_text(
|
||||
"\n".join(lines) + "\n", encoding="utf-8")
|
||||
|
||||
def __run_tally(self) -> tuple[int, str]:
|
||||
"""Run the tally command against the run directories.
|
||||
|
||||
:return: The exit status and the standard error text.
|
||||
"""
|
||||
stderr: io.StringIO = io.StringIO()
|
||||
status: int
|
||||
with redirect_stderr(stderr):
|
||||
status = tally_groups.main(
|
||||
[str(x) for x in self.__runs]
|
||||
+ [str(self.__valid), str(self.__output_csv)])
|
||||
return status, stderr.getvalue()
|
||||
|
||||
def __read_rows(self) -> list[list[str]]:
|
||||
"""Read the written CSV file back as rows.
|
||||
|
||||
:return: The rows, the header row included.
|
||||
"""
|
||||
with open(self.__output_csv, encoding="utf-8",
|
||||
newline="") as file:
|
||||
return list(csv.reader(file))
|
||||
|
||||
def test_majority_vote_settles_two_of_three(self) -> None:
|
||||
"""Test that a pair needs at least two votes to settle."""
|
||||
self.__write_runs([
|
||||
{"group-one": ["alpha", "beta", "gamma"]},
|
||||
{"group-one": ["alpha", "beta"]},
|
||||
{"group-one": ["alpha"]}])
|
||||
status: int
|
||||
status, _ = self.__run_tally()
|
||||
self.assertEqual(status, 0)
|
||||
self.assertEqual(self.__read_rows(), [
|
||||
["Group", "Keyword", "Votes"],
|
||||
["one", "alpha", "3"],
|
||||
["one", "beta", "2"]])
|
||||
|
||||
def test_rows_sorted_by_group_then_keyword(self) -> None:
|
||||
"""Test the row order: group name, then keyword, by
|
||||
Unicode code point."""
|
||||
selections: dict[str, list[str]] = {
|
||||
"group-women-power": ["beta", "alpha"],
|
||||
"group-masculine": ["delta", "gamma"]}
|
||||
self.__write_runs([selections, selections, selections])
|
||||
status: int
|
||||
status, _ = self.__run_tally()
|
||||
self.assertEqual(status, 0)
|
||||
self.assertEqual(self.__read_rows(), [
|
||||
["Group", "Keyword", "Votes"],
|
||||
["masculine", "delta", "3"],
|
||||
["masculine", "gamma", "3"],
|
||||
["women-power", "alpha", "3"],
|
||||
["women-power", "beta", "3"]])
|
||||
|
||||
def test_output_is_crlf_with_header(self) -> None:
|
||||
"""Test the written bytes: RFC 4180, CRLF, header row."""
|
||||
selections: dict[str, list[str]] = {"group-one": ["alpha"]}
|
||||
self.__write_runs([selections, selections, selections])
|
||||
status: int
|
||||
status, _ = self.__run_tally()
|
||||
self.assertEqual(status, 0)
|
||||
self.assertEqual(
|
||||
self.__output_csv.read_bytes(),
|
||||
b"Group,Keyword,Votes\r\n"
|
||||
b"one,alpha,3\r\n")
|
||||
|
||||
def test_out_of_vocabulary_item_casts_no_vote(self) -> None:
|
||||
"""Test that a selected item outside the valid keyword
|
||||
list is dropped, each occurrence reported on standard
|
||||
error."""
|
||||
selections: dict[str, list[str]] = {
|
||||
"group-one": ["alpha", "hallucinated"]}
|
||||
self.__write_runs([selections, selections, selections])
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_tally()
|
||||
self.assertEqual(status, 0)
|
||||
self.assertEqual(self.__read_rows(), [
|
||||
["Group", "Keyword", "Votes"],
|
||||
["one", "alpha", "3"]])
|
||||
self.assertEqual(stderr.count(
|
||||
"dropped out-of-vocabulary item \"hallucinated\""), 3)
|
||||
|
||||
def test_duplicate_selection_counts_once(self) -> None:
|
||||
"""Test that a keyword listed twice in one run's selection
|
||||
casts one vote only."""
|
||||
self.__write_runs([
|
||||
{"group-one": ["alpha", "alpha"]},
|
||||
{"group-one": []},
|
||||
{"group-one": []}])
|
||||
status: int
|
||||
status, _ = self.__run_tally()
|
||||
self.assertEqual(status, 0)
|
||||
self.assertEqual(self.__read_rows(),
|
||||
[["Group", "Keyword", "Votes"]])
|
||||
|
||||
def test_empty_selections_yield_header_only(self) -> None:
|
||||
"""Test that no settled pair still writes the header."""
|
||||
selections: dict[str, list[str]] = {"group-one": []}
|
||||
self.__write_runs([selections, selections, selections])
|
||||
status: int
|
||||
status, _ = self.__run_tally()
|
||||
self.assertEqual(status, 0)
|
||||
self.assertEqual(self.__read_rows(),
|
||||
[["Group", "Keyword", "Votes"]])
|
||||
|
||||
def test_mismatched_group_sets_fail(self) -> None:
|
||||
"""Test that runs covering different groups fail, nothing
|
||||
written."""
|
||||
self.__write_runs([
|
||||
{"group-one": ["alpha"]},
|
||||
{"group-one": ["alpha"]},
|
||||
{"group-two": ["alpha"]}])
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_tally()
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertIn("do not cover the same groups", stderr)
|
||||
self.assertFalse(self.__output_csv.exists())
|
||||
|
||||
def test_id_without_the_group_prefix_fails(self) -> None:
|
||||
"""Test that a record ID without the "group-" prefix
|
||||
fails the run."""
|
||||
selections: dict[str, list[str]] = {"song-1": ["alpha"]}
|
||||
self.__write_runs([selections, selections, selections])
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_tally()
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertIn("group-", stderr)
|
||||
self.assertFalse(self.__output_csv.exists())
|
||||
|
||||
def test_duplicate_record_fails(self) -> None:
|
||||
"""Test that two records of one group in one run fail the
|
||||
run."""
|
||||
selections: dict[str, list[str]] = {"group-one": ["alpha"]}
|
||||
self.__write_runs([selections, selections, selections])
|
||||
path: Path = self.__runs[0] / "output.jsonl"
|
||||
path.write_text(
|
||||
path.read_text(encoding="utf-8")
|
||||
+ json.dumps({"id": "group-one",
|
||||
"text": json.dumps(["beta"])}) + "\n",
|
||||
encoding="utf-8")
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_tally()
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertIn("duplicate record", stderr)
|
||||
|
||||
def test_text_not_an_array_of_strings_fails(self) -> None:
|
||||
"""Test that a "text" that is not a JSON array of strings
|
||||
fails the run."""
|
||||
self.__write_runs([
|
||||
{"group-one": ["alpha"]},
|
||||
{"group-one": ["alpha"]},
|
||||
{"group-one": ["alpha"]}])
|
||||
(self.__runs[2] / "output.jsonl").write_text(
|
||||
json.dumps({"id": "group-one",
|
||||
"text": json.dumps({"alpha": []})})
|
||||
+ "\n", encoding="utf-8")
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_tally()
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertIn("JSON array of strings", stderr)
|
||||
|
||||
def test_unsuccessful_record_fails(self) -> None:
|
||||
"""Test that an errored record fails the run."""
|
||||
selections: dict[str, list[str]] = {"group-one": ["alpha"]}
|
||||
self.__write_runs([selections, selections, selections])
|
||||
(self.__runs[1] / "output.jsonl").write_text(
|
||||
json.dumps({"id": "group-one", "error": "overloaded"})
|
||||
+ "\n", encoding="utf-8")
|
||||
status: int
|
||||
stderr: str
|
||||
status, stderr = self.__run_tally()
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertIn("not a successful result", stderr)
|
||||
|
||||
def test_missing_valid_keywords_file_fails(self) -> None:
|
||||
"""Test that a missing valid keyword list fails the run."""
|
||||
selections: dict[str, list[str]] = {"group-one": ["alpha"]}
|
||||
self.__write_runs([selections, selections, selections])
|
||||
self.__valid.unlink()
|
||||
status: int
|
||||
status, _ = self.__run_tally()
|
||||
self.assertNotEqual(status, 0)
|
||||
self.assertFalse(self.__output_csv.exists())
|
||||
Reference in New Issue
Block a user