capradeepgujaran commited on
Commit
5af6c1b
1 Parent(s): 4751acf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -15
app.py CHANGED
@@ -7,6 +7,7 @@ import json
7
  import tempfile
8
  from typing import List, Dict, Tuple, Optional
9
  from dataclasses import dataclass
 
10
 
11
  @dataclass
12
  class Question:
@@ -111,29 +112,115 @@ class QuizGenerator:
111
  all(isinstance(opt, str) for opt in question["options"])
112
  )
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  class CertificateGenerator:
115
  def __init__(self):
116
  self.certificate_size = (1200, 800)
117
  self.border_color = '#4682B4'
118
  self.background_color = '#F0F8FF'
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  def generate(
121
  self,
122
- name: str,
123
  score: float,
 
124
  course_name: str,
125
  company_logo: Optional[str] = None,
126
  participant_photo: Optional[str] = None
127
  ) -> str:
128
- certificate = self._create_base_certificate()
129
- draw = ImageDraw.Draw(certificate)
130
-
131
- fonts = self._load_fonts()
132
- self._add_borders(draw)
133
- self._add_content(draw, fonts, name, score, course_name)
134
- self._add_images(certificate, company_logo, participant_photo)
135
-
136
- return self._save_certificate(certificate)
 
 
 
 
 
 
 
137
 
138
  def _create_base_certificate(self) -> Image.Image:
139
  return Image.new('RGB', self.certificate_size, self.background_color)
@@ -183,20 +270,24 @@ class CertificateGenerator:
183
  draw: ImageDraw.Draw,
184
  fonts: Dict[str, ImageFont.FreeTypeFont],
185
  name: str,
186
- score: float,
187
- course_name: str
188
  ):
189
  # Title and headers
190
  draw.text((600, 100), "CertifyMe AI", font=fonts['title'], fill=self.border_color, anchor="mm")
191
  draw.text((600, 160), "Certificate of Achievement", font=fonts['subtitle'], fill=self.border_color, anchor="mm")
192
 
 
 
 
 
193
  # Main content
194
  content = [
195
  (300, "This is to certify that", 'black'),
196
- (380, name.strip() or "Participant", self.border_color),
197
  (460, "has successfully completed", 'black'),
198
- (540, course_name.strip() or "Assessment", self.border_color),
199
- (620, f"with a score of {score:.1f}%", 'black'),
200
  (700, datetime.now().strftime("%B %d, %Y"), 'black')
201
  ]
202
 
 
7
  import tempfile
8
  from typing import List, Dict, Tuple, Optional
9
  from dataclasses import dataclass
10
+ import subprocess
11
 
12
  @dataclass
13
  class Question:
 
112
  all(isinstance(opt, str) for opt in question["options"])
113
  )
114
 
115
+ class FontManager:
116
+ """Manages font installation and loading for the certificate generator"""
117
+
118
+ @staticmethod
119
+ def install_fonts():
120
+ """Install required fonts if they're not already present"""
121
+ try:
122
+ # Install fonts package
123
+ subprocess.run([
124
+ "apt-get", "update", "-y"
125
+ ], check=True)
126
+ subprocess.run([
127
+ "apt-get", "install", "-y",
128
+ "fonts-liberation", # Provides Liberation fonts (Arial alternative)
129
+ "fontconfig" # Font configuration
130
+ ], check=True)
131
+
132
+ # Clear font cache
133
+ subprocess.run(["fc-cache", "-f"], check=True)
134
+ print("Fonts installed successfully")
135
+ except subprocess.CalledProcessError as e:
136
+ print(f"Warning: Could not install fonts: {e}")
137
+ except Exception as e:
138
+ print(f"Warning: Unexpected error installing fonts: {e}")
139
+
140
+ @staticmethod
141
+ def get_font_paths() -> Dict[str, str]:
142
+ """Get the paths to the required fonts"""
143
+ # Liberation Sans is a metric-compatible replacement for Arial
144
+ font_paths = {
145
+ 'regular': '/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf',
146
+ 'bold': '/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf'
147
+ }
148
+
149
+ # Fallback paths for different distributions
150
+ fallback_paths = {
151
+ 'regular': [
152
+ '/usr/share/fonts/liberation-sans/LiberationSans-Regular.ttf',
153
+ '/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf',
154
+ '/usr/share/fonts/TTF/LiberationSans-Regular.ttf'
155
+ ],
156
+ 'bold': [
157
+ '/usr/share/fonts/liberation-sans/LiberationSans-Bold.ttf',
158
+ '/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf',
159
+ '/usr/share/fonts/TTF/LiberationSans-Bold.ttf'
160
+ ]
161
+ }
162
+
163
+ # Check fallback paths
164
+ for style in ['regular', 'bold']:
165
+ if not os.path.exists(font_paths[style]):
166
+ for path in fallback_paths[style]:
167
+ if os.path.exists(path):
168
+ font_paths[style] = path
169
+ break
170
+
171
+ return font_paths
172
+
173
  class CertificateGenerator:
174
  def __init__(self):
175
  self.certificate_size = (1200, 800)
176
  self.border_color = '#4682B4'
177
  self.background_color = '#F0F8FF'
178
 
179
+ # Install fonts if needed
180
+ FontManager.install_fonts()
181
+ self.font_paths = FontManager.get_font_paths()
182
+
183
+ def _load_fonts(self) -> Dict[str, ImageFont.FreeTypeFont]:
184
+ """Load fonts with fallbacks"""
185
+ fonts = {}
186
+ try:
187
+ fonts['title'] = ImageFont.truetype(self.font_paths['bold'], 60)
188
+ fonts['text'] = ImageFont.truetype(self.font_paths['regular'], 40)
189
+ fonts['subtitle'] = ImageFont.truetype(self.font_paths['regular'], 30)
190
+ except Exception as e:
191
+ print(f"Font loading error: {e}. Using default font.")
192
+ default = ImageFont.load_default()
193
+ fonts = {
194
+ 'title': default,
195
+ 'text': default,
196
+ 'subtitle': default
197
+ }
198
+ return fonts
199
+
200
  def generate(
201
  self,
 
202
  score: float,
203
+ name: str,
204
  course_name: str,
205
  company_logo: Optional[str] = None,
206
  participant_photo: Optional[str] = None
207
  ) -> str:
208
+ """
209
+ Generate a certificate with custom styling and optional logo/photo
210
+ """
211
+ try:
212
+ certificate = self._create_base_certificate()
213
+ draw = ImageDraw.Draw(certificate)
214
+
215
+ fonts = self._load_fonts()
216
+ self._add_borders(draw)
217
+ self._add_content(draw, fonts, str(name), str(course_name), float(score))
218
+ self._add_images(certificate, company_logo, participant_photo)
219
+
220
+ return self._save_certificate(certificate)
221
+ except Exception as e:
222
+ print(f"Error generating certificate: {e}")
223
+ return None
224
 
225
  def _create_base_certificate(self) -> Image.Image:
226
  return Image.new('RGB', self.certificate_size, self.background_color)
 
270
  draw: ImageDraw.Draw,
271
  fonts: Dict[str, ImageFont.FreeTypeFont],
272
  name: str,
273
+ course_name: str,
274
+ score: float
275
  ):
276
  # Title and headers
277
  draw.text((600, 100), "CertifyMe AI", font=fonts['title'], fill=self.border_color, anchor="mm")
278
  draw.text((600, 160), "Certificate of Achievement", font=fonts['subtitle'], fill=self.border_color, anchor="mm")
279
 
280
+ # Clean inputs
281
+ name = str(name).strip() or "Participant"
282
+ course_name = str(course_name).strip() or "Assessment"
283
+
284
  # Main content
285
  content = [
286
  (300, "This is to certify that", 'black'),
287
+ (380, name, self.border_color),
288
  (460, "has successfully completed", 'black'),
289
+ (540, course_name, self.border_color),
290
+ (620, f"with a score of {float(score):.1f}%", 'black'),
291
  (700, datetime.now().strftime("%B %d, %Y"), 'black')
292
  ]
293