"""Generate the downloadable Word report.""" import io, tempfile from docx import Document from docx.shared import Inches import streamlit as st from config import FREQUENCIES from helpers import calc_abs_area def generate_docx() -> bytes: doc = Document() doc.add_heading("Room Acoustics Analysis Report", 0) # 1 ─ Input data doc.add_heading("1 Input Data", 1) doc.add_paragraph(f"Room volume: {st.session_state.room_volume:.2f} m³") if st.session_state.df_current_rt is not None: doc.add_heading("Current Reverberation Time", 2) doc.add_paragraph(st.session_state.df_current_rt.to_string(index=False)) if st.session_state.df_existing_mat is not None: doc.add_heading("Existing Materials – Coefficients & Areas", 2) doc.add_paragraph(st.session_state.df_existing_mat.to_string(index=False)) if not st.session_state.df_background_noise.empty: doc.add_heading("Background-Noise Measurements", 2) doc.add_paragraph(st.session_state.df_background_noise.to_string(index=False)) if st.session_state.df_spl is not None: doc.add_heading("Sound-Pressure Levels (SPL)", 2) doc.add_paragraph(st.session_state.df_spl.to_string()) # 2 ─ Speech-intelligibility (Dots & AI) doc.add_heading("2 Speech-Intelligibility (Dots & AI)", 1) if st.session_state.dots_init_dict: doc.add_heading("Initial Compliance Check", 2) for loc, dots in st.session_state.dots_init_dict.items(): ai, interp = st.session_state.ai_init_dict.get(loc, (None, "")) line = f"{loc}: Dots = {dots}" if ai is not None: line += f" → AI = {ai:.2f} ({interp})" doc.add_paragraph(line) if st.session_state.dots_final_dict: doc.add_heading("Final Compliance Check", 2) for loc, dots in st.session_state.dots_final_dict.items(): ai, interp = st.session_state.ai_final_dict.get(loc, (None, "")) line = f"{loc}: Dots = {dots}" if ai is not None: line += f" → AI = {ai:.2f} ({interp})" doc.add_paragraph(line) # 3 ─ Figures doc.add_heading("3 Figures", 1) def _add(fig, caption): if fig is None: return with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp: fig.write_image(tmp.name, scale=4) doc.add_picture(tmp.name, width=Inches(6)) doc.paragraphs[-1].alignment = 1 doc.add_paragraph(caption, style="Caption") _add(st.session_state.fig_rt_initial, "Fig 1 Initial RT60 vs Standard Range") _add(st.session_state.fig_bn_initial, "Fig 2 Initial Background-Noise vs Standard Range") _add(st.session_state.fig_rt_final, "Fig 3 Final RT60 vs Standard Range") _add(st.session_state.fig_bn_final, "Fig 4 Final Background-Noise vs Standard Range") buf = io.BytesIO() doc.save(buf) return buf.getvalue()