Dan Mo commited on
Commit
cf957e4
·
1 Parent(s): 0c2508d

Refactor application structure: implement EmojiProcessor, enhance Gradio interface, and add configuration management

Browse files
Files changed (4) hide show
  1. app.py +53 -79
  2. config.py +12 -0
  3. emoji_processor.py +119 -0
  4. utils.py +39 -0
app.py CHANGED
@@ -1,80 +1,54 @@
1
- import gradio as gr
2
- from sentence_transformers import SentenceTransformer
3
- from sklearn.metrics.pairwise import cosine_similarity
4
- import numpy as np
5
- import requests
6
- from PIL import Image
7
- from io import BytesIO
8
-
9
- # Load model
10
- model = SentenceTransformer('all-mpnet-base-v2')
11
-
12
- # Load emoji dictionaries
13
- def kitchen_txt_to_dict(filepath):
14
- emoji_dict = {}
15
- with open(filepath, 'r', encoding='utf-8') as f:
16
- for line in f:
17
- parts = line.strip().split(' ', 1)
18
- if len(parts) == 2:
19
- emoji, desc = parts
20
- emoji_dict[emoji] = desc
21
- return emoji_dict
22
-
23
- file_path_emotion = 'google-emoji-kitchen-emotion.txt'
24
- file_path_item = 'google-emoji-kitchen-item.txt'
25
-
26
- emotion_dict = kitchen_txt_to_dict(file_path_emotion)
27
- event_dict = kitchen_txt_to_dict('google-emoji-kitchen-item.txt')
28
-
29
- # Precompute embeddings
30
- emotion_embeddings = {emoji: model.encode(desc) for emoji, desc in emotion_dict.items()}
31
- event_embeddings = {emoji: model.encode(desc) for emoji, desc in event_dict.items()}
32
 
33
- # Helper functions
34
- def find_top_emojis(embedding, emoji_embeddings, top_n=1):
35
- similarities = [
36
- (emoji, cosine_similarity([embedding], [e_embed])[0][0])
37
- for emoji, e_embed in emoji_embeddings.items()
38
- ]
39
- similarities.sort(key=lambda x: x[1], reverse=True)
40
- return [emoji for emoji, _ in similarities[:top_n]]
41
-
42
- def get_emoji_kitchen_url(emoji1, emoji2, size=256):
43
- return f"https://emojik.vercel.app/s/{emoji1}_{emoji2}?size={size}"
44
-
45
- def fetch_image(url):
46
- try:
47
- response = requests.get(url)
48
- if response.status_code == 200 and "image" in response.headers.get("Content-Type", ""):
49
- return Image.open(BytesIO(response.content))
50
- else:
51
- return None
52
- except:
53
- return None
54
-
55
- # Main function for Gradio
56
- def sentence_to_emojis(sentence):
57
- embedding = model.encode(sentence)
58
-
59
- top_emotion = find_top_emojis(embedding, emotion_embeddings, top_n=1)[0]
60
- top_event = find_top_emojis(embedding, event_embeddings, top_n=1)[0]
61
-
62
- mashup_url = get_emoji_kitchen_url(top_emotion, top_event)
63
- mashup_image = fetch_image(mashup_url)
64
-
65
- return top_emotion, top_event, mashup_image
66
-
67
- # Gradio interface
68
- demo = gr.Interface(
69
- fn=sentence_to_emojis,
70
- inputs=gr.Textbox(lines=2, placeholder="Type a sentence..."),
71
- outputs=[
72
- gr.Text(label="Top Emotion Emoji"),
73
- gr.Text(label="Top Event Emoji"),
74
- gr.Image(label=" Kitchen Emoji")
75
- ],
76
- title="Sentence → Emoji Mashup",
77
- description="Get the top emotion and event emoji from your sentence, and view the mashup!"
78
- )
79
-
80
- demo.launch(share=True)
 
 
1
+ """
2
+ Main application file for the Emoji Mashup app.
3
+ This module handles the Gradio interface and application setup.
4
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
+ import gradio as gr
7
+ from utils import logger
8
+ from emoji_processor import EmojiProcessor
9
+
10
+ class EmojiMashupApp:
11
+ def __init__(self):
12
+ """Initialize the Gradio application."""
13
+ logger.info("Initializing Emoji Mashup App")
14
+ self.processor = EmojiProcessor()
15
+ self.processor.load_emoji_dictionaries()
16
+
17
+ def create_interface(self):
18
+ """Create and configure the Gradio interface.
19
+
20
+ Returns:
21
+ Gradio Interface object
22
+ """
23
+ return gr.Interface(
24
+ fn=self.processor.sentence_to_emojis,
25
+ inputs=gr.Textbox(lines=2, placeholder="Type a sentence..."),
26
+ outputs=[
27
+ gr.Text(label="Top Emotion Emoji"),
28
+ gr.Text(label="Top Event Emoji"),
29
+ gr.Image(label="Mashup Emoji")
30
+ ],
31
+ title="Sentence → Emoji Mashup",
32
+ description="Get the top emotion and event emoji from your sentence, and view the mashup!",
33
+ examples=[
34
+ ["I feel so happy today!"],
35
+ ["I'm really angry right now"],
36
+ ["Feeling tired after a long day"]
37
+ ]
38
+ )
39
+
40
+ def run(self, share=True):
41
+ """Launch the Gradio application.
42
+
43
+ Args:
44
+ share: Whether to create a public sharing link
45
+ """
46
+ logger.info("Starting Emoji Mashup App")
47
+ interface = self.create_interface()
48
+ interface.launch(share=share)
49
+
50
+
51
+ # Main entry point
52
+ if __name__ == "__main__":
53
+ app = EmojiMashupApp()
54
+ app.run(share=True)
config.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration settings for the Emoji Mashup application.
3
+ """
4
+
5
+ # Application configuration
6
+ CONFIG = {
7
+ "model_name": "all-mpnet-base-v2",
8
+ "emotion_file": "google-emoji-kitchen-emotion.txt",
9
+ "item_file": "google-emoji-kitchen-item.txt",
10
+ "emoji_kitchen_url": "https://emojik.vercel.app/s/{emoji1}_{emoji2}",
11
+ "default_size": 256
12
+ }
emoji_processor.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Core emoji processing logic for the Emoji Mashup application.
3
+ """
4
+
5
+ from sentence_transformers import SentenceTransformer
6
+ from sklearn.metrics.pairwise import cosine_similarity
7
+ import requests
8
+ from PIL import Image
9
+ from io import BytesIO
10
+
11
+ from config import CONFIG
12
+ from utils import logger, kitchen_txt_to_dict
13
+
14
+ class EmojiProcessor:
15
+ def __init__(self, model_name=CONFIG["model_name"]):
16
+ """Initialize the emoji processor with the specified model.
17
+
18
+ Args:
19
+ model_name: Name of the sentence transformer model to use
20
+ """
21
+ logger.info(f"Loading model: {model_name}")
22
+ self.model = SentenceTransformer(model_name)
23
+ self.emotion_dict = {}
24
+ self.event_dict = {}
25
+ self.emotion_embeddings = {}
26
+ self.event_embeddings = {}
27
+
28
+ def load_emoji_dictionaries(self, emotion_file=CONFIG["emotion_file"], item_file=CONFIG["item_file"]):
29
+ """Load emoji dictionaries from text files.
30
+
31
+ Args:
32
+ emotion_file: Path to the emotion emoji file
33
+ item_file: Path to the item emoji file
34
+ """
35
+ logger.info("Loading emoji dictionaries")
36
+ self.emotion_dict = kitchen_txt_to_dict(emotion_file)
37
+ self.event_dict = kitchen_txt_to_dict(item_file)
38
+
39
+ # Precompute embeddings
40
+ logger.info("Computing embeddings for emoji dictionaries")
41
+ self.emotion_embeddings = {emoji: self.model.encode(desc) for emoji, desc in self.emotion_dict.items()}
42
+ self.event_embeddings = {emoji: self.model.encode(desc) for emoji, desc in self.event_dict.items()}
43
+
44
+ def find_top_emojis(self, embedding, emoji_embeddings, top_n=1):
45
+ """Find top matching emojis based on cosine similarity.
46
+
47
+ Args:
48
+ embedding: Sentence embedding to compare
49
+ emoji_embeddings: Dictionary of emoji embeddings
50
+ top_n: Number of top emojis to return
51
+
52
+ Returns:
53
+ List of top matching emojis
54
+ """
55
+ similarities = [
56
+ (emoji, cosine_similarity([embedding], [e_embed])[0][0])
57
+ for emoji, e_embed in emoji_embeddings.items()
58
+ ]
59
+ similarities.sort(key=lambda x: x[1], reverse=True)
60
+ return [emoji for emoji, _ in similarities[:top_n]]
61
+
62
+ def get_emoji_mashup_url(self, emoji1, emoji2, size=CONFIG["default_size"]):
63
+ """Generate URL for emoji mashup.
64
+
65
+ Args:
66
+ emoji1: First emoji character
67
+ emoji2: Second emoji character
68
+ size: Image size in pixels
69
+
70
+ Returns:
71
+ URL for the emoji mashup
72
+ """
73
+ return f"{CONFIG['emoji_kitchen_url'].format(emoji1=emoji1, emoji2=emoji2)}?size={size}"
74
+
75
+ def fetch_mashup_image(self, url):
76
+ """Fetch emoji mashup image from URL.
77
+
78
+ Args:
79
+ url: URL of the emoji mashup image
80
+
81
+ Returns:
82
+ PIL Image object or None if fetch failed
83
+ """
84
+ try:
85
+ response = requests.get(url)
86
+ if response.status_code == 200 and "image" in response.headers.get("Content-Type", ""):
87
+ return Image.open(BytesIO(response.content))
88
+ else:
89
+ logger.warning(f"Failed to fetch image: Status code {response.status_code}")
90
+ return None
91
+ except Exception as e:
92
+ logger.error(f"Error fetching image: {e}")
93
+ return None
94
+
95
+ def sentence_to_emojis(self, sentence):
96
+ """Process sentence to find matching emojis and generate mashup.
97
+
98
+ Args:
99
+ sentence: User input text
100
+
101
+ Returns:
102
+ Tuple of (emotion emoji, event emoji, mashup image)
103
+ """
104
+ if not sentence.strip():
105
+ return "❓", "❓", None
106
+
107
+ try:
108
+ embedding = self.model.encode(sentence)
109
+
110
+ top_emotion = self.find_top_emojis(embedding, self.emotion_embeddings, top_n=1)[0]
111
+ top_event = self.find_top_emojis(embedding, self.event_embeddings, top_n=1)[0]
112
+
113
+ mashup_url = self.get_emoji_mashup_url(top_emotion, top_event)
114
+ mashup_image = self.fetch_mashup_image(mashup_url)
115
+
116
+ return top_emotion, top_event, mashup_image
117
+ except Exception as e:
118
+ logger.error(f"Error processing sentence: {e}")
119
+ return "❌", "❌", None
utils.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Utility functions for the Emoji Mashup application.
3
+ """
4
+
5
+ import logging
6
+
7
+ # Configure logging
8
+ def setup_logging():
9
+ """Configure application logging."""
10
+ logging.basicConfig(
11
+ level=logging.INFO,
12
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
13
+ )
14
+ return logging.getLogger(__name__)
15
+
16
+ # Initialize logger
17
+ logger = setup_logging()
18
+
19
+ def kitchen_txt_to_dict(filepath):
20
+ """Convert emoji kitchen text file to dictionary.
21
+
22
+ Args:
23
+ filepath: Path to the emoji kitchen text file
24
+
25
+ Returns:
26
+ Dictionary mapping emojis to descriptions
27
+ """
28
+ emoji_dict = {}
29
+ try:
30
+ with open(filepath, 'r', encoding='utf-8') as f:
31
+ for line in f:
32
+ parts = line.strip().split(' ', 1)
33
+ if len(parts) == 2:
34
+ emoji, desc = parts
35
+ emoji_dict[emoji] = desc
36
+ return emoji_dict
37
+ except Exception as e:
38
+ logger.error(f"Error loading emoji dictionary from {filepath}: {e}")
39
+ return {}