masterjedi commited on
Commit
dbc2350
·
1 Parent(s): 497943d

Create ADI voice persona lab Space

Browse files
Files changed (4) hide show
  1. .gitattributes +2 -4
  2. README.md +4 -6
  3. app.py +162 -0
  4. requirements.txt +2 -0
.gitattributes CHANGED
@@ -3,20 +3,16 @@
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
  *.bz2 filter=lfs diff=lfs merge=lfs -text
5
  *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
  *.gz filter=lfs diff=lfs merge=lfs -text
8
  *.h5 filter=lfs diff=lfs merge=lfs -text
9
  *.joblib filter=lfs diff=lfs merge=lfs -text
10
  *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
  *.model filter=lfs diff=lfs merge=lfs -text
13
  *.msgpack filter=lfs diff=lfs merge=lfs -text
14
  *.npy filter=lfs diff=lfs merge=lfs -text
15
  *.npz filter=lfs diff=lfs merge=lfs -text
16
  *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
  *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
  *.pickle filter=lfs diff=lfs merge=lfs -text
21
  *.pkl filter=lfs diff=lfs merge=lfs -text
22
  *.pt filter=lfs diff=lfs merge=lfs -text
@@ -33,3 +29,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
  *.bz2 filter=lfs diff=lfs merge=lfs -text
5
  *.ckpt filter=lfs diff=lfs merge=lfs -text
 
6
  *.gz filter=lfs diff=lfs merge=lfs -text
7
  *.h5 filter=lfs diff=lfs merge=lfs -text
8
  *.joblib filter=lfs diff=lfs merge=lfs -text
9
  *.lfs.* filter=lfs diff=lfs merge=lfs -text
 
10
  *.model filter=lfs diff=lfs merge=lfs -text
11
  *.msgpack filter=lfs diff=lfs merge=lfs -text
12
  *.npy filter=lfs diff=lfs merge=lfs -text
13
  *.npz filter=lfs diff=lfs merge=lfs -text
14
  *.onnx filter=lfs diff=lfs merge=lfs -text
 
15
  *.parquet filter=lfs diff=lfs merge=lfs -text
 
16
  *.pickle filter=lfs diff=lfs merge=lfs -text
17
  *.pkl filter=lfs diff=lfs merge=lfs -text
18
  *.pt filter=lfs diff=lfs merge=lfs -text
 
29
  *.zip filter=lfs diff=lfs merge=lfs -text
30
  *.zst filter=lfs diff=lfs merge=lfs -text
31
  *tfevents* filter=lfs diff=lfs merge=lfs -text
32
+ *.mp3 filter=lfs diff=lfs merge=lfs -text
33
+ *.wav filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,13 +1,11 @@
1
  ---
2
- title: Adi Voice Persona Lab
3
- emoji: 🐢
4
- colorFrom: yellow
5
  colorTo: green
6
  sdk: gradio
7
  sdk_version: 6.19.0
8
- python_version: '3.13'
9
  app_file: app.py
10
  pinned: false
11
  ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: ADI Voice Persona Lab
3
+ emoji: 🎛️
4
+ colorFrom: gray
5
  colorTo: green
6
  sdk: gradio
7
  sdk_version: 6.19.0
8
+ python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
11
  ---
 
 
app.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import re
3
+ import tempfile
4
+ import zipfile
5
+ from pathlib import Path
6
+
7
+ import edge_tts
8
+ import gradio as gr
9
+
10
+
11
+ PERSONAS = {
12
+ "ADI calm": {
13
+ "prefix": "Here is the calm version.",
14
+ "style": "steady, concise, and reassuring",
15
+ },
16
+ "Technical mentor": {
17
+ "prefix": "Here is the technical mentor version.",
18
+ "style": "precise, capable, and lightly explanatory",
19
+ },
20
+ "Operator mode": {
21
+ "prefix": "Here is the operator mode version.",
22
+ "style": "brief, action-oriented, and status-aware",
23
+ },
24
+ "Warm companion": {
25
+ "prefix": "Here is the warm companion version.",
26
+ "style": "friendly, grounded, and conversational",
27
+ },
28
+ "Launch demo": {
29
+ "prefix": "Here is the launch demo version.",
30
+ "style": "polished, confident, and presentation-ready",
31
+ },
32
+ }
33
+
34
+ VOICE_CHOICES = [
35
+ "en-US-AriaNeural",
36
+ "en-US-JennyNeural",
37
+ "en-US-GuyNeural",
38
+ "en-US-DavisNeural",
39
+ "en-US-AvaNeural",
40
+ "en-GB-SoniaNeural",
41
+ "en-GB-RyanNeural",
42
+ ]
43
+
44
+
45
+ def clean(text):
46
+ return re.sub(r"\s+", " ", (text or "").strip())
47
+
48
+
49
+ def rewrite_for_persona(text, persona, brevity):
50
+ base = clean(text)
51
+ if not base:
52
+ raise gr.Error("Add text for ADI to speak first.")
53
+
54
+ style = PERSONAS[persona]["style"]
55
+ prefix = PERSONAS[persona]["prefix"]
56
+ sentences = re.split(r"(?<=[.!?])\s+", base)
57
+ sentences = [sentence for sentence in sentences if sentence]
58
+
59
+ if brevity == "short":
60
+ body = " ".join(sentences[:2])
61
+ elif brevity == "expanded":
62
+ body = base
63
+ body += f" The intended delivery is {style}, with enough detail to feel useful."
64
+ else:
65
+ body = base
66
+
67
+ if persona == "Operator mode":
68
+ body = f"Status: ready. {body} Next step: tell me what you want to run."
69
+ elif persona == "Technical mentor":
70
+ body = f"{body} The key idea is to make the next action obvious."
71
+ elif persona == "Warm companion":
72
+ body = f"{body} I can stay with you while we tune it."
73
+ elif persona == "Launch demo":
74
+ body = f"{body} This is ready to show as a live ADI capability."
75
+
76
+ return f"{prefix} {body}"
77
+
78
+
79
+ async def synthesize_one(text, voice, rate, pitch):
80
+ output = Path(tempfile.NamedTemporaryFile(suffix=".mp3", delete=False).name)
81
+ communicate = edge_tts.Communicate(text, voice, rate=rate, pitch=pitch)
82
+ await communicate.save(str(output))
83
+ return str(output)
84
+
85
+
86
+ def synthesize(text, persona, voice, rate, pitch, brevity):
87
+ script = rewrite_for_persona(text, persona, brevity)
88
+ audio_path = asyncio.run(synthesize_one(script, voice, rate, pitch))
89
+ return script, audio_path
90
+
91
+
92
+ def compare(text, voice_a, persona_a, voice_b, persona_b, voice_c, persona_c, rate, pitch, brevity):
93
+ script_a, audio_a = synthesize(text, persona_a, voice_a, rate, pitch, brevity)
94
+ script_b, audio_b = synthesize(text, persona_b, voice_b, rate, pitch, brevity)
95
+ script_c, audio_c = synthesize(text, persona_c, voice_c, rate, pitch, brevity)
96
+
97
+ zip_path = Path(tempfile.NamedTemporaryFile(suffix=".zip", delete=False).name)
98
+ with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as bundle:
99
+ for idx, (script, audio) in enumerate(((script_a, audio_a), (script_b, audio_b), (script_c, audio_c)), 1):
100
+ bundle.write(audio, f"adi_voice_take_{idx}.mp3")
101
+ bundle.writestr(f"adi_voice_take_{idx}.txt", script)
102
+
103
+ return script_a, audio_a, script_b, audio_b, script_c, audio_c, str(zip_path)
104
+
105
+
106
+ with gr.Blocks(title="ADI Voice Persona Lab", fill_width=True) as demo:
107
+ gr.Markdown("# ADI Voice Persona Lab")
108
+ source = gr.Textbox(
109
+ label="Base ADI response",
110
+ lines=6,
111
+ value=(
112
+ "Hello, I am ADI. I can help inspect models, compare prompts, generate training data, "
113
+ "and turn your ideas into working demos on Hugging Face Spaces."
114
+ ),
115
+ )
116
+
117
+ with gr.Row():
118
+ rate = gr.Dropdown(
119
+ choices=["-20%", "-10%", "+0%", "+10%", "+20%"],
120
+ value="+0%",
121
+ label="Rate",
122
+ )
123
+ pitch = gr.Dropdown(
124
+ choices=["-10Hz", "+0Hz", "+10Hz", "+20Hz"],
125
+ value="+0Hz",
126
+ label="Pitch",
127
+ )
128
+ brevity = gr.Radio(
129
+ choices=["short", "normal", "expanded"],
130
+ value="normal",
131
+ label="Script length",
132
+ )
133
+
134
+ with gr.Row():
135
+ with gr.Column():
136
+ persona_a = gr.Dropdown(list(PERSONAS), value="ADI calm", label="Persona A")
137
+ voice_a = gr.Dropdown(VOICE_CHOICES, value="en-US-AriaNeural", label="Voice A")
138
+ script_a = gr.Textbox(label="Script A", lines=7)
139
+ audio_a = gr.Audio(label="Audio A", type="filepath")
140
+ with gr.Column():
141
+ persona_b = gr.Dropdown(list(PERSONAS), value="Technical mentor", label="Persona B")
142
+ voice_b = gr.Dropdown(VOICE_CHOICES, value="en-US-GuyNeural", label="Voice B")
143
+ script_b = gr.Textbox(label="Script B", lines=7)
144
+ audio_b = gr.Audio(label="Audio B", type="filepath")
145
+ with gr.Column():
146
+ persona_c = gr.Dropdown(list(PERSONAS), value="Launch demo", label="Persona C")
147
+ voice_c = gr.Dropdown(VOICE_CHOICES, value="en-US-AvaNeural", label="Voice C")
148
+ script_c = gr.Textbox(label="Script C", lines=7)
149
+ audio_c = gr.Audio(label="Audio C", type="filepath")
150
+
151
+ run = gr.Button("Generate Takes", variant="primary")
152
+ bundle = gr.File(label="Download all takes")
153
+
154
+ run.click(
155
+ compare,
156
+ inputs=[source, voice_a, persona_a, voice_b, persona_b, voice_c, persona_c, rate, pitch, brevity],
157
+ outputs=[script_a, audio_a, script_b, audio_b, script_c, audio_c, bundle],
158
+ )
159
+
160
+
161
+ if __name__ == "__main__":
162
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio==6.19.0
2
+ edge-tts==7.2.8