Krish Shah-Nathwani commited on
Commit
a2b8990
·
1 Parent(s): f4f0a66

adding in machine learning LOL

Browse files
Files changed (3) hide show
  1. README.md +6 -15
  2. app.py +28 -197
  3. requirements.txt +3 -1
README.md CHANGED
@@ -1,21 +1,12 @@
1
  ---
2
-
3
- title: "Note → Chord Chatbot"
4
-
5
- emoji: "🎵"
6
-
7
- colorFrom: blue
8
-
9
- colorTo: purple
10
-
11
  sdk: gradio
12
-
13
- sdk\_version: "4.44.0"
14
-
15
- app\_file: app.py
16
-
17
  pinned: false
18
-
19
  ---
20
 
21
 
 
1
  ---
2
+ title: Chord Bot Local
3
+ emoji: 🎸
4
+ colorFrom: indigo
5
+ colorTo: blue
 
 
 
 
 
6
  sdk: gradio
7
+ sdk_version: "4.44.0"
8
+ app_file: app.py
 
 
 
9
  pinned: false
 
10
  ---
11
 
12
 
app.py CHANGED
@@ -1,201 +1,32 @@
1
- # app.py
2
  import gradio as gr
3
- from typing import List, Tuple
4
- import re
5
-
6
- # ----- Pitch utilities -----
7
- SHARP_NAMES = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]
8
- FLAT_NAMES = ["C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B"]
9
-
10
- NAME_TO_PC = {
11
- # naturals
12
- "C":0, "D":2, "E":4, "F":5, "G":7, "A":9, "B":11,
13
- # sharps
14
- "C#":1, "D#":3, "F#":6, "G#":8, "A#":10,
15
- # flats
16
- "Db":1, "Eb":3, "Gb":6, "Ab":8, "Bb":10,
17
- # unicode ♯/♭
18
- "C♯":1, "D♯":3, "F♯":6, "G♯":8, "A♯":10,
19
- "D♭":1, "E♭":3, "G♭":6, "A♭":8, "B♭":10,
20
- }
21
-
22
- # Common chord templates: set of intervals from root (0 always present)
23
- CHORD_TEMPLATES = {
24
- (0,4,7): ("major triad", ""),
25
- (0,3,7): ("minor triad", "m"),
26
- (0,3,6): ("diminished triad", "dim"),
27
- (0,4,8): ("augmented triad", "+"),
28
- (0,2,7): ("sus2", "sus2"),
29
- (0,5,7): ("sus4", "sus4"),
30
- (0,4,7,10): ("dominant 7th", "7"),
31
- (0,4,7,11): ("major 7th", "maj7"),
32
- (0,3,7,10): ("minor 7th", "m7"),
33
- (0,3,6,10): ("half-diminished (m7♭5)", "m7b5"),
34
- (0,3,6,9): ("diminished 7th", "dim7"),
35
- (0,3,7,11): ("minor major 7th", "m(maj7)"),
36
- (0,4,7,9): ("major 6th", "6"),
37
- (0,3,7,9): ("minor 6th", "m6"),
38
- }
39
-
40
- ADD_TONES = {
41
- 2: ("add9", "add9"), # treat 2 as add9
42
- 9: ("add9", "add9"),
43
- 11: ("add11", "add11"),
44
- 6: ("add13", "add13"),
45
- }
46
-
47
- SUS_OVERLAPS = {(0,2,7), (0,5,7)}
48
-
49
- NOTE_TOKEN_RE = re.compile(r"[A-Ga-g](?:#|b|♯|♭)?")
50
-
51
-
52
- def pc_name(pc: int, prefer_flats: bool) -> str:
53
- return (FLAT_NAMES if prefer_flats else SHARP_NAMES)[pc % 12]
54
-
55
-
56
- def parse_notes(user_text: str) -> Tuple[List[int], bool, List[str]]:
57
- """Return (pitch_classes, prefer_flats, original_tokens)."""
58
- tokens = NOTE_TOKEN_RE.findall(user_text)
59
- tokens = [t.upper().replace("♯", "#").replace("♭", "b") for t in tokens]
60
- prefer_flats = any("B" in t and len(t)>1 for t in tokens) or any("b" in t for t in tokens)
61
- pcs = []
62
- for t in tokens:
63
- if t in NAME_TO_PC:
64
- pcs.append(NAME_TO_PC[t])
65
- # dedupe while preserving order
66
- seen = set()
67
- pcs_unique = []
68
- for p in pcs:
69
- if p not in seen:
70
- pcs_unique.append(p)
71
- seen.add(p)
72
- return pcs_unique, prefer_flats, tokens
73
-
74
-
75
- def intervals_from_root(pcs: List[int], root: int) -> Tuple[int,...]:
76
- ints = sorted(((p - root) % 12) for p in pcs)
77
- if 0 not in ints:
78
- ints = (0,) + tuple(i for i in ints)
79
- return tuple(sorted(set(ints)))
80
-
81
-
82
- def describe_chord(pcs: List[int], prefer_flats: bool) -> str:
83
- if len(pcs) < 3:
84
- return "Please provide at least 3 distinct note names (e.g., C E G or C, Eb, G)."
85
-
86
- matches = []
87
- for root in pcs: # try each included pitch as potential root
88
- base_ints = intervals_from_root(pcs, root)
89
- # Try exact template match first (triads/sevenths/6ths/etc.)
90
- if base_ints in CHORD_TEMPLATES:
91
- qual_name, suffix = CHORD_TEMPLATES[base_ints]
92
- matches.append((root, qual_name, suffix, []))
93
- continue
94
- # Try triad with added tones (add9/add11/add13)
95
- # Identify a triad subset and extra tones
96
- for triad in [(0,4,7), (0,3,7), (0,3,6), (0,4,8)]:
97
- triad_set = set(triad)
98
- if triad_set.issubset(set(base_ints)):
99
- extras = sorted(set(base_ints) - triad_set)
100
- add_suffixes = []
101
- for e in extras:
102
- if e in ADD_TONES:
103
- add_suffixes.append(ADD_TONES[e][1])
104
- if add_suffixes:
105
- qual_name, suffix = CHORD_TEMPLATES.get(triad, ("triad",""))
106
- matches.append((root, f"{qual_name} with {'/'.join(add_suffixes)}", suffix + ("" if not add_suffixes else ("("+" ".join(add_suffixes)+")")), extras))
107
- # sus chords (if match) possibly with added tones
108
- for sus in [(0,2,7), (0,5,7)]:
109
- if set(sus).issubset(set(base_ints)):
110
- extras = sorted(set(base_ints) - set(sus))
111
- add_suffixes = []
112
- for e in extras:
113
- if e in ADD_TONES:
114
- add_suffixes.append(ADD_TONES[e][1])
115
- qual_name, suffix = CHORD_TEMPLATES[sus]
116
- matches.append((root, qual_name + (" with "+"/".join(add_suffixes) if add_suffixes else ""), suffix + ("" if not add_suffixes else ("("+" ".join(add_suffixes)+")")), extras))
117
-
118
- if not matches:
119
- # fallback: show interval set relative to lowest note as a hint
120
- root_guess = min(pcs)
121
- ints = intervals_from_root(pcs, root_guess)
122
- return (
123
- "I couldn't confidently name that chord. Interval set from {}: {}.\n"
124
- "Try removing extensions/duplicates or check note spelling (sharps vs flats)."
125
- ).format(pc_name(root_guess, prefer_flats), ",".join(str(i) for i in ints))
126
-
127
- # Rank matches: prefer templates with no ambiguous extras, prefer 7th/6th over triad with adds, then by root being lowest provided note
128
- def rank(m):
129
- root, qual_name, suffix, extras = m
130
- score = 0
131
- if "7" in suffix or "6" in suffix:
132
- score += 2
133
- if not extras:
134
- score += 1
135
- if root == min(pcs):
136
- score += 0.5
137
- return -score
138
-
139
- matches.sort(key=rank)
140
-
141
- # Build a readable response listing top 1-3 candidates
142
- top = matches[:3]
143
- lines = []
144
- for i,(root, qual_name, suffix, extras) in enumerate(top, start=1):
145
- name = pc_name(root, prefer_flats)
146
- symbol = name + (suffix if suffix else "")
147
- spelled = ", ".join(pc_name(p, prefer_flats) for p in sorted(set(pcs)))
148
- lines.append(f"{i}. {symbol} — {qual_name} (notes: {spelled})")
149
-
150
- # Inversion hint (best-effort): if lowest note isn't the chosen root, suggest slash chord
151
- chosen_root = top[0][0]
152
- lowest = min(pcs)
153
- if lowest != chosen_root:
154
- lines[0] += f" — likely {pc_name(chosen_root, prefer_flats)}/{pc_name(lowest, prefer_flats)}"
155
-
156
- return "\n".join(lines)
157
-
158
-
159
- def answer(message: str, history: List[Tuple[str,str]]):
160
- pcs, prefer_flats, tokens = parse_notes(message)
161
- if not tokens:
162
- return (
163
- "Tell me 3+ notes (e.g., 'C E G' or 'Db, F, Ab, C'). "
164
- "I support #/b and unicode ♯/♭."
165
- )
166
- return describe_chord(pcs, prefer_flats)
167
-
168
-
169
- def example_inputs():
170
- return [
171
- "C E G",
172
- "D F# A C",
173
- "C Eb G Bb",
174
- "F A C D",
175
- "G Bb D F",
176
- "Db F Ab C",
177
- "C D G",
178
- "A C E G#",
179
- "E G# B D",
180
- "C Eb Gb A"
181
- ]
182
-
183
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
184
- gr.Markdown("""
185
- # 🎵 Note → Chord Chatbot
186
- Type 3 or more note names and I'll guess the chord (triads, 7ths, 6ths, sus, and common add tones).
187
- - Accepted formats: `C E G`, `Db, F, Ab, C`, `G-B-D-F`, etc.
188
- - Sharps/flats: `#`, `b`, or unicode `♯` `♭`.
189
- """)
190
- chat = gr.ChatInterface(
191
- fn=answer,
192
- examples=[[e] for e in example_inputs()],
193
- title="Chord Identifier",
194
- retry_btn=None,
195
- undo_btn="Delete last turn",
196
- clear_btn="Clear",
197
- textbox=gr.Textbox(placeholder="e.g., C E G or Db, F, Ab", label="Your notes"),
198
  )
 
 
 
 
 
 
 
 
 
 
199
 
200
  if __name__ == "__main__":
201
- demo.launch()
 
 
1
  import gradio as gr
2
+ from transformers import pipeline
3
+
4
+ generator = pipeline("text-generation", model="distilgpt2")
5
+
6
+ def chord_bot(prompt: str) -> str:
7
+ """
8
+ Generate a response using the local Hugging Face model.
9
+ This simulates a chord/music assistant, but could be extended with
10
+ domain-specific prompts or fine-tuned models.
11
+ """
12
+ response = generator(
13
+ prompt,
14
+ max_new_tokens=50,
15
+ do_sample=True,
16
+ temperature=0.7,
17
+ top_k=50,
18
+ top_p=0.95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  )
20
+ return response[0]["generated_text"]
21
+
22
+ # Gradio UI
23
+ iface = gr.Interface(
24
+ fn=chord_bot,
25
+ inputs=gr.Textbox(lines=2, placeholder="Type a chord progression or music-related question..."),
26
+ outputs="text",
27
+ title="🎶 Locally-Hosted Chord Bot",
28
+ description="This version of Chord Bot runs a local Hugging Face Transformers pipeline inside the Space container."
29
+ )
30
 
31
  if __name__ == "__main__":
32
+ iface.launch()
requirements.txt CHANGED
@@ -1 +1,3 @@
1
- gradio>=4.44.0
 
 
 
1
+ gradio
2
+ transformers
3
+ torch