diff --git a/.gitignore b/.gitignore index db5f9186d378..26245216cb90 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ examples/**/dataset/** # Flower Baselines baselines/datasets/leaf +# Swift auto-generated documentation +Documentation + # Exclude ee package src/py/flwr/ee diff --git a/intelligence/dev/build-docs.sh b/intelligence/dev/build-docs.sh index 9c7f43bd1c6f..7e093532fe63 100755 --- a/intelligence/dev/build-docs.sh +++ b/intelligence/dev/build-docs.sh @@ -2,6 +2,8 @@ set -e cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"/../ +python3 dev/build-example-docs.py + # Build TS docs cd ts && \ pnpm build:docs --readme none --name "TypeScript API" && \ diff --git a/intelligence/dev/build-example-docs.py b/intelligence/dev/build-example-docs.py new file mode 100644 index 000000000000..809f448d699e --- /dev/null +++ b/intelligence/dev/build-example-docs.py @@ -0,0 +1,150 @@ +# Copyright 2025 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Build the examples docs.""" + +import os +import re +import shutil + +from pathlib import Path + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +INDEX = os.path.join(ROOT, "docs", "source", "examples.rst") + +initial_text = """ +Examples +======== + +Below you will find a list of Flower Intelligence examples for Node.js and for +web apps running in the browser (as a tab or WebExtension). + +Node.js Examples +---------------- + +Those examples will run in the terminal and are mostly there to showcase some +features with very low overhead. You'll find more instruction in the +respective pages. + +""" + +table_headers = ( + "\n.. list-table::\n :widths: 50 45 \n " + ":header-rows: 1\n\n * - Title\n - Tags\n\n" +) + +categories = { + "node": {"table": table_headers, "list": ""}, + "web": {"table": table_headers, "list": ""}, +} + + +def _read_metadata(example): + with open(os.path.join(example, "README.md")) as f: + content = f.read() + + metadata_match = re.search(r"^---(.*?)^---", content, re.DOTALL | re.MULTILINE) + if not metadata_match: + raise ValueError("Metadata block not found") + metadata = metadata_match.group(1) + + title_match = re.search(r"^# (.+)$", content, re.MULTILINE) + if not title_match: + raise ValueError("Title not found in metadata") + title = title_match.group(1).strip() + + tags_match = re.search(r"^tags:\s*\[(.+?)\]$", metadata, re.MULTILINE) + if not tags_match: + raise ValueError("Tags not found in metadata") + tags = tags_match.group(1).strip() + + return title, tags + + +def _add_table_entry(example, tag, table_var): + title, tags = _read_metadata(example) + example_name = Path(example).stem + table_entry = f" * - `{title} <{example_name}.html>`_ \n - {tags}\n\n" + if tag in tags: + categories[table_var]["table"] += table_entry + categories[table_var]["list"] += f" {example_name}\n" + return True + return False + + +def _copy_markdown_files(example): + for file in os.listdir(example): + if file.endswith(".md"): + src = os.path.join(example, file) + dest = os.path.join( + ROOT, "docs", "source", os.path.basename(example) + ".md" + ) + shutil.copyfile(src, dest) + + +def _add_gh_button(example): + gh_text = f'[View on GitHub](https://github.com/adap/flower/blob/main/intelligence/ts/examples/{example})' + readme_file = os.path.join(ROOT, "docs", "source", example + ".md") + with open(readme_file, "r+") as f: + content = f.read() + if gh_text not in content: + content = re.sub( + r"(^# .+$)", rf"\1\n\n{gh_text}", content, count=1, flags=re.MULTILINE + ) + f.seek(0) + f.write(content) + f.truncate() + + +def _main(): + if os.path.exists(INDEX): + os.remove(INDEX) + + with open(INDEX, "w") as index_file: + index_file.write(initial_text) + + examples_dir = os.path.join(ROOT, "ts", "examples") + for example in sorted(os.listdir(examples_dir)): + example_path = os.path.join(examples_dir, example) + if os.path.isdir(example_path): + _copy_markdown_files(example_path) + _add_gh_button(example) + if not _add_table_entry(example_path, "node", "node"): + _add_table_entry(example_path, "web", "web") + + with open(INDEX, "a") as index_file: + index_file.write(categories["node"]["table"]) + + index_file.write("\nWeb Examples\n------------\n") + index_file.write( + "Those examples will require you to use a browser. You'll find " + "more instructions in the respective pages.\n" + ) + index_file.write(categories["web"]["table"]) + + index_file.write( + "\n.. toctree::\n :maxdepth: 1\n :caption: Quickstart\n :hidden:\n\n" + ) + index_file.write(categories["node"]["list"]) + + index_file.write( + "\n.. toctree::\n :maxdepth: 1\n :caption: Advanced\n :hidden:\n\n" + ) + index_file.write(categories["web"]["list"]) + + index_file.write("\n") + + +if __name__ == "__main__": + _main() diff --git a/intelligence/docs/source/.gitignore b/intelligence/docs/source/.gitignore index a24d78479931..94c5a16e7c85 100644 --- a/intelligence/docs/source/.gitignore +++ b/intelligence/docs/source/.gitignore @@ -1,2 +1,4 @@ ts-api-ref/ swift-api-ref/ +*.md +examples.rst diff --git a/intelligence/docs/source/_static/view-gh.png b/intelligence/docs/source/_static/view-gh.png new file mode 100644 index 000000000000..afc3f07bc2d5 Binary files /dev/null and b/intelligence/docs/source/_static/view-gh.png differ diff --git a/intelligence/docs/source/index.rst b/intelligence/docs/source/index.rst index 1b61a501111f..7ea41d0a0150 100644 --- a/intelligence/docs/source/index.rst +++ b/intelligence/docs/source/index.rst @@ -642,6 +642,7 @@ Information-oriented API reference and other reference material. :caption: Reference docs ref-models + examples ts-api-ref/index Join the Flower Community diff --git a/intelligence/ts/examples/browser-extension/README.md b/intelligence/ts/examples/browser-extension/README.md index ba8be244a609..ea7a965f2ac9 100644 --- a/intelligence/ts/examples/browser-extension/README.md +++ b/intelligence/ts/examples/browser-extension/README.md @@ -1,17 +1,38 @@ -# Flower Intelligence Flower Extension Example +--- +tags: [web, browser, extension, chat, typescript] +--- -## Dev Notes +# Browser Extension Example -- The `watch` script relies on [entr](https://github.com/eradman/entr). -- You can use `npm` or `pnpm` (or probably `yarn`), but this README shows examples using `pnpm` +You can use `npm` or `pnpm` (or probably `yarn`), but this README shows examples using `pnpm` -Install dependencies: `pnpm i` +## Project setup -In order to use remote handoff, copy `.env.example` into `.env` and update the API keys and IDs inside it. +You must first download the example with the following command: -Build with: +```bash +git clone --depth=1 https://github.com/adap/flower.git _tmp && mv _tmp/intelligence/ts/examples/encrypted . && rm -rf _tmp && cd encrypted +``` -```sh +You can then install the project dependencies with: + +```bash +pnpm i +``` + +```{note} +The `watch` script relies on [entr](https://github.com/eradman/entr). +``` + +```{warning} +In order to use remote handoff, copy `.env.example` into `.env` and update the API key inside it (if you don't have a valid API key, you can register [here](https://flower.ai/intelligence/)). +``` + +## Build + +Then, you need to build the project: + +```bash pnpm build ``` @@ -21,3 +42,8 @@ Or rebuild when files change: # Make sure to install this first: https://github.com/eradman/entr pnpm watch ``` + +## Run + +Once you have built the project, you should find the web-extension content that +can be imported into a browser in `dist/`. diff --git a/intelligence/ts/examples/browser-extension/package.json b/intelligence/ts/examples/browser-extension/package.json index 81f07db41887..a412d03a99ac 100644 --- a/intelligence/ts/examples/browser-extension/package.json +++ b/intelligence/ts/examples/browser-extension/package.json @@ -10,8 +10,7 @@ "format:check": "prettier --check .", "lint": "eslint --fix src", "lint:check": "eslint src", - "ibuild": "pnpm i && pnpm build", - "build:extension": "pnpm ibuild && cd dist && zip -r -FS ./flower-intelligence-browser-assistant.xpi * && cd .." + "ibuild": "pnpm i && pnpm build" }, "dependencies": { "@flwr/flwr": "^0.1.3", diff --git a/intelligence/ts/examples/encrypted/README.md b/intelligence/ts/examples/encrypted/README.md index 547ba5916593..1ffb7433037d 100644 --- a/intelligence/ts/examples/encrypted/README.md +++ b/intelligence/ts/examples/encrypted/README.md @@ -1,13 +1,45 @@ -# Flower Intelligence Encrypted Example +--- +tags: [node, minimal, remote, encryption, Flower Confidential Remote Compute, typescript] +--- -In order to run this example, update the following values inside `src/index.ts`: +# Flower Confidential Remote Compute example -```typescript -fi.apiKey = 'REPLACE_HERE'; +You can use `npm` or `pnpm` (or probably `yarn`), but this README shows examples using `pnpm` + +## Project setup + +You must first download the example with the following command: + +```bash +git clone --depth=1 https://github.com/adap/flower.git _tmp && mv _tmp/intelligence/ts/examples/encrypted . && rm -rf _tmp && cd encrypted +``` + +You can then install the project dependencies with: + +```bash +pnpm i +``` + +```{warning} +In order to run this example, you need to update `fi.apiKey = 'REPLACE_HERE'` inside `src/index.ts` with a valid API key (if you don't have one, you can register [here](https://flower.ai/intelligence/)). ``` -Run example: +## Build + +Then, you need to build the project: ```bash -pnpm start +pnpm build +``` + +## Run + +In order to run the example once the project has been built: + +```bash +node dist/index.js +``` + +```{note} +You can also use `pnpm start` to perform the installation, build, and run steps at the same time. ``` diff --git a/intelligence/ts/examples/hello-world-js/README.md b/intelligence/ts/examples/hello-world-js/README.md index 135c046898ad..3204b63e9579 100644 --- a/intelligence/ts/examples/hello-world-js/README.md +++ b/intelligence/ts/examples/hello-world-js/README.md @@ -1,7 +1,41 @@ -# Flower Intelligence "Hello, World!" Example Project +--- +tags: [node, minimal, javascript] +--- -Run example: +# "Hello, World!" JavaScript Project + +You can use `npm` or `pnpm` (or probably `yarn`), but this README shows examples using `pnpm` + +## Project setup + +You must first download the example with the following command: + +```bash +git clone --depth=1 https://github.com/adap/flower.git _tmp && mv _tmp/intelligence/ts/examples/hello-world-js . && rm -rf _tmp && cd hello-world-js +``` + +You can then install the project dependencies with: ```bash -pnpm start +pnpm i +``` + +## Build + +If you want to build the project, you can use: + +```bash +pnpm build +``` + +## Run + +In order to run the example once the project has been built: + +```bash +node dist/index.js +``` + +```{note} +You can also use `pnpm start` to perform the installation, build, and run steps at the same time. ``` diff --git a/intelligence/ts/examples/hello-world-ts/README.md b/intelligence/ts/examples/hello-world-ts/README.md index 755190962d2f..08ba90f63443 100644 --- a/intelligence/ts/examples/hello-world-ts/README.md +++ b/intelligence/ts/examples/hello-world-ts/README.md @@ -1,7 +1,41 @@ -# Flower Intelligence "Hello, World!" TypeScript Example +--- +tags: [node, minimal, typescript] +--- -Run example: +# "Hello, World!" TypeScript Project + +You can use `npm` or `pnpm` (or probably `yarn`), but this README shows examples using `pnpm` + +## Project setup + +You must first download the example with the following command: + +```bash +git clone --depth=1 https://github.com/adap/flower.git _tmp && mv _tmp/intelligence/ts/examples/hello-world-ts . && rm -rf _tmp && cd hello-world-ts +``` + +You can then install the project dependencies with: ```bash -pnpm start +pnpm i +``` + +## Build + +If you want to build the project, you can use: + +```bash +pnpm build +``` + +## Run + +In order to run the example once the project has been built: + +```bash +node dist/index.js +``` + +```{note} +You can also use `pnpm start` to perform the installation, build, and run steps at the same time. ``` diff --git a/intelligence/ts/examples/streaming/README.md b/intelligence/ts/examples/streaming/README.md index 9e386654eef6..01aeb9661c44 100644 --- a/intelligence/ts/examples/streaming/README.md +++ b/intelligence/ts/examples/streaming/README.md @@ -1,7 +1,41 @@ -# Flower Intelligence Streaming TypeScript Example +--- +tags: [node, minimal, streaming, typescript] +--- -Run example: +# Response streaming example + +You can use `npm` or `pnpm` (or probably `yarn`), but this README shows examples using `pnpm` + +## Project setup + +You must first download the example with the following command: + +```bash +git clone --depth=1 https://github.com/adap/flower.git _tmp && mv _tmp/intelligence/ts/examples/streaming . && rm -rf _tmp && cd streaming +``` + +You can then install the project dependencies with: ```bash -pnpm start +pnpm i +``` + +## Build + +If you want to build the project, you can use: + +```bash +pnpm build +``` + +## Run + +In order to run the example once the project has been built: + +```bash +node dist/index.js +``` + +```{note} +You can also use `pnpm start` to perform the installation, build, and run steps at the same time. ``` diff --git a/intelligence/ts/examples/web-chat/README.md b/intelligence/ts/examples/web-chat/README.md index 710c31aa4b02..da8b9673fcf4 100644 --- a/intelligence/ts/examples/web-chat/README.md +++ b/intelligence/ts/examples/web-chat/README.md @@ -1,14 +1,35 @@ -# Flower Intelligence Web Example +--- +tags: [web, chat, minimal, typescript] +--- -Run example: +# Web Chat example + +You can use `npm` or `pnpm` (or probably `yarn`), but this README shows examples using `pnpm` + +## Project setup + +You must first download the example with the following command: + +```bash +git clone --depth=1 https://github.com/adap/flower.git _tmp && mv _tmp/intelligence/ts/examples/web-chat . && rm -rf _tmp && cd web-chat +``` + +And install the required dependencies: ```bash pnpm i -pnpm dev ``` -or simply: +## Run + +In order to run the project, you can use: ```bash -pnpm start +pnpm dev +``` + +This should display a URL that you can navigate to on your browser to view the web-chat. + +```{note} +You can also use `pnpm start` to perform the installation, build, and run steps at the same time. ```