""" docs_export.py — La Suite Docs integration for CQAI Nursing Research Writer Converts generated essays, literature reviews, and reflective accounts to clean Markdown compatible with La Suite Docs (suitenumerique/docs). No API credentials needed. """ from __future__ import annotations from datetime import date import streamlit as st DOCS_PUBLIC_INSTANCE = "https://notes.liiib.re" DOCS_SIGNUP_URL = "https://notes.liiib.re" DOCS_IMPORT_GUIDE = """ **How to use La Suite Docs (free, no credit card):** 1. **Sign up** → go to [notes.liiib.re ↗](https://notes.liiib.re) and click **Start Writing** 2. Click **Créer un nouveau compte** (Create a new account) — enter username, email, password 3. Once logged in, click **+ New document** 4. Click the **⋯ menu → Import** → select your downloaded `.md` file 5. Your document is live — share, annotate, collaborate in real time > 💡 Accounts are free. Content resets monthly on this public demo instance. > For a permanent instance, consider self-hosting on Railway (see CQAI docs). """.format() def render_save_to_docs( title: str, markdown_content: str, filename: str, description: str = "", instance_url: str = DOCS_PUBLIC_INSTANCE, ) -> None: """Render a 'Save to Docs' panel with .md download + Open Docs link.""" st.markdown("---") st.markdown("#### 📄 Save to La Suite Docs") if description: st.caption(description) col_dl, col_open = st.columns(2) with col_dl: st.download_button( label="⬇️ Download as .md", data=markdown_content, file_name=f"{filename}.md", mime="text/markdown", use_container_width=True, key=f"docs_dl_{filename}", ) with col_open: st.link_button( "🌐 Sign up / Open Docs", url="https://notes.liiib.re", use_container_width=True, ) with st.expander("📋 How to import into Docs", expanded=False): st.markdown(DOCS_IMPORT_GUIDE) st.info( "💡 La Suite Docs is an open-source, GDPR-compliant alternative to Notion " "and Google Docs — built by the French and German governments. Free to use.", icon="ℹ️", ) # --------------------------------------------------------------------------- # Research Writer — Markdown formatter # --------------------------------------------------------------------------- def output_to_markdown( tool_name: str, topic: str, output_text: str, word_count: int | None = None, model: str | None = None, ) -> str: """ Wrap a Research Writer output in Docs-ready Markdown with metadata header. Args: tool_name: e.g. "Literature Review", "Essay Writer", "Reflective Account" topic: user-provided topic / question output_text: the full generated text (may already contain Markdown) word_count: approximate word count if available model: Claude model used """ meta_rows = [ f"| **Tool** | {tool_name} |", f"| **Topic** | {topic} |", f"| **Generated** | {date.today().strftime('%d %B %Y')} |", ] if word_count: meta_rows.append(f"| **Word count** | ~{word_count:,} |") if model: meta_rows.append(f"| **Model** | {model} |") lines = [ f"# {tool_name}", "", f"> *{topic}*", "", "---", "", "## Document Details", "", "| Field | Value |", "|-------|-------|", *meta_rows, "", "---", "", "## Content", "", output_text.strip(), "", "---", "", "## Academic Integrity Statement", "", "This document was generated using AI assistance (CQAI Nursing Research Writer). " "All AI-generated content has been reviewed for accuracy and academic integrity. " "References must be independently verified before submission.", "", "*This tool supports but does not replace academic judgment. " "Always follow your institution's AI use policy.*", ] return "\n".join(lines) def literature_review_to_markdown( topic: str, pico: dict | None, output_text: str, databases: list | None = None, ) -> str: """Format a literature review with PICO framing for Docs.""" pico = pico or {} db_list = databases or ["PubMed", "CINAHL", "Cochrane Library"] header_lines = [ "# Literature Review", "", f"> Topic: {topic} ", f"> Generated: {date.today().strftime('%d %B %Y')}", "", "---", "", ] if pico: header_lines += [ "## PICO Framework", "", "| Element | Description |", "|---------|-------------|", f"| **P — Population** | {pico.get('population', '[Not specified]')} |", f"| **I — Intervention** | {pico.get('intervention', '[Not specified]')} |", f"| **C — Comparison** | {pico.get('comparison', '[Not specified]')} |", f"| **O — Outcome** | {pico.get('outcome', '[Not specified]')} |", "", ] header_lines += [ "## Search Strategy", "", f"Databases searched: {', '.join(db_list)}", "", "---", "", "## Review", "", output_text.strip(), "", "---", "", "*Generated by CQAI Nursing Research Writer. " "This tool supports but does not replace academic judgment.*", ] return "\n".join(header_lines) def reflective_account_to_markdown( framework: str, situation: str, output_text: str, ) -> str: """Format a reflective account for Docs.""" lines = [ "# Reflective Account", "", f"> Framework: {framework} ", f"> Situation: {situation} ", f"> Date: {date.today().strftime('%d %B %Y')}", "", "---", "", "## Reflection", "", output_text.strip(), "", "---", "", "## NMC Revalidation — CPD Record", "", "| Field | Value |", "|-------|-------|", "| **Date of activity** | [DATE] |", "| **CPD method** | Reflective writing |", "| **Topic** | " + situation[:80] + " |", "| **NMC Standards addressed** | [e.g. Platform 1, 6] |", "| **Hours** | [X] |", "| **Confirmed by** | [NAME / NMC PIN] |", "", "---", "", "*Generated by CQAI Nursing Research Writer. " "Always review AI output before including in revalidation portfolio.*", ] return "\n".join(lines)