| import streamlit as st |
| import pandas as pd |
| import json |
| import datetime |
| import os |
| import plotly.express as px |
| from fpdf import FPDF |
|
|
| st.set_page_config(page_title="BRA Research Academy - Bra Fit Survey", layout="centered") |
|
|
| st.title("π BRA-FIT Survey (BRA Research Academy)") |
|
|
| tab1, tab2 = st.tabs(["π Survey Form", "π Visualizations"]) |
|
|
| |
| if not os.path.exists("survey_data"): |
| os.makedirs("survey_data") |
|
|
| |
| braid_counter_file = "braid_counter.txt" |
| if not os.path.exists(braid_counter_file): |
| with open(braid_counter_file, "w") as f: |
| f.write("1000") |
|
|
| |
| def get_next_braid(): |
| with open(braid_counter_file, "r") as f: |
| current_braid = int(f.read().strip()) |
| next_braid = current_braid + 1 |
| with open(braid_counter_file, "w") as f: |
| f.write(str(next_braid)) |
| return f"BRAID{current_braid}" |
|
|
| |
| class PDF(FPDF): |
| def header(self): |
| self.set_font('Arial', 'B', 14) |
| self.cell(0, 10, 'BRA-FIT Survey Report', ln=True, align='C') |
| self.ln(10) |
|
|
| def chapter_title(self, title): |
| self.set_font('Arial', 'B', 12) |
| self.cell(0, 10, title, ln=True) |
| self.ln(4) |
|
|
| def chapter_body(self, body): |
| self.set_font('Arial', '', 12) |
| self.multi_cell(0, 10, body) |
| self.ln() |
|
|
| def generate_pdf(data, braid): |
| if isinstance(data, str): |
| data = json.loads(data) |
| pdf = PDF() |
| pdf.add_page() |
| pdf.chapter_title(f"Braid Number: {braid}") |
| for section, details in data.items(): |
| pdf.chapter_title(section) |
| body = "\n".join([f"{k}: {v}" for k, v in details.items()]) |
| pdf.chapter_body(body) |
| return pdf.output(dest='S').encode('latin-1') |
|
|
| with tab1: |
| st.header("Section A: Demographics & Background") |
| age = st.number_input("Age", min_value=20, max_value=60) |
| occupation = st.text_input("Occupation") |
| city_state = st.text_input("City & State") |
| body_type = st.selectbox("Body Type", ["Petite", "Tall", "Plus-size", "Average"]) |
| activity_level = st.selectbox("Activity Level", ["Sedentary", "Active", "Highly Active"]) |
| professional_fitting = st.radio("Have you ever had a professional bra fitting?", ["Yes", "No"]) |
|
|
| st.header("Section B: Breast & Body Details") |
| breast_size = st.text_input("Approximate Breast Size (if known)") |
| breast_shape = st.selectbox( |
| "Breast Shape", |
| ["Round", "Bell-shaped", "East-West", "Side set", "Teardrop", "Asymmetrical", "Athletic", "Relaxed"] |
| ) |
| asymmetry = st.radio("Any Asymmetry?", ["No", "Yes - Left Larger", "Yes - Right Larger"]) |
| underbust_cm = st.number_input("Underbust Measurement (cm)") |
| bust_cm = st.number_input("Bust Measurement (cm)") |
| rib_cage_shape = st.text_input("Rib Cage Shape (broad, narrow, protruding, flat)") |
|
|
| st.header("Section C: Bra Usage & Habits") |
| current_bra_size = st.text_input("Current Bra Size") |
| preferred_brands = st.text_input("Preferred Brands") |
| preferred_styles = st.multiselect( |
| "Preferred Bra Styles", |
| ["T-shirt", "Balconette", "Plunge", "Bralette", "Sports", "Full coverage", "Others"] |
| ) |
| fit_issues = st.multiselect( |
| "Common Fit Issues", |
| ["Tight band", "Spillage", "Straps dig in", "Underwire pokes", "Gaping cups", "Center gore not tacking"] |
| ) |
| replace_frequency = st.selectbox( |
| "How often do you replace your bras?", |
| ["Every 6 months", "Every year", "Every 2+ years", "Rarely"] |
| ) |
| dispose_method = st.text_input("How do you usually dispose of old bras?") |
| open_to_try = st.radio("Open to trying new bra styles/sizes?", ["Yes", "No"]) |
| willing_for_trial = st.radio("Willing to participate in bra trial & feedback?", ["Yes", "No"]) |
|
|
| |
| if st.button("Submit and Generate Report"): |
| |
| form_data = { |
| "Section A: Demographics & Background": { |
| "Age": age, |
| "Occupation": occupation, |
| "City & State": city_state, |
| "Body Type": body_type, |
| "Activity Level": activity_level, |
| "Professional Bra Fitting": professional_fitting |
| }, |
| "Section B: Breast & Body Details": { |
| "Approximate Breast Size": breast_size, |
| "Breast Shape": breast_shape, |
| "Asymmetry": asymmetry, |
| "Underbust Measurement (cm)": underbust_cm, |
| "Bust Measurement (cm)": bust_cm, |
| "Rib Cage Shape": rib_cage_shape |
| }, |
| "Section C: Bra Usage & Habits": { |
| "Current Bra Size": current_bra_size, |
| "Preferred Brands": preferred_brands, |
| "Preferred Styles": preferred_styles, |
| "Common Fit Issues": fit_issues, |
| "Replace Frequency": replace_frequency, |
| "Dispose Method": dispose_method, |
| "Open to Trying New Styles/Sizes": open_to_try, |
| "Willing to Participate in Trials": willing_for_trial |
| } |
| } |
|
|
| |
| missing_fields = [] |
| for section, details in form_data.items(): |
| for field, value in details.items(): |
| if not value: |
| missing_fields.append(f"{field} in {section}") |
| |
| if missing_fields: |
| st.error(f"Missing required fields in: {', '.join(missing_fields)}. Please fill them out.") |
| else: |
| st.success("Form submitted successfully!") |
|
|
| |
| unique_id = get_next_braid() |
| timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S") |
|
|
| |
| json_data = json.dumps(form_data, indent=4) |
| flat_data = {} |
| for section, items in form_data.items(): |
| for k, v in items.items(): |
| if isinstance(v, list): |
| v = ", ".join(v) |
| flat_data[k] = v |
| df = pd.DataFrame([flat_data]) |
|
|
| |
| json_file = json.dumps(form_data, indent=4) |
| |
| |
| pdf_file = generate_pdf(form_data, unique_id) |
|
|
| |
| st.download_button( |
| label="π Download Report as JSON", |
| data=json_file, |
| file_name=f"{unique_id}_bra_fit_survey.json", |
| mime="application/json" |
| ) |
|
|
| st.download_button( |
| label="π Download Report as PDF", |
| data=pdf_file, |
| file_name=f"{unique_id}_bra_fit_survey.pdf", |
| mime="application/pdf" |
| ) |
|
|
| st.download_button( |
| label="π Download Report as CSV", |
| data=df.to_csv(index=False).encode('utf-8'), |
| file_name=f"{unique_id}_bra_fit_survey.csv", |
| mime="text/csv" |
| ) |
|
|
| with tab2: |
| st.header("π Visualizations from Survey Data") |
|
|
| |
| all_data = [] |
| for file in os.listdir("survey_data"): |
| if file.endswith(".json"): |
| with open(os.path.join("survey_data", file)) as f: |
| data = json.load(f) |
| flat_record = {} |
| for section, items in data.items(): |
| for k, v in items.items(): |
| if isinstance(v, list): |
| v = ", ".join(v) |
| flat_record[k] = v |
| all_data.append(flat_record) |
|
|
| if all_data: |
| df = pd.DataFrame(all_data) |
|
|
| st.subheader("Age Distribution") |
| st.bar_chart(df['Age']) |
|
|
| st.subheader("Preferred Styles") |
| if 'Preferred Styles' in df.columns: |
| preferred_styles_series = df['Preferred Styles'].str.split(", ").explode() |
| style_counts = preferred_styles_series.value_counts().reset_index() |
| style_counts.columns = ['Style', 'Count'] |
| fig = px.pie(style_counts, names='Style', values='Count', title='Preferred Bra Styles') |
| st.plotly_chart(fig) |
|
|
| st.subheader("Fit Issues") |
| if 'Common Fit Issues' in df.columns: |
| fit_issues_series = df['Common Fit Issues'].str.split(", ").explode() |
| issues_counts = fit_issues_series.value_counts().reset_index() |
| issues_counts.columns = ['Issue', 'Count'] |
| fig2 = px.bar(issues_counts, x='Issue', y='Count', title='Common Fit Issues') |
| st.plotly_chart(fig2) |
|
|
| st.subheader("Activity Level Distribution") |
| if 'Activity Level' in df.columns: |
| activity_counts = df['Activity Level'].value_counts().reset_index() |
| activity_counts.columns = ['Activity Level', 'Count'] |
| fig3 = px.pie(activity_counts, names='Activity Level', values='Count', title='Activity Levels') |
| st.plotly_chart(fig3) |
|
|
| else: |
| st.info("No survey data found. Please submit the survey form first.") |
|
|