MilanM commited on
Commit
4c680cd
·
verified ·
1 Parent(s): 6b23862

Update report_gen.py

Browse files
Files changed (1) hide show
  1. report_gen.py +82 -129
report_gen.py CHANGED
@@ -1,162 +1,115 @@
1
  import io
2
- import re
3
  from reportlab.lib import colors
4
  from reportlab.lib.pagesizes import A4
5
  from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
6
- from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Flowable
7
  from reportlab.lib.units import mm
8
  from reportlab.graphics.shapes import Drawing, Rect, String, Line
9
 
10
- class SliderFlowable(Flowable):
11
- def __init__(self, name, value, min_val, max_val, is_percentage=False):
12
- Flowable.__init__(self)
13
  self.name = name
14
  self.value = value
15
  self.min_val = min_val
16
  self.max_val = max_val
17
- self.is_percentage = is_percentage
18
- self.width = 400
19
- self.height = 80
20
-
21
- def draw(self):
22
- drawing = Drawing(self.width, self.height)
23
-
24
  # Draw slider bar
25
- bar = Rect(50, 30, 300, 20, fillColor=colors.HexColor("#f7fbfd"), strokeColor=colors.HexColor("#9999ff"))
26
- drawing.add(bar)
27
-
28
  # Draw slider value
29
- if self.max_val == self.min_val:
30
- value_width = 50 # or some default width
31
- else:
32
- value_width = 50 + ((self.value - self.min_val) / (self.max_val - self.min_val) * 300)
33
- value_bar = Rect(50, 30, value_width - 50, 20, fillColor=colors.HexColor("#9999ff"), strokeColor=None)
34
- drawing.add(value_bar)
35
-
36
- # Add slider name
37
- drawing.add(String(0, 60, self.name, fontSize=12, fillColor=colors.HexColor("#26004d")))
38
-
39
- # Add range labels
40
- min_str = f"{self.min_val:.1f}%" if self.is_percentage else f"{self.min_val:.1f}"
41
- max_str = f"{self.max_val:.1f}%" if self.is_percentage else f"{self.max_val:.1f}"
42
- drawing.add(String(40, 10, min_str, fontSize=10, fillColor=colors.HexColor("#26004d")))
43
- drawing.add(String(340, 10, max_str, fontSize=10, fillColor=colors.HexColor("#26004d")))
44
-
45
- # Add value label
46
- value_str = f"{self.value:.1f}%" if self.is_percentage else f"{self.value:.1f}"
47
- drawing.add(String(value_width - 20, 55, value_str, fontSize=10, fillColor=colors.HexColor("#26004d")))
48
-
49
- # Add value marker
50
- drawing.add(Line(value_width, 25, value_width, 55, strokeColor=colors.HexColor("#26004d"), strokeWidth=2))
51
-
52
- drawing.drawOn(self.canv, 0, 0)
53
 
54
  def create_styles():
55
  styles = getSampleStyleSheet()
56
- styles['Title'].fontName = 'Helvetica-Bold'
57
- styles['Title'].fontSize = 18
58
- styles['Title'].spaceAfter = 16
59
- styles['Title'].textColor = colors.HexColor("#26004d")
60
-
61
- styles['Heading1'].fontName = 'Helvetica-Bold'
62
- styles['Heading1'].fontSize = 16
63
- styles['Heading1'].spaceAfter = 10
64
- styles['Heading1'].textColor = colors.HexColor("#3b0b75")
65
-
66
- styles['Heading2'].fontName = 'Helvetica'
67
- styles['Heading2'].fontSize = 14
68
- styles['Heading2'].spaceAfter = 12
69
- styles['Heading2'].textColor = colors.HexColor("#52176a")
70
-
71
- styles['BodyText'].fontName = 'Helvetica'
72
- styles['BodyText'].fontSize = 12
73
- styles['BodyText'].spaceAfter = 12
74
- styles['BodyText'].textColor = colors.HexColor("#26004d")
75
-
76
  styles.add(ParagraphStyle(
77
- name='Answer',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  parent=styles['BodyText'],
79
  backColor=colors.HexColor("#f0f2fd"),
80
- borderColor=colors.HexColor("#9999ff"),
81
- borderWidth=0.5,
82
- borderPadding=(5, 5, 5, 5),
83
  spaceAfter=10
84
  ))
85
-
86
  return styles
87
 
88
- def create_page_template(canvas, doc):
89
- canvas.saveState()
90
- canvas.setFillColor(colors.HexColor("#e6ebfb"))
91
- canvas.rect(0, 0, doc.pagesize[0], doc.pagesize[1], fill=1)
92
- canvas.setFillColor(colors.HexColor("#26004d"))
93
- canvas.setFont('Helvetica', 9)
94
- canvas.drawString(30, 20, f"Page {doc.page}")
95
- canvas.restoreState()
96
-
97
  def generate_pdf(pages, answers):
98
  buffer = io.BytesIO()
99
  doc = SimpleDocTemplate(buffer, pagesize=A4, rightMargin=20*mm, leftMargin=20*mm, topMargin=20*mm, bottomMargin=20*mm)
100
  styles = create_styles()
101
- story = [Paragraph("AI Trust and Opacity Evaluation", styles['Title'])]
102
 
103
- for page in pages[:-1]: # Skip the last page
104
- if 'input_key' in page and page['input_key'] is not None:
105
- story.append(Paragraph(page['title'], styles['Heading1']))
106
  story.append(Paragraph(page['content'], styles['BodyText']))
107
-
 
 
 
 
108
  answer = answers.get(page['input_key'], "")
109
- if isinstance(answer, list):
110
- answer = ', '.join(answer)
111
-
112
- if page.get('input_type') == 'combined':
113
- option = answers.get(page['input_key'], "")
114
- conclusion = answers.get(f"{page['input_key']}_conclusion", "")
115
- story.append(Paragraph(f"<b>Option selected:</b> {option}", styles['Answer']))
116
- story.append(Paragraph(f"<b>Conclusion:</b> {conclusion}", styles['Answer']))
117
- else:
118
- story.append(Paragraph(f"<b>Answer:</b> {answer}", styles['Answer']))
119
-
120
- # Add quantitative criteria visualization if applicable
121
- if page['input_key'] in ['technological_literacy', 'cognitive_mismatch']:
122
- story.extend(process_quantitative_criteria(answer, styles))
123
-
124
- story.append(Spacer(1, 12))
125
-
126
- doc.build(story, onFirstPage=create_page_template, onLaterPages=create_page_template)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  buffer.seek(0)
128
  return buffer
129
 
130
- def process_quantitative_criteria(answer, styles):
131
- story = []
132
- lines = answer.split('\n')
133
- for line in lines:
134
- parsed = parse_quantitative_criteria(line)
135
- if parsed:
136
- name, value, min_val, max_val, is_percentage = parsed
137
- if is_percentage:
138
- slider = SliderFlowable(name, value*100, min_val*100, max_val*100, is_percentage=True)
139
- else:
140
- slider = SliderFlowable(name, value, min_val, max_val, is_percentage=False)
141
- story.append(slider)
142
- return story
143
-
144
- def parse_quantitative_criteria(input_string):
145
- match = re.match(r'(.+):\s*([-+]?(?:\d*\.*\d+)(?:%)?)(?:\s*\[([-+]?(?:\d*\.*\d+)(?:%)?)\s*-\s*([-+]?(?:\d*\.*\d+)(?:%)?)?\])?', input_string)
146
- if match:
147
- name, value, min_val, max_val = match.groups()
148
- name = name.strip()
149
-
150
- # Handle percentage inputs
151
- is_percentage = '%' in value or '%' in min_val or '%' in max_val
152
- value = float(value.rstrip('%'))
153
- min_val = float(min_val.rstrip('%') if min_val else 0)
154
- max_val = float(max_val.rstrip('%') if max_val else 100)
155
-
156
- if is_percentage:
157
- value /= 100
158
- min_val /= 100
159
- max_val /= 100
160
-
161
- return name, value, min_val, max_val, is_percentage
162
- return None
 
1
  import io
 
2
  from reportlab.lib import colors
3
  from reportlab.lib.pagesizes import A4
4
  from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
5
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle
6
  from reportlab.lib.units import mm
7
  from reportlab.graphics.shapes import Drawing, Rect, String, Line
8
 
9
+ class SliderFlowable(Drawing):
10
+ def __init__(self, name, value, min_val=1, max_val=10, width=400, height=50):
11
+ Drawing.__init__(self, width, height)
12
  self.name = name
13
  self.value = value
14
  self.min_val = min_val
15
  self.max_val = max_val
16
+
 
 
 
 
 
 
17
  # Draw slider bar
18
+ self.add(Rect(50, 15, 300, 20, fillColor=colors.lightgrey, strokeColor=colors.grey))
19
+
 
20
  # Draw slider value
21
+ value_width = 50 + ((self.value - self.min_val) / (self.max_val - self.min_val) * 300)
22
+ self.add(Rect(50, 15, value_width - 50, 20, fillColor=colors.blue, strokeColor=None))
23
+
24
+ # Add slider name and value
25
+ self.add(String(0, 40, self.name, fontSize=10))
26
+ self.add(String(value_width - 10, 40, str(self.value), fontSize=10))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  def create_styles():
29
  styles = getSampleStyleSheet()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  styles.add(ParagraphStyle(
31
+ name='SectionTitle',
32
+ parent=styles['Heading1'],
33
+ fontSize=16,
34
+ textColor=colors.HexColor("#3b0b75"),
35
+ spaceAfter=10
36
+ ))
37
+ styles.add(ParagraphStyle(
38
+ name='SubsectionTitle',
39
+ parent=styles['Heading2'],
40
+ fontSize=14,
41
+ textColor=colors.HexColor("#52176a"),
42
+ spaceAfter=8
43
+ ))
44
+ styles.add(ParagraphStyle(
45
+ name='BodyText',
46
+ parent=styles['Normal'],
47
+ fontSize=10,
48
+ textColor=colors.HexColor("#26004d"),
49
+ spaceAfter=6
50
+ ))
51
+ styles.add(ParagraphStyle(
52
+ name='AnswerText',
53
  parent=styles['BodyText'],
54
  backColor=colors.HexColor("#f0f2fd"),
55
+ borderPadding=(4, 4, 4, 4),
 
 
56
  spaceAfter=10
57
  ))
 
58
  return styles
59
 
 
 
 
 
 
 
 
 
 
60
  def generate_pdf(pages, answers):
61
  buffer = io.BytesIO()
62
  doc = SimpleDocTemplate(buffer, pagesize=A4, rightMargin=20*mm, leftMargin=20*mm, topMargin=20*mm, bottomMargin=20*mm)
63
  styles = create_styles()
64
+ story = [Paragraph("Critical Infrastructure - LLM Considerations Report", styles['Title'])]
65
 
66
+ for page in pages[:-1]: # Skip the last page (report generation page)
67
+ if page['type'] == 'description':
68
+ story.append(Paragraph(page['title'], styles['SectionTitle']))
69
  story.append(Paragraph(page['content'], styles['BodyText']))
70
+
71
+ elif page['type'] == 'quiz':
72
+ story.append(Paragraph(page['title'], styles['SubsectionTitle']))
73
+ story.append(Paragraph(page['description'], styles['BodyText']))
74
+
75
  answer = answers.get(page['input_key'], "")
76
+ story.append(Paragraph(f"<b>Analysis:</b>", styles['BodyText']))
77
+ story.append(Paragraph(answer, styles['AnswerText']))
78
+
79
+ risk_level = answers.get(page['slider_key'], 1)
80
+ story.append(SliderFlowable(f"Risk Level: {risk_level}", risk_level))
81
+
82
+ elif page['type'] == 'inference':
83
+ story.append(Paragraph(page['title'], styles['SubsectionTitle']))
84
+ story.append(Paragraph(page['prompt_description'], styles['BodyText']))
85
+
86
+ user_input = answers.get(page['input_key'], "")
87
+ inference_output = answers.get(page['output_key'], "")
88
+
89
+ story.append(Paragraph("<b>User Input:</b>", styles['BodyText']))
90
+ story.append(Paragraph(user_input, styles['AnswerText']))
91
+ story.append(Paragraph("<b>Inference Output:</b>", styles['BodyText']))
92
+ story.append(Paragraph(inference_output, styles['AnswerText']))
93
+
94
+ elif page['type'] == 'architecture':
95
+ story.append(Paragraph(page['title'], styles['SubsectionTitle']))
96
+
97
+ # We can't include the actual architecture diagram in the PDF,
98
+ # so we'll just mention that it was reviewed
99
+ story.append(Paragraph("Architecture diagram was reviewed.", styles['BodyText']))
100
+
101
+ analysis = answers.get(page['input_key'], "")
102
+ story.append(Paragraph("<b>Security Analysis:</b>", styles['BodyText']))
103
+ story.append(Paragraph(analysis, styles['AnswerText']))
104
+
105
+ story.append(Spacer(1, 12))
106
+
107
+ doc.build(story)
108
  buffer.seek(0)
109
  return buffer
110
 
111
+ def create_page_template(canvas, doc):
112
+ canvas.saveState()
113
+ canvas.setFont('Helvetica', 9)
114
+ canvas.drawString(20*mm, 10*mm, f"Page {doc.page}")
115
+ canvas.restoreState()