File size: 9,465 Bytes
c10c249
cc4a711
c10c249
 
 
 
 
 
 
 
 
 
 
 
 
cd1a8cb
c10c249
 
 
c5824b7
 
210ae7b
 
c10c249
 
 
 
2dbbde3
 
 
 
c5824b7
6387673
c5824b7
 
 
32af644
 
 
 
 
 
 
5791635
a0baf01
 
 
5791635
 
 
 
 
32af644
 
5791635
 
 
32af644
 
c5824b7
5791635
c5824b7
 
 
b3d72a4
0c2c10c
 
b3d72a4
 
 
 
c10c249
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b3d72a4
c10c249
 
 
 
 
 
7724541
c10c249
7724541
c10c249
7724541
c10c249
 
 
 
 
72ef07a
e9c4cef
72ef07a
 
5949155
 
 
 
 
 
 
907d5bd
b7c7796
21fb761
907d5bd
 
 
 
 
 
 
 
72ef07a
7648069
c10c249
7648069
 
500d228
5e34946
7648069
72ef07a
7648069
e9c4cef
7648069
e9c4cef
ee46fa2
7648069
ba9437d
c10c249
ba9437d
 
5949155
 
 
 
 
 
ba9437d
 
 
 
 
 
 
 
 
 
b3d72a4
ba9437d
 
 
 
 
 
 
c10c249
 
 
e9c4cef
 
18fbc7d
72ef07a
4d700d3
 
c10c249
 
 
9b74ea3
c5824b7
c10c249
 
 
 
 
 
 
 
 
18fbc7d
c10c249
 
 
 
 
 
 
 
 
 
 
c5824b7
7648069
210ae7b
7648069
210ae7b
 
c5824b7
 
907d5bd
 
 
 
 
 
 
b49f486
c10c249
 
 
cc4a711
c5a7526
c10c249
58672a4
 
c10c249
 
 
 
 
0c2c10c
 
46493b6
 
c10c249
5015e4e
c10c249
cc4a711
c10c249
a0baf01
e9c4cef
 
72ef07a
d9c1d7b
c10c249
b3d72a4
 
c10c249
72ef07a
e9c4cef
72ef07a
 
 
c10c249
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#================================================================
# https://huggingface.co/spaces/asigalov61/MIDI-Identification
#================================================================

import os
import hashlib

import time
import datetime
from pytz import timezone

import copy
from collections import Counter
import random
import statistics
import re

import gradio as gr

from huggingface_hub import InferenceClient

from datasets import load_dataset

import TMIDIX

#==========================================================================================================

HF_TOKEN = os.getenv('HF_TOKEN')

#==========================================================================================================

def format_table_data(data_string):
    
    # Split the string into rows based on newlines
    rows = data_string.strip().split("\n")

    # Initialize a list to store the formatted data
    formatted_data = []

    for row in rows:
        # Split each row into columns based on the separator '|' and strip extra spaces
        columns = row.split("|")
        formatted_row = [cell.strip() for cell in columns]
        
        # Remove cells with only "-" symbols
        formatted_row = [cell for cell in formatted_row if not all(char == '-' for char in cell)]

        # Handle uneven rows by ensuring each row has the same number of columns
        max_columns = max(len(columns) for columns in formatted_data) if formatted_data else len(columns)
        while len(formatted_row) < max_columns:
            formatted_row.append("")  # Add empty strings to fill the row
        
        formatted_data.append(formatted_row)
    
    # Handle case where new rows have more columns than previous rows
    max_columns = max(len(row) for row in formatted_data)
    for row in formatted_data:
        while len(row) < max_columns:
            row.append("")  # Add empty strings to fill the row

    return formatted_data

#==========================================================================================================


MODELS = {'Mistral Nemo Instruct 2407': 'mistralai/Mistral-Nemo-Instruct-2407'
         }

#==========================================================================================================

def ID_MIDI(input_midi, input_model):
    
    print('*' * 70)
    print('Req start time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
    start_time = time.time()
    
    print('=' * 70)
    print('Loading MIDI...')

    fn = os.path.basename(input_midi)
    fn1 = fn.split('.')[0]

    fdata = open(input_midi, 'rb').read()

    input_midi_md5hash = hashlib.md5(fdata).hexdigest()
    
    print('=' * 70)
    print('Requested settings:')
    print('=' * 70)
    print('Input MIDI file name:', fn)
    print('Input MIDI md5 hash', input_midi_md5hash)
    print('Input model:', input_model)
    print('=' * 70)
    print('Processing MIDI...Please wait...')
    
    #=======================================================
    # START PROCESSING

    new_midi_data = TMIDIX.score2midi(TMIDIX.midi2score(fdata))
    
    new_midi_md5hash = hashlib.md5(new_midi_data).hexdigest()

    print('New md5 hash:', new_midi_md5hash)
    
    print('Done!')
    print('=' * 70)
    print('Processing...Please wait...')

    output_str = 'None'
    output_midi_records_count = 0
    output_midi_src_dataset= 'Unknown'
    output_midi_path_str = 'None'

    raw_score = TMIDIX.midi2single_track_ms_score(fdata)
    escore_notes = TMIDIX.advanced_score_processor(raw_score, return_enhanced_score_notes=True)[0]
    escore_notes = TMIDIX.augment_enhanced_score_notes(escore_notes, sort_drums_last=True)

    output_midi_src_dataset = 'unknown'
    output_midi_path_str = 'none'

    if new_midi_md5hash in monster_midi_titles['md5_hashes_titles_dict']:
        title = random.choice(monster_midi_titles['md5_hashes_titles_dict'][new_midi_md5hash]).split(' --- ')

        song = title[0]
        artist = title[1]

        song_description = TMIDIX.escore_notes_to_text_description(escore_notes, song_name=song, artist_name=artist)

    else:
        song_description = TMIDIX.escore_notes_to_text_description(escore_notes)
    
    if new_midi_md5hash in midid_md5_hashes:

        midid_entry_idx = midid_md5_hashes.index(new_midi_md5hash)

        MIDID_record = midid_dataset[midid_entry_idx]['midid']

        output_midi_records_count = len(MIDID_record)

        output_entry = random.choice(MIDID_record)

        output_midi_src_dataset = output_entry[0]

        output_midi_path_str = TMIDIX.clean_string(output_entry[1], regex=r'[^a-zA-Z0-9.() \n]')

    client = InferenceClient(api_key=HF_TOKEN)

    prompt = "Please create a summary table for a MIDI file based on the following keywords strings, best possible description and best possible summary fields. Please respond with the table only. Do not say anything else. Thank you."
    
    data = 'Source MIDI dataset: ' + output_midi_src_dataset + '\n\n'
    data += 'MIDI keywords strings:' + '\n'
    data += output_midi_path_str + '\n\n'
    data += 'Music description:' + '\n'
    data += song_description

    
    messages = [
        {
            "role": "user",
            "content": prompt + "\n\n" + data
        }
    ]

    completion = client.chat.completions.create(
        #model="Qwen/Qwen2.5-72B-Instruct",
        model=MODELS[input_model],
        messages=messages, 
        max_tokens=500
    )

    output_str = completion.choices[0].message['content']

    output_table_data = format_table_data(output_str)
    
    print('Done!')
    print('=' * 70)
    print('Original MIDI unique records count', output_midi_records_count)
    print('Original MIDI dataset', output_midi_src_dataset)
    print('Original MIDI path string', data)
    print('=' * 70)
    print(output_str)
    print('=')

    #========================================================

    output_midi_md5 = str(new_midi_md5hash)
   
    #========================================================

    print('Req end time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
    print('-' * 70)
    print('Req execution time:', (time.time() - start_time), 'sec')
    print('*' * 70)
    
    #========================================================
    
    return output_midi_md5, output_midi_records_count, output_midi_src_dataset, data, output_table_data
    
#==========================================================================================================

if __name__ == "__main__":

    PDT = timezone('US/Pacific')
    
    print('=' * 70)
    print('App start time: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now(PDT)))
    print('=' * 70)

    print('Loading MIDID database...')
    midid_dataset = load_dataset("asigalov61/MIDID")['train']

    midid_md5_hashes = midid_dataset['midi_hash']

    print('Done!')
    print('=' * 70)

    print('Loading Monster MIDI titles database...')

    monster_midi_titles = TMIDIX.Tegridy_Any_Pickle_File_Reader('Monster_MIDI_Titles_Database_CC_BY_NC_SA.pickle')
    
    print('Done!')
    print('=' * 70)
    
    app = gr.Blocks()
    
    with app:
        
        gr.Markdown("<h1 style='text-align: center; margin-bottom: 1rem'>MIDI Identification</h1>")
        gr.Markdown("<h1 style='text-align: center; margin-bottom: 1rem'>Identify any MIDI in a comprehensive database of 2.32M+ MIDI records</h1>")
        
        gr.Markdown("This is a demo for tegridy-tools, MIDID and Monster MIDI dataset\n\n"
                    "Please see [tegridy-tools](https://github.com/asigalov61/tegridy-tools), [MIDID](https://huggingface.co/datasets/asigalov61/MIDID) and [Monster MIDI Dataset](https://github.com/asigalov61/Monster-MIDI-Dataset) repos for more information\n\n"
                   )
        
        gr.Markdown("## Upload your MIDI")
        
        input_midi = gr.File(label="Input MIDI", file_types=[".midi", ".mid", ".kar"], type="filepath")
        input_model = gr.Dropdown(['Mistral Nemo Instruct 2407', 'Mistral Nemo Instruct 2407'], 
                                  value='Mistral Nemo Instruct 2407', 
                                  label='Select model'
                                 )

        submit = gr.Button("Identify MIDI", variant="primary")

        gr.Markdown("## MIDI identification results")
        
        output_midi_md5 = gr.Textbox(label="Monster MIDI dataset md5 hash")
        output_midi_records_count = gr.Textbox(label="Original MIDI unique records count")
        output_midi_src_dataset = gr.Textbox(label="Original MIDI dataset pretty name")
        output_midi_path_str = gr.Textbox(label="Original MIDI raw path string")
        output_MIDID_results_table = gr.Dataframe(label="MIDID database results table", wrap=True, col_count=(3, 'dynamic'))
        
        run_event = submit.click(ID_MIDI, [input_midi,
                                           input_model
                                              ],
                                                [output_midi_md5,
                                                 output_midi_records_count,
                                                 output_midi_src_dataset,
                                                 output_midi_path_str,                                                 
                                                 output_MIDID_results_table
                                                ])
        
    app.queue().launch()