pradachan commited on
Commit
bcfdaf8
·
verified ·
1 Parent(s): c0524ef

Dark violet theme matching the cover art

Browse files
Files changed (2) hide show
  1. README.md +2 -1
  2. tonesearch.py +50 -2
README.md CHANGED
@@ -1,7 +1,8 @@
1
  ---
2
  title: tonesearch
3
  colorFrom: indigo
4
- colorTo: red
 
5
  sdk: gradio
6
  sdk_version: 6.30.0
7
  python_version: "3.12"
 
1
  ---
2
  title: tonesearch
3
  colorFrom: indigo
4
+ colorTo: purple
5
+ thumbnail: https://raw.githubusercontent.com/aipdv/tonesearch/main/assets/banner.jpg
6
  sdk: gradio
7
  sdk_version: 6.30.0
8
  python_version: "3.12"
tonesearch.py CHANGED
@@ -101,6 +101,49 @@ def search(index_dir, query="", tone="angry", w=1.0, k=10):
101
  return top, score[top]
102
 
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  MAX_UPLOAD_S = 300 # ponytail: 5 min keeps one upload inside a free visitor's daily ZeroGPU quota
105
 
106
 
@@ -149,7 +192,7 @@ def ui(index_dir):
149
  return plot, pd.DataFrame({"start": ux["start"][top].round(1), "end": ux["end"][top].round(1), "score": score.round(2)})
150
 
151
  with gr.Blocks(title="tonesearch") as app:
152
- gr.Markdown("# tonesearch\nSearch calls by **what** was said and **how** it was said.")
153
  with gr.Tab("Search"):
154
  with gr.Row():
155
  q = gr.Textbox(label="What was said (optional)", placeholder="customer wants a refund")
@@ -161,6 +204,7 @@ def ui(index_dir):
161
  go.click(run_search, [q, tone, w], [hits, seg])
162
  q.submit(run_search, [q, tone, w], [hits, seg])
163
  hits.select(on_select, hits, seg)
 
164
  with gr.Tab("Timeline"):
165
  with gr.Row():
166
  call = gr.Dropdown([(os.path.basename(c), c) for c in calls], value=calls[0], label="Call")
@@ -179,7 +223,11 @@ def ui(index_dir):
179
  up_plot = gr.LinePlot()
180
  up_hits = gr.Dataframe(label="Top segments (seconds)", interactive=False)
181
  up_go.click(run_upload, [up, up_q, up_tone], [up_plot, up_hits])
182
- app.launch(allowed_paths=sorted({os.path.dirname(c) for c in calls}))
 
 
 
 
183
 
184
 
185
  def main():
 
101
  return top, score[top]
102
 
103
 
104
+ # Look: dark violet, faint grid, film grain, one glowing lens. Matches assets/banner.svg.
105
+ HERO = """<div id="hero">
106
+ <div class="mark"><svg width="34" height="34" viewBox="0 0 38 38" fill="none" stroke="#fff" stroke-linecap="round">
107
+ <circle cx="17" cy="17" r="14" stroke-width="2.6"/><line x1="27.5" y1="27.5" x2="36" y2="36" stroke-width="3.6"/>
108
+ <line x1="11" y1="14" x2="11" y2="20" stroke-width="2.6"/><line x1="17" y1="9.5" x2="17" y2="24.5" stroke="#fb7185" stroke-width="2.6"/>
109
+ <line x1="23" y1="13" x2="23" y2="21" stroke-width="2.6"/></svg><span>tonesearch</span></div>
110
+ <p class="tag">Find the angry minute in your call recordings.</p>
111
+ <p class="sub">Search calls by <b>what</b> was said and <b>how</b> it was said. Or upload your own call.</p>
112
+ <div class="lens"><svg viewBox="0 0 200 100" preserveAspectRatio="none"><polyline points="0,78 20,74 35,80 50,72 62,76 75,70 85,62 92,30 100,14 108,30 115,62 125,70 140,74 155,68 170,75 185,70 200,74"/></svg></div>
113
+ </div>"""
114
+ CSS = """
115
+ html { background: #110e22 !important; }
116
+ body { background: radial-gradient(900px 520px at 88% -8%, rgba(99,102,241,.38), transparent 60%),
117
+ radial-gradient(700px 420px at 105% 45%, rgba(124,58,237,.18), transparent 60%),
118
+ linear-gradient(135deg, #2b1f57 0%, #1b1638 55%, #110e22 100%) fixed !important; }
119
+ body::before { content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
120
+ background-image: linear-gradient(rgba(255,255,255,.035) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.035) 1px, transparent 1px);
121
+ background-size: 40px 40px; }
122
+ body::after { content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 1000; opacity: .09;
123
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
124
+ .gradio-container { background: transparent !important; max-width: 1080px !important; position: relative; z-index: 1; }
125
+ #hero { position: relative; padding: 36px 8px 28px; overflow: visible; }
126
+ #hero .mark { display: flex; align-items: center; gap: 14px; }
127
+ #hero .mark span { font-size: 46px; font-weight: 300; letter-spacing: -1.2px; color: #fff; }
128
+ #hero .tag { margin: 44px 0 4px; font-size: 20px; color: #eef2ff; }
129
+ #hero .sub { margin: 0; font-size: 15px; font-weight: 300; color: #a5a3c8; }
130
+ #hero .lens { position: absolute; right: 40px; top: 22px; width: 170px; height: 170px; border-radius: 50%;
131
+ border: 2px solid #e0e7ff; background: rgba(15,12,36,.55); overflow: hidden;
132
+ box-shadow: 0 0 36px rgba(129,140,248,.55), inset 0 0 28px rgba(99,102,241,.35); }
133
+ #hero .lens svg { position: absolute; left: 0; top: 30px; width: 100%; height: 100px; }
134
+ #hero .lens polyline { fill: none; stroke: #fb7185; stroke-width: 2.2; vector-effect: non-scaling-stroke;
135
+ filter: drop-shadow(0 0 6px rgba(244,63,94,.8)); }
136
+ @media (max-width: 720px) { #hero .lens { display: none; } }
137
+ """
138
+ DARK = dict(body_background_fill="transparent", body_text_color="#e0e7ff", body_text_color_subdued="#a5a3c8",
139
+ background_fill_primary="#15122e", background_fill_secondary="#1b1638",
140
+ block_background_fill="rgba(21,18,46,.72)", block_border_color="rgba(165,180,252,.14)",
141
+ block_label_text_color="#a5a3c8", block_title_text_color="#c7d2fe", border_color_primary="rgba(165,180,252,.14)",
142
+ input_background_fill="rgba(15,12,36,.8)", input_border_color="rgba(165,180,252,.22)",
143
+ button_primary_background_fill="linear-gradient(90deg, #6366f1, #8b5cf6)", button_primary_text_color="#ffffff",
144
+ button_secondary_background_fill="rgba(99,102,241,.14)", button_secondary_text_color="#e0e7ff",
145
+ table_even_background_fill="#17142f", table_odd_background_fill="#1b1638", color_accent_soft="rgba(99,102,241,.25)")
146
+
147
  MAX_UPLOAD_S = 300 # ponytail: 5 min keeps one upload inside a free visitor's daily ZeroGPU quota
148
 
149
 
 
192
  return plot, pd.DataFrame({"start": ux["start"][top].round(1), "end": ux["end"][top].round(1), "score": score.round(2)})
193
 
194
  with gr.Blocks(title="tonesearch") as app:
195
+ gr.HTML(HERO)
196
  with gr.Tab("Search"):
197
  with gr.Row():
198
  q = gr.Textbox(label="What was said (optional)", placeholder="customer wants a refund")
 
204
  go.click(run_search, [q, tone, w], [hits, seg])
205
  q.submit(run_search, [q, tone, w], [hits, seg])
206
  hits.select(on_select, hits, seg)
207
+ app.load(run_search, [q, tone, w], [hits, seg]) # empty query = tone only, no GPU call
208
  with gr.Tab("Timeline"):
209
  with gr.Row():
210
  call = gr.Dropdown([(os.path.basename(c), c) for c in calls], value=calls[0], label="Call")
 
223
  up_plot = gr.LinePlot()
224
  up_hits = gr.Dataframe(label="Top segments (seconds)", interactive=False)
225
  up_go.click(run_upload, [up, up_q, up_tone], [up_plot, up_hits])
226
+ theme = gr.themes.Base(primary_hue="indigo", secondary_hue="rose", neutral_hue="slate",
227
+ font=[gr.themes.GoogleFont("Inter", weights=(300, 400, 600)), "Helvetica Neue", "sans-serif"])
228
+ theme.set(**DARK, **{k + "_dark": v for k, v in DARK.items()}) # same values both modes: always dark
229
+ app.launch(allowed_paths=sorted({os.path.dirname(c) for c in calls}), theme=theme, css=CSS,
230
+ js="() => document.body.classList.add('dark')")
231
 
232
 
233
  def main():