nursing-research-writer / utils /docs_export.py
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)