mgeorgi commited on
Commit
d4448fe
·
verified ·
1 Parent(s): 9f0facd

Upload folder using huggingface_hub

Browse files
Files changed (5) hide show
  1. .gitignore +2 -0
  2. README.md +46 -7
  3. app.py +236 -0
  4. requirements.txt +8 -0
  5. sample.csv +0 -0
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .gradio
2
+ font_cache
README.md CHANGED
@@ -1,12 +1,51 @@
1
  ---
2
  title: Heeha
3
- emoji: 📊
4
- colorFrom: indigo
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 5.20.1
8
  app_file: app.py
9
- pinned: false
 
10
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
  title: Heeha
 
 
 
 
 
3
  app_file: app.py
4
+ sdk: gradio
5
+ sdk_version: 5.20.0
6
  ---
7
+ # Llama 3.2 3B Chat Interface
8
+
9
+ This project provides a Gradio web interface for interacting with the Llama 3.2 3B model using Hugging Face Transformers.
10
+
11
+ ## Prerequisites
12
+
13
+ - Python 3.8 or higher
14
+ - CUDA-capable GPU (recommended for better performance)
15
+ - Hugging Face account with access to Llama 3.2 models
16
+
17
+ ## Setup
18
+
19
+ 1. Clone this repository
20
+ 2. Install the required dependencies:
21
+ ```bash
22
+ pip install -r requirements.txt
23
+ ```
24
+ 3. Set up your Hugging Face token as an environment variable:
25
+ ```bash
26
+ export HF_TOKEN="your_huggingface_token_here"
27
+ ```
28
+ You can get your token from: https://huggingface.co/settings/tokens
29
+
30
+ ## Usage
31
+
32
+ Run the application:
33
+
34
+ ```bash
35
+ python app.py
36
+ ```
37
+
38
+ The Gradio interface will be available at `http://localhost:7860` by default.
39
+
40
+ ## Features
41
+
42
+ - Interactive chat interface using the Transformers pipeline
43
+ - Adjustable generation parameters (max new tokens and temperature)
44
+ - Example prompts for quick testing
45
+ - Automatic GPU utilization when available
46
+ - Uses bfloat16 precision for better performance
47
+ - Secure token handling through environment variables
48
+
49
+ ## Note
50
 
51
+ You need to have access to the Llama 3.2 models on Hugging Face. You can request access at: https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct
app.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import gradio as gr
3
+ from transformers import pipeline
4
+ from typing import List, Dict, Any, Tuple
5
+ import csv
6
+ from io import StringIO
7
+ from PIL import Image, ImageDraw, ImageFont
8
+ import requests
9
+ from io import BytesIO
10
+ import os
11
+ from pathlib import Path
12
+ import logging
13
+
14
+ # Create a font cache directory
15
+ FONT_CACHE_DIR = Path("./font_cache")
16
+ FONT_CACHE_DIR.mkdir(exist_ok=True)
17
+
18
+ # Define common font URLs and their corresponding filenames
19
+ FONT_SOURCES = {
20
+ "Arial": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Arial.ttf",
21
+ "Arial Bold": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Arial_Bold.ttf",
22
+ "Arial Bold Italic": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Arial_Bold_Italic.ttf",
23
+ "Arial Italic": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Arial_Italic.ttf",
24
+ "Courier New": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Courier_New.ttf",
25
+ "Verdana": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Verdana.ttf",
26
+ "Verdana Bold": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Verdana_Bold.ttf",
27
+ "Verdana Bold Italic": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Verdana_Bold_Italic.ttf",
28
+ "Verdana Italic": "https://github.com/matomo-org/travis-scripts/raw/master/fonts/Verdana_Italic.ttf",
29
+ }
30
+
31
+ # Font cache dictionary
32
+ font_cache = {}
33
+
34
+
35
+ def load_and_cache_fonts():
36
+ """Load and cache fonts from known sources."""
37
+ for font_name, url in FONT_SOURCES.items():
38
+ font_path = FONT_CACHE_DIR / f"{font_name}.ttf"
39
+
40
+ # Check if font is already cached
41
+ if font_path.exists():
42
+ try:
43
+ font_cache[font_name] = str(font_path)
44
+ logging.info(f"Loaded cached font: {font_name}")
45
+ except Exception as e:
46
+ logging.error(f"Error loading cached font {font_name}: {e}")
47
+ continue
48
+
49
+ # Download and cache font
50
+ try:
51
+ response = requests.get(url)
52
+ response.raise_for_status()
53
+
54
+ with open(font_path, "wb") as f:
55
+ f.write(response.content)
56
+
57
+ font_cache[font_name] = str(font_path)
58
+ logging.info(f"Downloaded and cached font: {font_name}")
59
+ except Exception as e:
60
+ logging.error(f"Error downloading font {font_name}: {e}")
61
+
62
+
63
+ # Initialize font cache at startup
64
+ load_and_cache_fonts()
65
+
66
+ # Initialize the pipeline (doing it here means it will be loaded only once when the script starts)
67
+ pipe = pipeline(
68
+ "text-generation",
69
+ model="alpindale/Llama-3.2-3B-Instruct",
70
+ torch_dtype=torch.bfloat16,
71
+ device="cuda",
72
+ )
73
+
74
+
75
+ def read_feed_data(feed_text: str) -> Dict[str, str]:
76
+ """Read the first row of feed data and return as dictionary.
77
+ Automatically detects the delimiter from common options (|, ,, ;, \t)."""
78
+ feed_io = StringIO(feed_text)
79
+ # Get first line to detect delimiter
80
+ first_line = feed_io.readline().strip()
81
+
82
+ # Common delimiters to check
83
+ delimiters = ["|", ",", ";", "\t"]
84
+ delimiter = "|" # default
85
+ max_count = 0
86
+
87
+ # Find the delimiter that splits the line into the most fields
88
+ for d in delimiters:
89
+ count = len(first_line.split(d))
90
+ if count > max_count:
91
+ max_count = count
92
+ delimiter = d
93
+
94
+ # Reset the StringIO buffer to start
95
+ feed_io.seek(0)
96
+ reader = csv.reader(feed_io, delimiter=delimiter)
97
+ headers = next(reader) # Get header row
98
+ first_row = next(reader) # Get first data row
99
+ return dict(zip(headers, first_row))
100
+
101
+
102
+ def overlay_text_on_image(
103
+ image_url: str,
104
+ text: str,
105
+ position: Tuple[int, int],
106
+ font_size: int,
107
+ font_color: str,
108
+ font_family: str,
109
+ ) -> Image.Image:
110
+ """Add text overlay to image with specified properties."""
111
+ # Download image
112
+ response = requests.get(image_url)
113
+ img = Image.open(BytesIO(response.content))
114
+
115
+ # Create draw object
116
+ draw = ImageDraw.Draw(img)
117
+
118
+ try:
119
+ # Try to use cached font first
120
+ if font_family in font_cache:
121
+ font = ImageFont.truetype(font_cache[font_family], font_size)
122
+ else:
123
+ # Fallback to system font or default
124
+ font = ImageFont.truetype(font_family, font_size)
125
+ except OSError:
126
+ # Ultimate fallback to default font
127
+ font = ImageFont.load_default()
128
+ logging.warning(f"Failed to load font {font_family}, using default")
129
+
130
+ # Convert RGBA color format to hex if needed
131
+ if font_color.startswith("rgba"):
132
+ try:
133
+ # Parse RGBA values
134
+ rgba = font_color.strip("rgba()").split(",")
135
+ r = int(float(rgba[0]))
136
+ g = int(float(rgba[1]))
137
+ b = int(float(rgba[2]))
138
+ a = int(float(rgba[3]) * 255) # Convert alpha from 0-1 to 0-255
139
+ font_color = f"#{r:02x}{g:02x}{b:02x}"
140
+ except (ValueError, IndexError):
141
+ logging.warning(
142
+ f"Invalid RGBA color format: {font_color}, falling back to white"
143
+ )
144
+ font_color = "#FFFFFF"
145
+
146
+ # Add text to image
147
+ draw.text(position, text, font=font, fill=font_color)
148
+
149
+ return img
150
+
151
+
152
+ def generate_response(
153
+ prompt: str,
154
+ feed_text: str,
155
+ text_x: int = 10,
156
+ text_y: int = 10,
157
+ font_size: int = 24,
158
+ font_color: str = "#FFFFFF",
159
+ font_family: str = "Arial",
160
+ max_new_tokens: int = 256,
161
+ temperature: float = 0.7,
162
+ ) -> tuple[str, Image.Image]:
163
+ # Read feed data
164
+ feed_data = read_feed_data(feed_text)
165
+
166
+ # Format the prompt using the chat template and feed data
167
+ formatted_prompt = prompt.format(**feed_data)
168
+ system_prompt = "You are a helpful assistant that processes Meta Product Feeds."
169
+
170
+ print(formatted_prompt)
171
+
172
+ messages = [
173
+ {"role": "system", "content": system_prompt},
174
+ {"role": "user", "content": formatted_prompt},
175
+ ]
176
+
177
+ # Generate response
178
+ outputs = pipe(
179
+ messages,
180
+ max_new_tokens=max_new_tokens,
181
+ temperature=temperature,
182
+ )
183
+ response = outputs[0]["generated_text"]
184
+
185
+ # Get image with text overlay
186
+ image_with_text = overlay_text_on_image(
187
+ image_url=feed_data.get("image_link", ""),
188
+ text=response[-1]["content"],
189
+ position=(text_x, text_y),
190
+ font_size=font_size,
191
+ font_color=font_color,
192
+ font_family=font_family,
193
+ )
194
+
195
+ return response[-1]["content"], image_with_text
196
+
197
+
198
+ # Create Gradio interface
199
+ demo = gr.Interface(
200
+ title="Meta Product Feed Chat",
201
+ description="Chat with Llama 3.2 model using feed data. Use {field_name} in your prompt to include feed data. The feed should be in CSV format with headers in the first row.",
202
+ fn=generate_response,
203
+ inputs=[
204
+ gr.Textbox(
205
+ label="Enter your prompt (use {field_name} for feed data)",
206
+ lines=3,
207
+ value="""
208
+ Write an English slogan for "{title}", respond with slogan only.
209
+ """,
210
+ ),
211
+ gr.Textbox(
212
+ label="Feed data (CSV with auto-detected delimiter)",
213
+ lines=10,
214
+ value="""id|item_group_id|title|description|availability|condition|price|sale_price|sale_price_effective_date|link|image_link|additional_image_link|brand|google_product_category|product_type|gtin|mpn|gender|age_group|color|material|pattern|size|shipping|custom_label_0|custom_label_1|custom_label_2|custom_label_3|custom_label_4|ios_url|ios_app_store_id|ios_app_name|android_url|android_package|android_app_name|additional image 1|additional image 2
215
+ 93310981|100274271|Spangenpumps aus Leder|Klassischer Spangenpumps aus Leder|in stock|new|52,99 EUR|false|2011-03-01T13:00-0800/2030-12-31T15:30-0800|https://www.bonprix.de/produkt/spangenpumps-aus-leder-schwarz-933109/?fb_pid=93310981|https://image01.bonprix.de/assets/1400x1960/1729512044/24082077-slWAlGkv.jpg|https://image01.bonprix.de/assets/1400x1960/1729512076/24081283-ApoUcVxa.jpg,,https://image01.bonprix.de/assets/1400x1960/1729512046/24082348-PLsOBIrl.jpg|bonprix|187|Damen > Schuhe > Pumps|8964004145445|93310981|female|adult|schwarz|Leder|Einfarbig|36,37,38,42,39,40,41|DE:::4.99 EUR|nein|false|Damen Schuhe > Pumps > Pumps > Spangenpumps|raus|raus|bonprix://www.bonprix.de/produkt/spangenpumps-aus-leder-schwarz-933109/?fb_pid=93310981|1090412741|bonprix – Mode und Wohn-Trends online shoppen|bonprix://www.bonprix.de/produkt/spangenpumps-aus-leder-schwarz-933109/?fb_pid=93310981|de.bonprix|bonprix – Mode online shoppen||""",
216
+ ),
217
+ gr.Number(label="Text X Position", value=10),
218
+ gr.Number(label="Text Y Position", value=10),
219
+ gr.Number(label="Font Size", value=24),
220
+ gr.ColorPicker(label="Font Color", value="#FFFFFF"),
221
+ gr.Dropdown(
222
+ label="Font Family",
223
+ choices=list(FONT_SOURCES.keys()),
224
+ value="Arial",
225
+ ),
226
+ gr.Slider(minimum=1, maximum=512, value=256, step=1, label="Max New Tokens"),
227
+ gr.Slider(minimum=0.1, maximum=2.0, value=0.7, step=0.1, label="Temperature"),
228
+ ],
229
+ outputs=[
230
+ gr.Textbox(label="Response", lines=5),
231
+ gr.Image(label="Product Image with Text"),
232
+ ],
233
+ )
234
+
235
+ if __name__ == "__main__":
236
+ demo.launch(share=True)
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ torch
2
+ numpy==1.26.0
3
+ gradio
4
+ sentencepiece
5
+ ninja
6
+ transformers
7
+ pillow
8
+ requests
sample.csv ADDED
The diff for this file is too large to render. See raw diff