ysharma HF Staff commited on
Commit
9013d8b
Β·
verified Β·
1 Parent(s): 2360382

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -75
app.py CHANGED
@@ -354,12 +354,39 @@ class FontMoodGenerator:
354
 
355
  return css
356
 
357
- def generate_palette_and_theme(self, mood_text: str) -> tuple[str, str]:
358
- """
359
- Generates a font palette HTML and a dynamic theme CSS string.
360
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  if not mood_text or not mood_text.strip():
362
- return "<p>Please enter a mood or a description.</p>", ""
363
 
364
  mood_embedding = self.embedding_model.encode(
365
  mood_text,
@@ -370,43 +397,194 @@ class FontMoodGenerator:
370
  )[0]
371
 
372
  palette_html = self._format_palette_as_html(top_hits)
373
- theme_css = self._create_dynamic_theme_css(top_hits)
374
 
375
- return palette_html, theme_css
 
 
376
 
377
- def clear_theme(self) -> tuple[str, str]:
378
- return "", ""
 
379
 
380
 
381
- # --- GRADIO UI ---
382
- # Defines and launches the web interface.
383
 
384
  def create_ui(generator: FontMoodGenerator):
385
- """Creates the Gradio web interface."""
 
 
 
 
386
  with gr.Blocks(theme="ocean") as demo:
387
- # This invisible component will hold our dynamic CSS
388
  dynamic_css_output = gr.HTML()
389
-
390
  gr.Markdown("""
391
  # πŸ“ Font Mood Generator
392
- Describe a mood, a scene, or a feeling, and get a matching font palette.<br>
393
- **The UI fonts will update to match your mood!**
394
  """)
395
 
396
- with gr.Row():
397
- with gr.Column(scale=4):
 
 
 
 
 
 
 
 
398
  mood_input = gr.Textbox(
399
- value="Elegant wedding invitation",
400
  label="Enter Your Mood or Scene",
401
- info="Be as descriptive as you like!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  )
403
- with gr.Column(scale=1, min_width=150):
404
- submit_button = gr.Button("Generate Fonts", variant="primary")
405
- clear_button = gr.Button("Clear", variant="secondary")
406
-
407
- palette_output = gr.HTML(label="Your Generated Font Palette")
408
 
409
- # Define CSS for font cards here once
410
  gr.HTML("""
411
  <style>
412
  .font-palette-container {
@@ -451,66 +629,33 @@ def create_ui(generator: FontMoodGenerator):
451
  .font-description {
452
  color: #5d6d7e; font-size: 0.9em; line-height: 1.4;
453
  }
 
 
 
 
 
 
454
  </style>
455
  """)
456
 
457
- # Define the function to be called by events
458
- event_handler = generator.generate_palette_and_theme
459
- outputs_list = [palette_output, dynamic_css_output]
460
-
461
- gr.Examples(
462
- [
463
- "Elegant wedding invitation with vintage charm",
464
- "Modern tech startup with clean aesthetics",
465
- "Playful children's book with whimsical characters",
466
- "Horror movie poster with scary atmosphere",
467
- "Luxury fashion brand with sophisticated appeal",
468
- "Retro 1950s diner with nostalgic vibes",
469
- "Academic research paper with scholarly tone",
470
- "Surf shop with California beach culture",
471
- "Gothic medieval manuscript with ancient feel",
472
- "Futuristic sci-fi interface with cyber aesthetics"
473
- ],
474
- inputs=mood_input,
475
- outputs=outputs_list,
476
- fn=event_handler,
477
- run_on_click=True,
478
- )
479
-
480
- submit_button.click(
481
- fn=event_handler,
482
- inputs=mood_input,
483
- outputs=outputs_list,
484
- )
485
- clear_button.click(
486
- fn=generator.clear_theme,
487
- outputs=outputs_list,
488
- )
489
- # Also allow submitting by pressing Enter in the textbox
490
- mood_input.submit(
491
- fn=event_handler,
492
- inputs=mood_input,
493
- outputs=outputs_list,
494
- )
495
-
496
  gr.Markdown("""
497
  ----
498
- ## What is this?
499
- This interactive application, the **Font Mood Generator**, transforms your words into a curated typography palette. Simply describe a mood, a scene, or a feeling and the app will generate a set of matching fonts. As a unique touch, the entire user interface dynamically updates its typography to reflect the generated palette, immersing you in your chosen aesthetic.
500
-
501
- ## How It Works?
502
- At its core, this tool is powered by [**EmbeddingGemma**](http://huggingface.co/google/embeddinggemma-300M), a state-of-the-art text embedding model. The process works in a few simple steps:
503
 
504
- 1. **Text to Vector**: When you enter a description, EmbeddingGemma converts your text into a numerical representation called an **embedding**. This embedding captures the semantic essence, or the "vibe" of your words.
505
- 2. **Semantic Font Search**: The application has a pre-defined library of fonts, where each font is associated with its own descriptive text and a pre-computed embedding.
506
- 3. **Finding the Match**: Your input embedding is compared against the entire library of font embeddings to find the closest matches based on a similarity score.
507
- 4. **Palette Creation**: The fonts with the highest similarity scores are selected and presented to you as a complete typography palette.
508
 
509
- The Font Mood Generator demonstrates how embeddings can be used for creative applications in typography and design, going beyond simple text search to understand the emotional and aesthetic qualities of typefaces.
 
 
 
 
 
 
510
  """)
511
 
512
  return demo
513
 
 
514
  if __name__ == "__main__":
515
  # Initialize application components
516
  generator = FontMoodGenerator(config=Config(), font_data=FONT_DATA)
 
354
 
355
  return css
356
 
357
+ def _create_css_code_output(self, top_hits: list[dict[str, any]]) -> str:
358
+ """Creates exportable CSS code for users."""
359
+ if not top_hits:
360
+ return ""
361
+
362
+ font_imports = self._create_font_imports_css(top_hits)
363
+
364
+ css_code = f"""/* Generated Font Palette CSS */
365
+ {font_imports}
366
+
367
+ /* Font Variables */
368
+ :root {{"""
369
+
370
+ for i, hit in enumerate(top_hits):
371
+ font_info = self.font_data[hit['corpus_id']]
372
+ font_name = font_info['name']
373
+ css_code += f"""
374
+ --font-{i+1}: '{font_name}', {font_info['family']};"""
375
+
376
+ css_code += """
377
+ }
378
+
379
+ /* Usage Examples */
380
+ .heading { font-family: var(--font-1); }
381
+ .body-text { font-family: var(--font-2); }
382
+ .accent { font-family: var(--font-3); }"""
383
+
384
+ return css_code
385
+
386
+ def generate_palette(self, mood_text: str) -> tuple[str, list[dict[str, any]]]:
387
+ """Generates font palette and returns both HTML and raw data."""
388
  if not mood_text or not mood_text.strip():
389
+ return "<p>Please enter a mood or a description.</p>", []
390
 
391
  mood_embedding = self.embedding_model.encode(
392
  mood_text,
 
397
  )[0]
398
 
399
  palette_html = self._format_palette_as_html(top_hits)
400
+ return palette_html, top_hits
401
 
402
+ def apply_theme(self, top_hits: list[dict[str, any]]) -> str:
403
+ """Applies the theme CSS."""
404
+ return self._create_dynamic_theme_css(top_hits)
405
 
406
+ def generate_css_code(self, top_hits: list[dict[str, any]]) -> str:
407
+ """Generates exportable CSS code."""
408
+ return self._create_css_code_output(top_hits)
409
 
410
 
411
+ # --- GRADIO UI WITH WALKTHROUGH ---
 
412
 
413
  def create_ui(generator: FontMoodGenerator):
414
+ """Creates the Gradio web interface with Walkthrough."""
415
+
416
+ # Shared state to store generated fonts across steps
417
+ font_state = gr.State([])
418
+
419
  with gr.Blocks(theme="ocean") as demo:
420
+ # Dynamic CSS output
421
  dynamic_css_output = gr.HTML()
422
+
423
  gr.Markdown("""
424
  # πŸ“ Font Mood Generator
425
+ Follow the steps below to generate and apply a personalized font palette based on your mood or description.
 
426
  """)
427
 
428
+ with gr.Walkthrough(selected=0) as walkthrough:
429
+
430
+ # STEP 1: Input Mood
431
+ with gr.Step("🎯 Describe Your Mood", id=0):
432
+ gr.Markdown("""
433
+ ### Step 1: Tell us about your mood or vision
434
+ Describe the feeling, atmosphere, or aesthetic you're aiming for.
435
+ Be as detailed as you like - the more descriptive, the better the results!
436
+ """)
437
+
438
  mood_input = gr.Textbox(
439
+ value="Elegant wedding invitation with vintage charm",
440
  label="Enter Your Mood or Scene",
441
+ info="Examples: 'Modern tech startup', 'Playful children's book', 'Gothic horror movie'",
442
+ lines=3
443
+ )
444
+
445
+ gr.Examples(
446
+ [
447
+ "Elegant wedding invitation with vintage charm",
448
+ "Modern tech startup with clean aesthetics",
449
+ "Playful children's book with whimsical characters",
450
+ "Horror movie poster with scary atmosphere",
451
+ "Luxury fashion brand with sophisticated appeal",
452
+ "Retro 1950s diner with nostalgic vibes",
453
+ ],
454
+ inputs=mood_input,
455
+ )
456
+
457
+ generate_btn = gr.Button("Generate Font Palette β†’", variant="primary", size="lg")
458
+
459
+ def generate_and_move(mood_text):
460
+ palette_html, top_hits = generator.generate_palette(mood_text)
461
+ return palette_html, top_hits, gr.Walkthrough(selected=1)
462
+
463
+ generate_btn.click(
464
+ fn=generate_and_move,
465
+ inputs=mood_input,
466
+ outputs=[gr.State(), font_state, walkthrough]
467
+ )
468
+
469
+ # STEP 2: Review Generated Fonts
470
+ with gr.Step("🎨 Review Your Font Palette", id=1):
471
+ gr.Markdown("""
472
+ ### Step 2: Review your generated fonts
473
+ Here are the fonts that best match your mood, ranked by similarity score.
474
+ Each font is scored based on how well it captures your described aesthetic.
475
+ """)
476
+
477
+ palette_display = gr.HTML()
478
+
479
+ def show_palette(palette_html):
480
+ return palette_html
481
+
482
+ # Update palette when entering this step
483
+ demo.load(
484
+ fn=show_palette,
485
+ inputs=gr.State(),
486
+ outputs=palette_display
487
+ )
488
+
489
+ with gr.Row():
490
+ back_to_input_btn = gr.Button("← Back to Input", variant="secondary")
491
+ apply_theme_btn = gr.Button("Apply Typography Theme β†’", variant="primary", size="lg")
492
+
493
+ back_to_input_btn.click(
494
+ fn=lambda: gr.Walkthrough(selected=0),
495
+ outputs=walkthrough
496
+ )
497
+
498
+ def apply_and_move(top_hits):
499
+ theme_css = generator.apply_theme(top_hits)
500
+ return theme_css, gr.Walkthrough(selected=2)
501
+
502
+ apply_theme_btn.click(
503
+ fn=apply_and_move,
504
+ inputs=font_state,
505
+ outputs=[dynamic_css_output, walkthrough]
506
+ )
507
+
508
+ # STEP 3: Experience the Typography
509
+ with gr.Step("✨ Experience Your Typography", id=2):
510
+ gr.Markdown("""
511
+ ### Step 3: See your fonts in action!
512
+ Notice how the entire interface has transformed to reflect your chosen aesthetic.
513
+ The fonts from your palette are now applied throughout the UI.
514
+ """)
515
+
516
+ gr.Markdown("""
517
+ **πŸŽ‰ Your typography theme is now active!**
518
+
519
+ Look around the interface - the headings, buttons, and text inputs now use fonts from your generated palette.
520
+ This gives you a real preview of how these fonts work together in a design context.
521
+
522
+ **Font Roles:**
523
+ - **Primary Font**: Used for headings and primary buttons
524
+ - **Secondary Font**: Used for input fields and body text
525
+ - **Accent Font**: Used for secondary buttons and highlights
526
+ """)
527
+
528
+ with gr.Row():
529
+ back_to_palette_btn = gr.Button("← Back to Palette", variant="secondary")
530
+ get_code_btn = gr.Button("Get CSS Code β†’", variant="primary", size="lg")
531
+
532
+ back_to_palette_btn.click(
533
+ fn=lambda: gr.Walkthrough(selected=1),
534
+ outputs=walkthrough
535
+ )
536
+
537
+ get_code_btn.click(
538
+ fn=lambda: gr.Walkthrough(selected=3),
539
+ outputs=walkthrough
540
+ )
541
+
542
+ # STEP 4: Export and Use
543
+ with gr.Step("πŸ’Ύ Export & Use Your Fonts", id=3):
544
+ gr.Markdown("""
545
+ ### Step 4: Get the code and use your fonts
546
+ Copy the CSS code below to use your font palette in your own projects.
547
+ """)
548
+
549
+ css_code_output = gr.Code(
550
+ language="css",
551
+ label="Your Font Palette CSS",
552
+ value="",
553
+ lines=15
554
+ )
555
+
556
+ def generate_css_code(top_hits):
557
+ return generator.generate_css_code(top_hits)
558
+
559
+ # Generate CSS when entering this step
560
+ demo.load(
561
+ fn=generate_css_code,
562
+ inputs=font_state,
563
+ outputs=css_code_output
564
+ )
565
+
566
+ gr.Markdown("""
567
+ **πŸš€ Next Steps:**
568
+ 1. Copy the CSS code above
569
+ 2. Include it in your website's stylesheet
570
+ 3. Apply the font variables to your HTML elements
571
+ 4. Enjoy your new typography!
572
+
573
+ **πŸ’‘ Pro Tip:** You can also use individual Google Fonts links if you prefer to load fonts separately.
574
+ """)
575
+
576
+ with gr.Row():
577
+ start_over_btn = gr.Button("πŸ”„ Start Over", variant="secondary", size="lg")
578
+
579
+ def restart():
580
+ return "", [], gr.Walkthrough(selected=0)
581
+
582
+ start_over_btn.click(
583
+ fn=restart,
584
+ outputs=[dynamic_css_output, font_state, walkthrough]
585
  )
 
 
 
 
 
586
 
587
+ # Static CSS for font cards
588
  gr.HTML("""
589
  <style>
590
  .font-palette-container {
 
629
  .font-description {
630
  color: #5d6d7e; font-size: 0.9em; line-height: 1.4;
631
  }
632
+
633
+ /* Walkthrough styling enhancements */
634
+ .gr-walkthrough {
635
+ border-radius: 12px;
636
+ overflow: hidden;
637
+ }
638
  </style>
639
  """)
640
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
641
  gr.Markdown("""
642
  ----
643
+ ## About This App
 
 
 
 
644
 
645
+ This **Font Mood Generator** uses the new `gr.Walkthrough` component to create a guided, step-by-step experience for generating typography palettes.
 
 
 
646
 
647
+ The app is powered by [**EmbeddingGemma**](http://huggingface.co/google/embeddinggemma-300M), Google's text embedding model that understands the semantic meaning and emotional qualities of your descriptions to find matching fonts.
648
+
649
+ **πŸ†• Walkthrough Features:**
650
+ - **Guided Experience**: Step-by-step workflow for better user experience
651
+ - **Progressive Disclosure**: Information and controls revealed when needed
652
+ - **Visual Progress**: Clear indication of current step and progress
653
+ - **Interactive Navigation**: Ability to go back and forth between steps
654
  """)
655
 
656
  return demo
657
 
658
+
659
  if __name__ == "__main__":
660
  # Initialize application components
661
  generator = FontMoodGenerator(config=Config(), font_data=FONT_DATA)