Lincoln Gombedza
fix: point Save to Docs at notes.liiib.re β public instance with open registration
6e65427 unverified | """ | |
| 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) | |