Spaces:
Sleeping
Sleeping
File size: 7,325 Bytes
f725ded 1a5096f 0663d77 1a5096f f725ded 1a5096f 0663d77 aab39ff f725ded 0663d77 f725ded 0663d77 aab39ff f725ded 0663d77 f725ded 0663d77 1a5096f 0663d77 1a5096f 49417eb 6796622 611dfea 1a5096f 3bdea97 3a016f4 3bdea97 1a5096f 3a016f4 3bdea97 3a016f4 1a5096f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
from io import BytesIO
import re
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Flowable
from reportlab.lib.units import mm
from reportlab.graphics.shapes import Drawing, Rect, String, Line
class SliderFlowable(Flowable):
def __init__(self, name, value, min_val, max_val, is_percentage=False):
Flowable.__init__(self)
self.name = name
self.value = value
self.min_val = min_val
self.max_val = max_val
self.is_percentage = is_percentage
self.width = 400
self.height = 80
def draw(self):
drawing = Drawing(self.width, self.height)
# Draw slider bar
bar = Rect(50, 30, 300, 20, fillColor=colors.HexColor("#f7fbfd"), strokeColor=colors.HexColor("#9999ff"))
drawing.add(bar)
# Draw slider value
if self.max_val == self.min_val:
value_width = 50 # or some default width
else:
value_width = 50 + ((self.value - self.min_val) / (self.max_val - self.min_val) * 300)
value_bar = Rect(50, 30, value_width - 50, 20, fillColor=colors.HexColor("#9999ff"), strokeColor=None)
drawing.add(value_bar)
# Add slider name
drawing.add(String(0, 60, self.name, fontSize=12, fillColor=colors.HexColor("#26004d")))
# Add range labels
min_str = f"{self.min_val:.1f}%" if self.is_percentage else f"{self.min_val:.1f}"
max_str = f"{self.max_val:.1f}%" if self.is_percentage else f"{self.max_val:.1f}"
drawing.add(String(40, 10, min_str, fontSize=10, fillColor=colors.HexColor("#26004d")))
drawing.add(String(340, 10, max_str, fontSize=10, fillColor=colors.HexColor("#26004d")))
# Add value label
value_str = f"{self.value:.1f}%" if self.is_percentage else f"{self.value:.1f}"
drawing.add(String(value_width - 20, 55, value_str, fontSize=10, fillColor=colors.HexColor("#26004d")))
# Add value marker
drawing.add(Line(value_width, 25, value_width, 55, strokeColor=colors.HexColor("#26004d"), strokeWidth=2))
drawing.drawOn(self.canv, 0, 0)
def create_styles():
styles = getSampleStyleSheet()
styles['Title'].fontName = 'Helvetica-Bold'
styles['Title'].fontSize = 18
styles['Title'].spaceAfter = 16
styles['Title'].textColor = colors.HexColor("#26004d")
styles['Heading1'].fontName = 'Helvetica-Bold'
styles['Heading1'].fontSize = 16
styles['Heading1'].spaceAfter = 10
styles['Heading1'].textColor = colors.HexColor("#3b0b75")
styles['Heading2'].fontName = 'Helvetica'
styles['Heading2'].fontSize = 14
styles['Heading2'].spaceAfter = 12
styles['Heading2'].textColor = colors.HexColor("#52176a")
styles['BodyText'].fontName = 'Helvetica'
styles['BodyText'].fontSize = 12
styles['BodyText'].spaceAfter = 12
styles['BodyText'].textColor = colors.HexColor("#26004d")
styles.add(ParagraphStyle(
name='Answer',
parent=styles['BodyText'],
backColor=colors.HexColor("#f0f2fd"),
borderColor=colors.HexColor("#9999ff"),
borderWidth=0.5,
borderPadding=(5, 5, 5, 5),
spaceAfter=10
))
return styles
def create_page_template(canvas, doc):
canvas.saveState()
canvas.setFillColor(colors.HexColor("#e6ebfb"))
canvas.rect(0, 0, doc.pagesize[0], doc.pagesize[1], fill=1)
canvas.setFillColor(colors.HexColor("#26004d"))
canvas.setFont('Helvetica', 9)
canvas.drawString(30, 20, f"Page {doc.page}")
canvas.restoreState()
def generate_pdf(session_state):
buffer = BytesIO()
doc = SimpleDocTemplate(buffer, pagesize=A4, rightMargin=20*mm, leftMargin=20*mm, topMargin=20*mm, bottomMargin=20*mm)
styles = create_styles()
story = [Paragraph("AI Trust and Opacity Evaluation", styles['Title'])]
pages = session_state.pages
answers = session_state.answers
for page in pages[:-1]: # Skip the last page
if 'input_key' in page and page['input_key'] is not None:
story.append(Paragraph(page['title'], styles['Heading1']))
story.append(Paragraph(page['content'], styles['BodyText']))
answer = answers.get(page['input_key'], "")
if isinstance(answer, list):
answer = ', '.join(answer)
if page.get('input_type') == 'combined':
option = answers.get(page['input_key'], "")
conclusion = answers.get(f"{page['input_key']}_conclusion", "")
answer = f"Option selected: {option}\n\nConclusion: {conclusion}"
# Create a table for the answer to allow multi-line text within a block
data = [[Paragraph(answer, styles['Answer'])]]
t = Table(data, colWidths=[450])
t.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, -1), colors.HexColor("#f0f2fd")),
('TEXTCOLOR', (0, 0), (-1, -1), colors.HexColor("#26004d")),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
('INNERGRID', (0, 0), (-1, -1), 0.25, colors.HexColor("#9999ff")),
('BOX', (0, 0), (-1, -1), 0.25, colors.HexColor("#9999ff")),
]))
story.append(t)
story.append(Spacer(1, 12))
# Add quantitative criteria visualization if applicable
if page['input_key'] in ['technological_literacy', 'cognitive_mismatch']:
story.extend(process_quantitative_criteria(answer, styles))
doc.build(story, onFirstPage=create_page_template, onLaterPages=create_page_template)
buffer.seek(0)
return buffer
def process_quantitative_criteria(answer, styles):
story = []
lines = answer.split('\n')
for line in lines:
parsed = parse_quantitative_criteria(line)
if parsed:
name, value, min_val, max_val, is_percentage = parsed
if is_percentage:
slider = SliderFlowable(name, value*100, min_val*100, max_val*100, is_percentage=True)
else:
slider = SliderFlowable(name, value, min_val, max_val, is_percentage=False)
story.append(slider)
return story
def parse_quantitative_criteria(input_string):
# Match both "Name: value [min-max]" and "Name [min-max]" formats
match = re.match(r'(.+?)\s*:\s*([-+]?(?:\d*\.*\d+)(?:%)?)\s*\[([-+]?(?:\d*\.*\d+)(?:%)?)\s*-\s*([-+]?(?:\d*\.*\d+)(?:%)?)?\]', input_string)
if match:
name, value, min_val, max_val = match.groups()
name = name.strip()
# Handle percentage inputs
is_percentage = '%' in value or '%' in min_val or '%' in max_val
value = float(value.rstrip('%'))
min_val = float(min_val.rstrip('%'))
max_val = float(max_val.rstrip('%'))
if is_percentage:
value /= 100
value = int(value)
min_val = int(min_val)
max_val = int(max_val)
else:
value = float(value)
min_val = float(min_val)
max_val = float(max_val)
return name, value, min_val, max_val, is_percentage
return None |