Soumik Bose commited on
Commit
bd8337b
·
1 Parent(s): 79d3c9c
Files changed (1) hide show
  1. download_messages_service.py +53 -53
download_messages_service.py CHANGED
@@ -1,5 +1,5 @@
1
  """
2
- Professional Chat Message Log PDF Generator
3
  Generates beautifully formatted PDF reports from chat conversations
4
  Uses WeasyPrint for superior CSS support and rendering
5
  Supports file attachments (CSV and Image files)
@@ -28,7 +28,7 @@ logging.basicConfig(
28
  logger = logging.getLogger(__name__)
29
 
30
  # ---------------------------------------------------------
31
- # CHAT LOG THEME - WEASYPRINT OPTIMIZED
32
  # ---------------------------------------------------------
33
  CSS_STYLE = """
34
  @page {
@@ -46,7 +46,7 @@ CSS_STYLE = """
46
 
47
  body {
48
  font-family: 'Helvetica', Arial, sans-serif;
49
- color: #1a1a1a;
50
  line-height: 1.6;
51
  font-size: 11pt;
52
  }
@@ -54,8 +54,8 @@ body {
54
  .header {
55
  position: running(header);
56
  font-size: 9pt;
57
- color: #666;
58
- border-bottom: 1px solid #ddd;
59
  padding-bottom: 4px;
60
  margin-bottom: 20px;
61
  }
@@ -63,8 +63,8 @@ body {
63
  .footer {
64
  position: running(footer);
65
  font-size: 9pt;
66
- color: #666;
67
- border-top: 1px solid #ddd;
68
  padding-top: 4px;
69
  text-align: center;
70
  }
@@ -78,26 +78,26 @@ body {
78
  .cover-title {
79
  font-size: 32pt;
80
  font-weight: bold;
81
- color: #003366;
82
  margin-bottom: 0.5in;
83
  letter-spacing: 1px;
84
  }
85
 
86
  .cover-subtitle {
87
  font-size: 18pt;
88
- color: #0055a5;
89
  margin-bottom: 1in;
90
  }
91
 
92
  .cover-meta {
93
  font-size: 14pt;
94
- color: #666;
95
  margin-bottom: 0.2in;
96
  }
97
 
98
  .cover-date {
99
  font-size: 11pt;
100
- color: #999;
101
  }
102
 
103
  .message-container {
@@ -107,7 +107,7 @@ body {
107
 
108
  .message-user {
109
  background-color: #ffffff;
110
- border-left: 0.5px solid #0055a5;
111
  padding: 16px 20px;
112
  margin-bottom: 16px;
113
  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
@@ -115,7 +115,7 @@ body {
115
 
116
  .message-assistant {
117
  background-color: #ffffff;
118
- border-left: 0.5px solid #003366;
119
  padding: 16px 20px;
120
  margin-bottom: 16px;
121
  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
@@ -130,23 +130,23 @@ body {
130
  }
131
 
132
  .role-user {
133
- color: #003366;
134
  font-size: 11pt;
135
  }
136
 
137
  .role-assistant {
138
- color: #003366;
139
  font-size: 11pt;
140
  }
141
 
142
  .timestamp {
143
  font-size: 9pt;
144
- color: #999;
145
  font-weight: normal;
146
  }
147
 
148
  .message-content {
149
- color: #333;
150
  font-size: 10pt;
151
  line-height: 1.5;
152
  word-wrap: break-word;
@@ -154,7 +154,7 @@ body {
154
  }
155
 
156
  a {
157
- color: #0055a5;
158
  text-decoration: none;
159
  word-wrap: break-word;
160
  overflow-wrap: break-word;
@@ -169,18 +169,18 @@ a:hover {
169
  }
170
 
171
  .message-divider {
172
- border-top: 1px solid #ddd;
173
  margin: 16px 0;
174
  }
175
 
176
  h1, h2, h3, h4 {
177
- color: #003366;
178
  margin-top: 12px;
179
  margin-bottom: 8px;
180
  }
181
 
182
  h1 { font-size: 16pt; }
183
- h2 { font-size: 14pt; color: #0055a5; }
184
  h3 { font-size: 12pt; }
185
  h4 { font-size: 11pt; }
186
 
@@ -203,12 +203,12 @@ table.many-columns td {
203
  }
204
 
205
  th {
206
- background-color: #003366;
207
  color: white;
208
  padding: 8px;
209
  text-align: left;
210
  font-weight: bold;
211
- border: 1px solid #002244;
212
  word-wrap: break-word;
213
  overflow-wrap: break-word;
214
  hyphens: auto;
@@ -216,7 +216,7 @@ th {
216
 
217
  td {
218
  padding: 6px 8px;
219
- border: 1px solid #ddd;
220
  word-wrap: break-word;
221
  overflow-wrap: break-word;
222
  max-width: 0;
@@ -226,21 +226,21 @@ td {
226
  }
227
 
228
  tr:nth-child(even) {
229
- background-color: #f8f9fa;
230
  }
231
 
232
  code {
233
- background-color: #f0f7ff;
234
  padding: 2px 6px;
235
  border-radius: 4px;
236
  font-family: 'Courier New', monospace;
237
  font-size: 9pt;
238
- color: #1a1a1a;
239
  }
240
 
241
  pre {
242
- background-color: #f0f7ff;
243
- border: 1px solid #c7ddff;
244
  border-left: none;
245
  padding: 12px;
246
  font-size: 8pt;
@@ -255,16 +255,16 @@ pre {
255
  pre code {
256
  background-color: transparent;
257
  padding: 0;
258
- color: #1a1a1a;
259
  }
260
 
261
  blockquote {
262
- border-left: 3px solid #0055a5;
263
  margin-left: 0;
264
  padding-left: 12px;
265
- color: #555;
266
  font-style: italic;
267
- background-color: #f8f9fa;
268
  padding: 8px 8px 8px 12px;
269
  margin: 10px 0;
270
  }
@@ -277,7 +277,7 @@ ul, ol {
277
 
278
  ul li:before {
279
  content: "• ";
280
- color: #0055a5;
281
  font-weight: bold;
282
  display: inline-block;
283
  width: 1em;
@@ -298,14 +298,14 @@ li {
298
  max-width: 100%;
299
  max-height: 400px;
300
  height: auto;
301
- border: 1px solid #ddd;
302
  padding: 4px;
303
  background: white;
304
  }
305
 
306
  .figure-caption {
307
  font-size: 9pt;
308
- color: #666;
309
  margin-top: 6px;
310
  font-style: italic;
311
  }
@@ -313,31 +313,31 @@ li {
313
  .file-item {
314
  margin-bottom: 12px;
315
  padding: 12px;
316
- background-color: #f8f9fa;
317
- border-left: 3px solid #0055a5;
318
  page-break-inside: avoid;
319
  }
320
 
321
  .file-label {
322
- color: #003366;
323
  font-weight: bold;
324
  font-size: 9pt;
325
  }
326
 
327
  .file-value {
328
- color: #333;
329
  font-size: 9pt;
330
  word-wrap: break-word;
331
  overflow-wrap: break-word;
332
  }
333
 
334
  .file-url {
335
- color: #0055a5;
336
  font-size: 7pt;
337
  font-family: 'Courier New', monospace;
338
  display: block;
339
  padding: 6px 8px;
340
- background-color: #f0f7ff;
341
  border-radius: 3px;
342
  margin-top: 4px;
343
  word-wrap: break-word;
@@ -346,7 +346,7 @@ li {
346
  }
347
 
348
  .file-url a {
349
- color: #0055a5;
350
  word-wrap: break-word;
351
  overflow-wrap: break-word;
352
  font-size: 7pt;
@@ -361,16 +361,16 @@ li {
361
  margin: 0;
362
  padding: 0;
363
  font-size: 10pt;
364
- color: #666;
365
  }
366
 
367
  .stats-summary strong {
368
- color: #003366;
369
  }
370
 
371
  .section-divider {
372
  border: none;
373
- border-top: 2px solid #0055a5;
374
  margin: 20px 0 30px 0;
375
  }
376
  """
@@ -569,7 +569,7 @@ class ChatLogGenerator:
569
  # Check if it's already a markdown link [text](url)
570
  if not line.strip().startswith('['):
571
  # Convert to "Click to View" link
572
- processed_lines.append(f'<a href="{stripped}" target="_blank" style="color: #0055a5; text-decoration: underline; font-weight: bold;">Click to View</a>')
573
  else:
574
  processed_lines.append(line)
575
  else:
@@ -579,7 +579,7 @@ class ChatLogGenerator:
579
 
580
  def replace_url(match):
581
  url = match.group(1)
582
- return f'<a href="{url}" target="_blank" style="color: #0055a5; text-decoration: underline; font-weight: bold;">Click to View</a>'
583
 
584
  processed_line = re.sub(url_pattern, replace_url, line)
585
  processed_lines.append(processed_line)
@@ -622,12 +622,12 @@ class ChatLogGenerator:
622
  return ""
623
 
624
  html = '<div style="margin: 30px 0; page-break-inside: avoid;">'
625
- html += '<h2 style="color: #003366; border-bottom: 2px solid #0055a5; padding-bottom: 8px; margin-bottom: 20px;">Attached Files</h2>'
626
 
627
  # CSV Files section
628
  csv_files = files_data.get('csv_files', [])
629
  if csv_files and len(csv_files) > 0:
630
- html += '<h3 style="color: #0055a5; margin-top: 20px; margin-bottom: 12px;">CSV Files:</h3>'
631
 
632
  for csv_file in csv_files:
633
  file_name = csv_file.get('fileName', 'Unknown')
@@ -646,7 +646,7 @@ class ChatLogGenerator:
646
  # Show clickable "Click to View" link
647
  html += f'''
648
  <div style="margin-top: 2px;">
649
- <a href="{file_path}" target="_blank" style="color: #0055a5; text-decoration: underline; font-weight: bold; font-size: 9pt;">Click to View</a>
650
  </div>
651
  '''
652
  else:
@@ -663,7 +663,7 @@ class ChatLogGenerator:
663
  # Image Files section
664
  image_files = files_data.get('image_files', [])
665
  if image_files and len(image_files) > 0:
666
- html += '<h3 style="color: #0055a5; margin-top: 20px; margin-bottom: 12px;">Image Files:</h3>'
667
 
668
  for img_file in image_files:
669
  file_name = img_file.get('fileName', 'Unknown')
@@ -682,7 +682,7 @@ class ChatLogGenerator:
682
  # Show clickable "Click to View" link
683
  html += f'''
684
  <div style="margin-top: 2px;">
685
- <a href="{file_path}" target="_blank" style="color: #0055a5; text-decoration: underline; font-weight: bold; font-size: 9pt;">Click to View</a>
686
  </div>
687
  '''
688
  else:
 
1
  """
2
+ Professional Chat Message Log PDF Generator - Soft Slate Blue Theme
3
  Generates beautifully formatted PDF reports from chat conversations
4
  Uses WeasyPrint for superior CSS support and rendering
5
  Supports file attachments (CSV and Image files)
 
28
  logger = logging.getLogger(__name__)
29
 
30
  # ---------------------------------------------------------
31
+ # SOFT SLATE BLUE THEME - WEASYPRINT OPTIMIZED
32
  # ---------------------------------------------------------
33
  CSS_STYLE = """
34
  @page {
 
46
 
47
  body {
48
  font-family: 'Helvetica', Arial, sans-serif;
49
+ color: #2d3748;
50
  line-height: 1.6;
51
  font-size: 11pt;
52
  }
 
54
  .header {
55
  position: running(header);
56
  font-size: 9pt;
57
+ color: #718096;
58
+ border-bottom: 1px solid #e2e8f0;
59
  padding-bottom: 4px;
60
  margin-bottom: 20px;
61
  }
 
63
  .footer {
64
  position: running(footer);
65
  font-size: 9pt;
66
+ color: #718096;
67
+ border-top: 1px solid #e2e8f0;
68
  padding-top: 4px;
69
  text-align: center;
70
  }
 
78
  .cover-title {
79
  font-size: 32pt;
80
  font-weight: bold;
81
+ color: #4a5568;
82
  margin-bottom: 0.5in;
83
  letter-spacing: 1px;
84
  }
85
 
86
  .cover-subtitle {
87
  font-size: 18pt;
88
+ color: #5b7c99;
89
  margin-bottom: 1in;
90
  }
91
 
92
  .cover-meta {
93
  font-size: 14pt;
94
+ color: #718096;
95
  margin-bottom: 0.2in;
96
  }
97
 
98
  .cover-date {
99
  font-size: 11pt;
100
+ color: #a0aec0;
101
  }
102
 
103
  .message-container {
 
107
 
108
  .message-user {
109
  background-color: #ffffff;
110
+ border-left: 0.5px solid #5b7c99;
111
  padding: 16px 20px;
112
  margin-bottom: 16px;
113
  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
 
115
 
116
  .message-assistant {
117
  background-color: #ffffff;
118
+ border-left: 0.5px solid #4a5568;
119
  padding: 16px 20px;
120
  margin-bottom: 16px;
121
  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
 
130
  }
131
 
132
  .role-user {
133
+ color: #4a5568;
134
  font-size: 11pt;
135
  }
136
 
137
  .role-assistant {
138
+ color: #4a5568;
139
  font-size: 11pt;
140
  }
141
 
142
  .timestamp {
143
  font-size: 9pt;
144
+ color: #a0aec0;
145
  font-weight: normal;
146
  }
147
 
148
  .message-content {
149
+ color: #4a5568;
150
  font-size: 10pt;
151
  line-height: 1.5;
152
  word-wrap: break-word;
 
154
  }
155
 
156
  a {
157
+ color: #5b7c99;
158
  text-decoration: none;
159
  word-wrap: break-word;
160
  overflow-wrap: break-word;
 
169
  }
170
 
171
  .message-divider {
172
+ border-top: 1px solid #e2e8f0;
173
  margin: 16px 0;
174
  }
175
 
176
  h1, h2, h3, h4 {
177
+ color: #4a5568;
178
  margin-top: 12px;
179
  margin-bottom: 8px;
180
  }
181
 
182
  h1 { font-size: 16pt; }
183
+ h2 { font-size: 14pt; color: #5b7c99; }
184
  h3 { font-size: 12pt; }
185
  h4 { font-size: 11pt; }
186
 
 
203
  }
204
 
205
  th {
206
+ background-color: #5b7c99;
207
  color: white;
208
  padding: 8px;
209
  text-align: left;
210
  font-weight: bold;
211
+ border: 1px solid #4a6b85;
212
  word-wrap: break-word;
213
  overflow-wrap: break-word;
214
  hyphens: auto;
 
216
 
217
  td {
218
  padding: 6px 8px;
219
+ border: 1px solid #e2e8f0;
220
  word-wrap: break-word;
221
  overflow-wrap: break-word;
222
  max-width: 0;
 
226
  }
227
 
228
  tr:nth-child(even) {
229
+ background-color: #f7fafc;
230
  }
231
 
232
  code {
233
+ background-color: #edf2f7;
234
  padding: 2px 6px;
235
  border-radius: 4px;
236
  font-family: 'Courier New', monospace;
237
  font-size: 9pt;
238
+ color: #2d3748;
239
  }
240
 
241
  pre {
242
+ background-color: #edf2f7;
243
+ border: 1px solid #cbd5e0;
244
  border-left: none;
245
  padding: 12px;
246
  font-size: 8pt;
 
255
  pre code {
256
  background-color: transparent;
257
  padding: 0;
258
+ color: #2d3748;
259
  }
260
 
261
  blockquote {
262
+ border-left: 3px solid #5b7c99;
263
  margin-left: 0;
264
  padding-left: 12px;
265
+ color: #4a5568;
266
  font-style: italic;
267
+ background-color: #f7fafc;
268
  padding: 8px 8px 8px 12px;
269
  margin: 10px 0;
270
  }
 
277
 
278
  ul li:before {
279
  content: "• ";
280
+ color: #5b7c99;
281
  font-weight: bold;
282
  display: inline-block;
283
  width: 1em;
 
298
  max-width: 100%;
299
  max-height: 400px;
300
  height: auto;
301
+ border: 1px solid #e2e8f0;
302
  padding: 4px;
303
  background: white;
304
  }
305
 
306
  .figure-caption {
307
  font-size: 9pt;
308
+ color: #718096;
309
  margin-top: 6px;
310
  font-style: italic;
311
  }
 
313
  .file-item {
314
  margin-bottom: 12px;
315
  padding: 12px;
316
+ background-color: #f7fafc;
317
+ border-left: 3px solid #5b7c99;
318
  page-break-inside: avoid;
319
  }
320
 
321
  .file-label {
322
+ color: #4a5568;
323
  font-weight: bold;
324
  font-size: 9pt;
325
  }
326
 
327
  .file-value {
328
+ color: #4a5568;
329
  font-size: 9pt;
330
  word-wrap: break-word;
331
  overflow-wrap: break-word;
332
  }
333
 
334
  .file-url {
335
+ color: #5b7c99;
336
  font-size: 7pt;
337
  font-family: 'Courier New', monospace;
338
  display: block;
339
  padding: 6px 8px;
340
+ background-color: #edf2f7;
341
  border-radius: 3px;
342
  margin-top: 4px;
343
  word-wrap: break-word;
 
346
  }
347
 
348
  .file-url a {
349
+ color: #5b7c99;
350
  word-wrap: break-word;
351
  overflow-wrap: break-word;
352
  font-size: 7pt;
 
361
  margin: 0;
362
  padding: 0;
363
  font-size: 10pt;
364
+ color: #718096;
365
  }
366
 
367
  .stats-summary strong {
368
+ color: #4a5568;
369
  }
370
 
371
  .section-divider {
372
  border: none;
373
+ border-top: 2px solid #5b7c99;
374
  margin: 20px 0 30px 0;
375
  }
376
  """
 
569
  # Check if it's already a markdown link [text](url)
570
  if not line.strip().startswith('['):
571
  # Convert to "Click to View" link
572
+ processed_lines.append(f'<a href="{stripped}" target="_blank" style="color: #5b7c99; text-decoration: underline; font-weight: bold;">Click to View</a>')
573
  else:
574
  processed_lines.append(line)
575
  else:
 
579
 
580
  def replace_url(match):
581
  url = match.group(1)
582
+ return f'<a href="{url}" target="_blank" style="color: #5b7c99; text-decoration: underline; font-weight: bold;">Click to View</a>'
583
 
584
  processed_line = re.sub(url_pattern, replace_url, line)
585
  processed_lines.append(processed_line)
 
622
  return ""
623
 
624
  html = '<div style="margin: 30px 0; page-break-inside: avoid;">'
625
+ html += '<h2 style="color: #4a5568; border-bottom: 2px solid #5b7c99; padding-bottom: 8px; margin-bottom: 20px;">Attached Files</h2>'
626
 
627
  # CSV Files section
628
  csv_files = files_data.get('csv_files', [])
629
  if csv_files and len(csv_files) > 0:
630
+ html += '<h3 style="color: #5b7c99; margin-top: 20px; margin-bottom: 12px;">CSV Files:</h3>'
631
 
632
  for csv_file in csv_files:
633
  file_name = csv_file.get('fileName', 'Unknown')
 
646
  # Show clickable "Click to View" link
647
  html += f'''
648
  <div style="margin-top: 2px;">
649
+ <a href="{file_path}" target="_blank" style="color: #5b7c99; text-decoration: underline; font-weight: bold; font-size: 9pt;">Click to View</a>
650
  </div>
651
  '''
652
  else:
 
663
  # Image Files section
664
  image_files = files_data.get('image_files', [])
665
  if image_files and len(image_files) > 0:
666
+ html += '<h3 style="color: #5b7c99; margin-top: 20px; margin-bottom: 12px;">Image Files:</h3>'
667
 
668
  for img_file in image_files:
669
  file_name = img_file.get('fileName', 'Unknown')
 
682
  # Show clickable "Click to View" link
683
  html += f'''
684
  <div style="margin-top: 2px;">
685
+ <a href="{file_path}" target="_blank" style="color: #5b7c99; text-decoration: underline; font-weight: bold; font-size: 9pt;">Click to View</a>
686
  </div>
687
  '''
688
  else: