cbg342 commited on
Commit
3614695
1 Parent(s): 98295c4

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -0
app.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, random, re
2
+ from fractions import Fraction
3
+ from midiutil.MidiFile import MIDIFile
4
+ import streamlit as st
5
+ import mido, openai
6
+
7
+ if 'path' not in st.session_state:
8
+ st.session_state['path'] = os.path.realpath(os.path.dirname(__file__))
9
+ if 'sessionID' not in st.session_state:
10
+ st.session_state['sessionID'] = random.randint(0,99999999)
11
+ if 'history' not in st.session_state:
12
+ st.session_state['history'] = []
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
+ monster = r'(?<![A-Za-z\d])([A-G](?:#|b)?\d(?:-\d+(?:\/\d+)?(?:-\d+(?:\.\d+)?)?)+)(?![A-Za-z\d])'
17
+
18
+ def noteToInt(n):
19
+ oct = int(n[-1])
20
+ letter = n[:-1]
21
+ id = 0
22
+ for ix, x in enumerate(notes):
23
+ for y in x:
24
+ if letter == y:
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 = []
32
+ globalT = 0
33
+ opens = {}
34
+ for track in midIn.tracks:
35
+ for msg in track:
36
+ if msg.type == 'note_on' or msg.type == 'note_off':
37
+ globalT += msg.time/ticks
38
+ if msg.note in opens:
39
+ noteTime = opens[msg.note]
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
+ midOut.append('-'.join([notes[msg.note%12][0]+str(msg.note//12-1), noteDur, str(round(noteTime,3))]))
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##### 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.\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.')
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)
59
+ with col1:
60
+ newSession = st.checkbox('New Session', True)
61
+ with col2:
62
+ showOutput = st.checkbox('Show Output', True)
63
+ uploadMidi = st.file_uploader('Upload a midi file (OPTIONAL)')
64
+ col3, col4 = st.columns(2)
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:
73
+ filename = ''.join(uploadMidi.name.split('.')[:-1])+str(st.session_state['sessionID'])+'.'+''.join(uploadMidi.name.split('.')[-1])
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
+
81
+ openai.api_key = openaikey
82
+ with st.spinner('Talking to OpenAI...'):
83
+ r = openai.ChatCompletion.create(
84
+ model=modelV.lower(),
85
+ messages=st.session_state['history']
86
+ )
87
+ response = r['choices'][0]['message']['content']
88
+ st.session_state['history'].append({'role': 'assistant', 'content': response})
89
+
90
+ noteInfo = []
91
+ for i in re.findall(monster, response):
92
+ n = i.split('-')
93
+ noteInfo.append([noteToInt(n[0]), float(Fraction(n[1])) * 4, float(n[2])]) #note, duration, time
94
+
95
+ song = MIDIFile(1, deinterleave=False)
96
+ for i in noteInfo:
97
+ pitch, dur, time = i
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']:
102
+ st.session_state['downloadable'] = True
103
+ else:
104
+ st.warning('Make sure OpenAI key, prompt, and system prompt are entered', icon='⚠️')
105
+ with col4:
106
+ if st.session_state['downloadable']:
107
+ with open(os.path.join(st.session_state['path'], 'output.mid'), 'rb') as f:
108
+ st.download_button('Download Midi', f, file_name='output.mid')
109
+ if showOutput:
110
+ with st.container():
111
+ for i in st.session_state['history']:
112
+ st.text(i['role']+': '+i['content']+'\n')
113
+
114
+ with m2t:
115
+ inMidi = st.file_uploader('Input')
116
+ if st.button('Convert', key='1'):
117
+ if inMidi:
118
+ filename = ''.join(inMidi.name.split('.')[:-1]) + str(st.session_state['sessionID']) + '.' + ''.join(inMidi.name.split('.')[-1])
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(monster, inText):
130
+ n = i.split('-')
131
+ noteInfo.append([noteToInt(n[0]), float(Fraction(n[1])) * 4, float(n[2])])
132
+ song = MIDIFile(1, deinterleave=False)
133
+ for i in noteInfo:
134
+ pitch, dur, time = i
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:
139
+ st.download_button('Download Midi', f, file_name='output.mid')