Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -13,7 +13,8 @@ if 'history' not in st.session_state:
|
|
13 |
if 'downloadable' not in st.session_state:
|
14 |
st.session_state['downloadable'] = False
|
15 |
notes = [['C'], ['Db', 'C#'], ['D'], ['Eb', 'D#'], ['E'], ['F'], ['Gb', 'F#'], ['G'], ['Ab', 'G#'], ['A'], ['Bb', 'A#'], ['B']]
|
16 |
-
|
|
|
17 |
|
18 |
def noteToInt(n):
|
19 |
oct = int(n[-1])
|
@@ -25,7 +26,7 @@ def noteToInt(n):
|
|
25 |
id = ix
|
26 |
return id+oct*12+12
|
27 |
|
28 |
-
def midiToStr(mPath):
|
29 |
midIn = mido.MidiFile(os.path.expanduser(mPath))
|
30 |
ticks = midIn.ticks_per_beat
|
31 |
midOut = []
|
@@ -40,19 +41,23 @@ def midiToStr(mPath):
|
|
40 |
noteTime = int(noteTime) if noteTime.is_integer() else noteTime
|
41 |
noteDur = str(Fraction((globalT-noteTime)/4))
|
42 |
noteDur = str(round((globalT-noteTime),3)) if len(noteDur)>=6 else noteDur
|
43 |
-
|
|
|
|
|
|
|
44 |
del opens[msg.note]
|
45 |
if msg.type == 'note_on':
|
46 |
opens[msg.note] = globalT
|
47 |
return ', '.join(midOut)
|
48 |
|
49 |
st.markdown('# GPT-4 2 Midi\n#### AI Generated Polyphonic Music\n##### plus conversion tools for use with Chat-GPT\napp by [d3nt](https://github.com/d3n7/)')
|
|
|
50 |
main, m2t, t2m = st.tabs(['GPT4-To-Midi', 'Midi-2-Text', 'Text-2-Midi'])
|
51 |
|
52 |
with main:
|
53 |
userPrompt = st.text_input('Prompt', 'Full piece of sad music with multiple parts. Plan out the structure beforehand, including chords, parts (soprano, alto, tenor, bass), meter, etc.')
|
54 |
with st.expander('System Prompt'):
|
55 |
-
sysPrompt = st.text_input('', 'You are MusicGPT, a music creation and completion chat bot that. When a user gives you a prompt, you return them a song showing the notes, durations, and times that they occur. Respond with just the music
|
56 |
openaikey = st.text_input('OpenAI API Key', type='password')
|
57 |
modelV = st.selectbox('Model', ('GPT-4', 'GPT-3.5-Turbo'))
|
58 |
col1, col2 = st.columns(2)
|
@@ -65,8 +70,10 @@ with main:
|
|
65 |
with col3:
|
66 |
if st.button('Ask GPT'):
|
67 |
if userPrompt != '' and sysPrompt != '' and openaikey != '':
|
|
|
|
|
68 |
if newSession:
|
69 |
-
st.session_state['history'] = [{'role': 'system', 'content': sysPrompt}]
|
70 |
|
71 |
prompt = userPrompt
|
72 |
if uploadMidi:
|
@@ -74,7 +81,7 @@ with main:
|
|
74 |
midiPath = os.path.join(st.session_state['path'], filename)
|
75 |
with open(midiPath, 'wb') as f:
|
76 |
f.write(uploadMidi.getbuffer())
|
77 |
-
prompt += '\n'+midiToStr(midiPath)
|
78 |
os.remove(midiPath)
|
79 |
st.session_state['history'].append({'role': 'user', 'content': prompt})
|
80 |
|
@@ -88,14 +95,23 @@ with main:
|
|
88 |
st.session_state['history'].append({'role': 'assistant', 'content': response})
|
89 |
|
90 |
noteInfo = []
|
91 |
-
for i in re.findall(
|
92 |
n = i.split('-')
|
93 |
-
|
|
|
|
|
|
|
94 |
|
95 |
song = MIDIFile(1, deinterleave=False)
|
|
|
96 |
for i in noteInfo:
|
97 |
-
|
|
|
|
|
|
|
98 |
song.addNote(0, 0, pitch, time, dur, 100)
|
|
|
|
|
99 |
with open(os.path.join(st.session_state['path'], 'output.mid'), 'wb') as f:
|
100 |
song.writeFile(f)
|
101 |
if not st.session_state['downloadable']:
|
@@ -119,20 +135,30 @@ with m2t:
|
|
119 |
midiPath = os.path.join(st.session_state['path'], filename)
|
120 |
with open(midiPath, 'wb') as f:
|
121 |
f.write(inMidi.getbuffer())
|
122 |
-
st.text_area('Output', midiToStr(midiPath))
|
123 |
os.remove(midiPath)
|
124 |
|
125 |
with t2m:
|
126 |
inText = st.text_input('Input')
|
127 |
if st.button('Convert', key='2'):
|
|
|
128 |
noteInfo = []
|
129 |
-
for i in re.findall(
|
130 |
n = i.split('-')
|
131 |
-
|
|
|
|
|
|
|
132 |
song = MIDIFile(1, deinterleave=False)
|
|
|
133 |
for i in noteInfo:
|
134 |
-
|
|
|
|
|
|
|
135 |
song.addNote(0, 0, pitch, time, dur, 100)
|
|
|
|
|
136 |
with open(os.path.join(st.session_state['path'], 't2m.mid'), 'wb') as f:
|
137 |
song.writeFile(f)
|
138 |
with open(os.path.join(st.session_state['path'], 't2m.mid'), 'rb') as f:
|
|
|
13 |
if 'downloadable' not in st.session_state:
|
14 |
st.session_state['downloadable'] = False
|
15 |
notes = [['C'], ['Db', 'C#'], ['D'], ['Eb', 'D#'], ['E'], ['F'], ['Gb', 'F#'], ['G'], ['Ab', 'G#'], ['A'], ['Bb', 'A#'], ['B']]
|
16 |
+
monsters = [r'(?<![A-Za-z\d])([A-G](?:#|b)?\d-(?:\d+\/\d+|\d+))(?![A-Za-z\d])', r'(?<![A-Za-z\d])([A-G](?:#|b)?\d(?:-\d+(?:\/\d+)?(?:-\d+(?:\.\d+)?)?)+)(?![A-Za-z\d])']
|
17 |
+
examples = ['\n\nNotation looks like this:\n(Note-duration)\nC4-1/4, Eb4-1/4, D4-1/8, Eb4-1/8, C4-1/4', '\n\nNotation looks like this:\n(Note-duration-time in beats)\nC4-1/4-0, Eb4-1/8-2.5, D4-1/4-3, F4-1/4-3 etc.']
|
18 |
|
19 |
def noteToInt(n):
|
20 |
oct = int(n[-1])
|
|
|
26 |
id = ix
|
27 |
return id+oct*12+12
|
28 |
|
29 |
+
def midiToStr(mPath, nIndex):
|
30 |
midIn = mido.MidiFile(os.path.expanduser(mPath))
|
31 |
ticks = midIn.ticks_per_beat
|
32 |
midOut = []
|
|
|
41 |
noteTime = int(noteTime) if noteTime.is_integer() else noteTime
|
42 |
noteDur = str(Fraction((globalT-noteTime)/4))
|
43 |
noteDur = str(round((globalT-noteTime),3)) if len(noteDur)>=6 else noteDur
|
44 |
+
if nIndex:
|
45 |
+
midOut.append('-'.join([notes[msg.note%12][0]+str(msg.note//12-1), noteDur, str(round(noteTime,3))]))
|
46 |
+
else:
|
47 |
+
midOut.append('-'.join([notes[msg.note%12][0]+str(msg.note//12-1), noteDur]))
|
48 |
del opens[msg.note]
|
49 |
if msg.type == 'note_on':
|
50 |
opens[msg.note] = globalT
|
51 |
return ', '.join(midOut)
|
52 |
|
53 |
st.markdown('# GPT-4 2 Midi\n#### AI Generated Polyphonic Music\n##### plus conversion tools for use with Chat-GPT\napp by [d3nt](https://github.com/d3n7/)')
|
54 |
+
notation = st.selectbox('Notation', ('Polyphonic', 'Monophonic'))
|
55 |
main, m2t, t2m = st.tabs(['GPT4-To-Midi', 'Midi-2-Text', 'Text-2-Midi'])
|
56 |
|
57 |
with main:
|
58 |
userPrompt = st.text_input('Prompt', 'Full piece of sad music with multiple parts. Plan out the structure beforehand, including chords, parts (soprano, alto, tenor, bass), meter, etc.')
|
59 |
with st.expander('System Prompt'):
|
60 |
+
sysPrompt = st.text_input('', 'You are MusicGPT, a music creation and completion chat bot that. When a user gives you a prompt, you return them a song showing the notes, durations, and times that they occur. Respond with just the music.')
|
61 |
openaikey = st.text_input('OpenAI API Key', type='password')
|
62 |
modelV = st.selectbox('Model', ('GPT-4', 'GPT-3.5-Turbo'))
|
63 |
col1, col2 = st.columns(2)
|
|
|
70 |
with col3:
|
71 |
if st.button('Ask GPT'):
|
72 |
if userPrompt != '' and sysPrompt != '' and openaikey != '':
|
73 |
+
notationIndex = int(notation=='Polyphonic')
|
74 |
+
|
75 |
if newSession:
|
76 |
+
st.session_state['history'] = [{'role': 'system', 'content': sysPrompt+examples[notationIndex]}]
|
77 |
|
78 |
prompt = userPrompt
|
79 |
if uploadMidi:
|
|
|
81 |
midiPath = os.path.join(st.session_state['path'], filename)
|
82 |
with open(midiPath, 'wb') as f:
|
83 |
f.write(uploadMidi.getbuffer())
|
84 |
+
prompt += '\n'+midiToStr(midiPath, notationIndex)
|
85 |
os.remove(midiPath)
|
86 |
st.session_state['history'].append({'role': 'user', 'content': prompt})
|
87 |
|
|
|
95 |
st.session_state['history'].append({'role': 'assistant', 'content': response})
|
96 |
|
97 |
noteInfo = []
|
98 |
+
for i in re.findall(monsters[notationIndex], response):
|
99 |
n = i.split('-')
|
100 |
+
if notationIndex:
|
101 |
+
noteInfo.append([noteToInt(n[0]), float(Fraction(n[1]))*4, float(n[2])]) #note, duration, time
|
102 |
+
else:
|
103 |
+
noteInfo.append([noteToInt(n[0]), float(Fraction(n[1]))*4]) # note, duration
|
104 |
|
105 |
song = MIDIFile(1, deinterleave=False)
|
106 |
+
time = 0
|
107 |
for i in noteInfo:
|
108 |
+
if notationIndex:
|
109 |
+
pitch, dur, time = i
|
110 |
+
else:
|
111 |
+
pitch, dur = i
|
112 |
song.addNote(0, 0, pitch, time, dur, 100)
|
113 |
+
if not notationIndex:
|
114 |
+
time += dur
|
115 |
with open(os.path.join(st.session_state['path'], 'output.mid'), 'wb') as f:
|
116 |
song.writeFile(f)
|
117 |
if not st.session_state['downloadable']:
|
|
|
135 |
midiPath = os.path.join(st.session_state['path'], filename)
|
136 |
with open(midiPath, 'wb') as f:
|
137 |
f.write(inMidi.getbuffer())
|
138 |
+
st.text_area('Output', midiToStr(midiPath, notation=='Polyphonic'))
|
139 |
os.remove(midiPath)
|
140 |
|
141 |
with t2m:
|
142 |
inText = st.text_input('Input')
|
143 |
if st.button('Convert', key='2'):
|
144 |
+
notationIndex = int(notation=='Polyphonic')
|
145 |
noteInfo = []
|
146 |
+
for i in re.findall(monsters[notationIndex], inText):
|
147 |
n = i.split('-')
|
148 |
+
if notationIndex:
|
149 |
+
noteInfo.append([noteToInt(n[0]), float(Fraction(n[1])) * 4, float(n[2])]) # note, duration, time
|
150 |
+
else:
|
151 |
+
noteInfo.append([noteToInt(n[0]), float(Fraction(n[1])) * 4]) # note, duration
|
152 |
song = MIDIFile(1, deinterleave=False)
|
153 |
+
time = 0
|
154 |
for i in noteInfo:
|
155 |
+
if notationIndex:
|
156 |
+
pitch, dur, time = i
|
157 |
+
else:
|
158 |
+
pitch, dur = i
|
159 |
song.addNote(0, 0, pitch, time, dur, 100)
|
160 |
+
if not notationIndex:
|
161 |
+
time += dur
|
162 |
with open(os.path.join(st.session_state['path'], 't2m.mid'), 'wb') as f:
|
163 |
song.writeFile(f)
|
164 |
with open(os.path.join(st.session_state['path'], 't2m.mid'), 'rb') as f:
|