From f03392d49754fada9ffc46d9107af3f3adf0409a Mon Sep 17 00:00:00 2001 From: Dr Alexander Mikhalev Date: Mon, 12 Oct 2026 10:44:36 +0100 Subject: [PATCH] fix: qualify synonym tutorial for publication --- .github/workflows/validate.yml | 5 +- config.toml | 2 +- content/how-tos/synonym-search.md | 16 +- scripts/test_synonym_publication.py | 80 +++++++++ static/demos/synonym-search/README.md | 70 ++++++++ .../demos/synonym-search/baseline-role.json | 91 +++++++++++ static/demos/synonym-search/captions.srt | 75 +++++++++ .../released-before-sharing.json | 13 ++ .../released-with-synthesis.json | 71 ++++++++ .../released-without-synthesis.json | 51 ++++++ static/demos/synonym-search/reproduction.json | 152 ++++++++++++++++++ .../synonym-search/synonym-search-example.zip | Bin 0 -> 12127 bytes themes/WarpDrive/templates/base.html | 29 +++- 13 files changed, 648 insertions(+), 7 deletions(-) create mode 100644 scripts/test_synonym_publication.py create mode 100644 static/demos/synonym-search/README.md create mode 100644 static/demos/synonym-search/baseline-role.json create mode 100644 static/demos/synonym-search/captions.srt create mode 100644 static/demos/synonym-search/released-before-sharing.json create mode 100644 static/demos/synonym-search/released-with-synthesis.json create mode 100644 static/demos/synonym-search/released-without-synthesis.json create mode 100644 static/demos/synonym-search/reproduction.json create mode 100644 static/demos/synonym-search/synonym-search-example.zip diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0215369..a997bfc 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -39,6 +39,9 @@ jobs: # Zola fails the build on broken internal links. run: zola build + - name: Verify editor, demo outputs and publication downloads + run: python3 -m unittest discover -s scripts -p 'test_*.py' -v + - name: Verify the build produced pages run: | pages=$(find public -name '*.html' | wc -l) @@ -64,4 +67,4 @@ jobs: uses: actions/checkout@v6 - name: Verify advertised downloads exist on the public channel - run: python3 scripts/check-release-links.py \ No newline at end of file + run: python3 scripts/check-release-links.py diff --git a/config.toml b/config.toml index 8878c85..d8014fe 100644 --- a/config.toml +++ b/config.toml @@ -51,7 +51,7 @@ include_content = true [extra] version = "1.21.16" -release_version = "1.21.18" +release_version = "1.21.19" navbar_items = [ { code = "en", nav_items = [ diff --git a/content/how-tos/synonym-search.md b/content/how-tos/synonym-search.md index 32bf89a..8ca51cc 100644 --- a/content/how-tos/synonym-search.md +++ b/content/how-tos/synonym-search.md @@ -5,6 +5,8 @@ date = 2026-10-11 [taxonomies] categories = ["How-tos"] tags = ["editor", "knowledge-graph", "search"] +[extra] +social_image = "/demos/synonym-search/poster.jpg" +++ Your project brief says **risk**. Later, you search for **concern**. Terraphim connects the two so a change of wording does not hide the decisions you need. @@ -32,12 +34,12 @@ Download the graph and the clean text. This explicitly shares the document's aut Use the graph downloaded from that editing session: ```sh -terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --json +terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --search-only --json ``` The actual result contains three risk passages and their related decisions, with file and line locations. No generated answer is requested. -Add `--answer` to the same command for synthesis: +Replace `--search-only` with `--answer` for synthesis: ```sh terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --json --answer @@ -54,9 +56,17 @@ Editing and local search use your local data. Optional synthesis sends the retri - [Saved Markdown with alternatives](/demos/synonym-search/annotated.md) - [Actual result without synthesis](/demos/synonym-search/without-synthesis.json) - [Actual result with synthesis](/demos/synonym-search/with-synthesis.json) +- [Download the complete example ZIP](/demos/synonym-search/synonym-search-example.zip), including a step-by-step README +- [English subtitles (SRT)](/demos/synonym-search/captions.srt) The community garden brief is authored public sample input. The alternatives, downloaded graph, retrieved passages and generated answer are actual outputs. The command-line section displays those JSON fields in a readable presentation; it is not a separate Terraphim interface. The voice is synthetic British English (Emma). Setup is omitted, and the recorded interaction runs at its original speed. [Recording details and file identities](/demos/synonym-search/manifest.json). -This is a preview of the new export and search flow. It uses the [editor graph-sharing candidate](https://git.terraphim.cloud/terraphim/terraphim-editor/pulls/131) and the [grep synonym/synthesis candidate](https://git.terraphim.cloud/terraphim/terraphim-clients/pulls/385); older installed binaries may differ. A fresh synthesis run may produce different wording. +## Reproduce it with released builds + +The recording preserves its original candidate-build identities. The same flow was separately verified on 12 October 2026 using the published [Editor v0.1.0-rc.1 prerelease](https://github.com/terraphim/terraphim-editor/releases/tag/v0.1.0-rc.1) and [terraphim-grep v1.21.19](https://github.com/terraphim/terraphim-clients/releases/tag/v1.21.19). The editor is still an RC; the video is not a claim that every host or feature is fully qualified. + +Download the example ZIP, extract it, and follow `README.md`. It uses the same graph and clean brief as the recording. Verify `terraphim-grep --version` before running the two commands above. The release includes macOS and Linux builds; Windows is not claimed by this example. + +Inspect the separate released-binary outputs: [before sharing the synonym graph](/demos/synonym-search/released-before-sharing.json), [without synthesis](/demos/synonym-search/released-without-synthesis.json), and [with synthesis](/demos/synonym-search/released-with-synthesis.json). The baseline used the editor's default role, which lacks the authored synonym: zero passages became three when the exported graph was supplied. The paired modes retrieved the same passages. [Released-build identities, commands and file checksums](/demos/synonym-search/reproduction.json) distinguish this verification from the original recording. A fresh synthesis run may produce different wording. [Earlier browser and Zed host walkthroughs](/how-tos/knowledge-work-editor/) retain their own recorded versions and limitations. This focused story does not qualify all 41 source-video requirements. The Zed fork remains separate. diff --git a/scripts/test_synonym_publication.py b/scripts/test_synonym_publication.py new file mode 100644 index 0000000..596f4ee --- /dev/null +++ b/scripts/test_synonym_publication.py @@ -0,0 +1,80 @@ +"""Exercise the built page and the downloadable reproduction kit.""" +import hashlib +from html.parser import HTMLParser +import json +from pathlib import Path +import subprocess +import tempfile +import unittest +import zipfile + +ROOT = Path(__file__).resolve().parents[1] +MEDIA = ROOT / "static/demos/synonym-search" + + +class HeadParser(HTMLParser): + def __init__(self): + super().__init__() + self.meta = {} + self.canonicals = [] + + def handle_starttag(self, tag, attrs): + attrs = dict(attrs) + if tag == "meta": + self.meta[attrs.get("property", attrs.get("name"))] = attrs.get("content") + if tag == "link" and attrs.get("rel") == "canonical": + self.canonicals.append(attrs["href"]) + + +class PublicationTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.output = tempfile.TemporaryDirectory() + built = Path(cls.output.name) / "site" + subprocess.run(["zola", "build", "--output-dir", str(built)], cwd=ROOT, check=True, text=True) + cls.html = (built / "how-tos/synonym-search/index.html").read_text() + + @classmethod + def tearDownClass(cls): + cls.output.cleanup() + + def test_production_metadata_and_privacy_wording(self): + head = HeadParser() + head.feed(self.html) + url = "https://terraphim.ai/how-tos/synonym-search/" + self.assertEqual(head.canonicals, [url]) + self.assertEqual(head.meta["og:url"], url) + self.assertEqual(head.meta["og:title"], "Different words. The same idea.") + self.assertEqual(head.meta["og:image"], "https://terraphim.ai/demos/synonym-search/poster.jpg") + self.assertEqual(head.meta["twitter:card"], "summary_large_image") + self.assertNotIn("All data processed locally", self.html) + self.assertIn("Optional synthesis uses your configured model provider", self.html) + self.assertNotIn("editor graph-sharing candidate", self.html) + self.assertIn("v0.1.0-rc.1", self.html) + self.assertIn("v1.21.19", self.html) + + def test_released_evidence_and_bundle_match_actual_files(self): + receipt = json.loads((MEDIA / "reproduction.json").read_text()) + self.assertEqual(receipt["grepVersion"], "1.21.19") + self.assertEqual(receipt["editorVersion"], "0.1.0-rc.1") + before = json.loads((MEDIA / "released-before-sharing.json").read_text()) + off = json.loads((MEDIA / "released-without-synthesis.json").read_text()) + on = json.loads((MEDIA / "released-with-synthesis.json").read_text()) + self.assertEqual(before["chunks"], []) + self.assertEqual(off["chunks"], on["chunks"]) + self.assertEqual(len(off["chunks"]), 3) + self.assertIsNone(off["answer"]) + self.assertTrue(on["answer"]["answer"]) + self.assertEqual(len(on["answer"]["citations"]), 3) + with zipfile.ZipFile(MEDIA / "synonym-search-example.zip") as bundle: + self.assertEqual(set(bundle.namelist()), set(receipt["bundleFiles"])) + for name in receipt["bundleFiles"]: + self.assertEqual(bundle.read(name), (MEDIA / name).read_bytes()) + for item in receipt["files"]: + self.assertEqual(hashlib.sha256((MEDIA / item["file"]).read_bytes()).hexdigest(), item["sha256"]) + for name in ["reproduction.json", "synonym-search-example.zip", "captions.srt"]: + self.assertIn("/demos/synonym-search/" + name, self.html) + + +if __name__ == "__main__": + unittest.main() diff --git a/static/demos/synonym-search/README.md b/static/demos/synonym-search/README.md new file mode 100644 index 0000000..3ae366e --- /dev/null +++ b/static/demos/synonym-search/README.md @@ -0,0 +1,70 @@ +# Different words. The same idea. + +Source: https://terraphim.ai/how-tos/synonym-search/ + +This kit contains the actual graph and clean brief exported in the 80-second +recording, and separate evidence from released builds. The brief is public sample +input. The graph and search results are actual outputs. + +## Reproduce local retrieval + +1. Download terraphim-grep v1.21.19 for your macOS or Linux architecture: + https://github.com/terraphim/terraphim-clients/releases/tag/v1.21.19 + Check the archive against that release's SHA256SUMS, then extract it and put + terraphim-grep on PATH. No Windows build is claimed by this kit. +2. In this extracted directory, run: + +```sh +terraphim-grep --version +mkdir -p corpus +cp project-brief.md corpus/project-brief.md +terraphim-grep concern --thesaurus baseline-role.json --paths corpus -C 2 --search-only --json +terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --search-only --json +``` + +The first search uses the editor's default role, which lacks this authored +synonym. It returns zero passages. The exported graph connects Risk and Concern; +the second search returns three Risk passages even though Concern is absent +from the clean brief. `released-before-sharing.json` and +`released-without-synthesis.json` contain those actual outputs. + +## Compare optional synthesis + +Configure a model provider using the client release documentation. Then run: + +```sh +terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --json --answer +``` + +Optional synthesis sends the retrieved passages to your configured model +provider and may incur provider charges. The released verification used +DeepSeek (deepseek-v4-flash-0731). No credentials are included. Generated wording +can vary. Compare the chunks and citations, not an exact answer string: +`released-with-synthesis.json` has the same three chunks as the search-only run. +Decisions in the source do not prove that the actions have been completed. + +## Recreate the editor export + +Use https://terraphim.ai/editor/ or the published v0.1.0-rc.1 editor prerelease: +https://github.com/terraphim/terraphim-editor/releases/tag/v0.1.0-rc.1 + +Open the brief, add Concern as an alternative to Risk, swap between them, and +retain Risk in the final text. Choose Knowledge graph from the Markdown export +menu. The definition is `synonyms:: Risk, Concern`. Export the graph and clean +text, then use your exported filenames in the commands above. This explicitly +shares document synonyms; it does not silently update the active role. +`annotated.md` preserves the alternatives for reopening. + +## Provenance + +- `manifest.json`, `without-synthesis.json`, and `with-synthesis.json` describe + the original candidate-build recording. They have not been relabelled as + released-binary evidence. +- `reproduction.json` and the `released-*.json` files describe the separate + v0.1.0-rc.1 / v1.21.19 verification on 12 October 2026. +- `captions.vtt`, `captions.srt`, and `transcript.txt` accompany the original video. + The British female narration is synthetic (Emma, Kokoro). +- Video and poster are available on the source page; they are not in this ZIP. + +This focused flow does not qualify all 41 requirements or every extension. +The Zed fork remains separate. diff --git a/static/demos/synonym-search/baseline-role.json b/static/demos/synonym-search/baseline-role.json new file mode 100644 index 0000000..a8c1b2c --- /dev/null +++ b/static/demos/synonym-search/baseline-role.json @@ -0,0 +1,91 @@ +{ + "name": "terraphim-editor-default", + "data": { + "alternative": { + "id": 100, + "nterm": "alternatives" + }, + "alternatives": { + "id": 100, + "nterm": "alternatives" + }, + "caf\u00e9": { + "id": 4, + "nterm": "caf\u00e9" + }, + "choice": { + "id": 1, + "nterm": "decision" + }, + "coffee shop": { + "id": 4, + "nterm": "caf\u00e9" + }, + "coffeehouse": { + "id": 4, + "nterm": "caf\u00e9" + }, + "decision": { + "id": 1, + "nterm": "decision" + }, + "employ": { + "id": 8, + "nterm": "use" + }, + "eraser": { + "id": 2, + "nterm": "eraser" + }, + "honour": { + "id": 5, + "nterm": "honour" + }, + "judgment": { + "id": 1, + "nterm": "decision" + }, + "large language model": { + "id": 3, + "nterm": "llm", + "display_value": "LLM" + }, + "llm": { + "id": 3, + "nterm": "llm", + "display_value": "LLM" + }, + "option": { + "id": 1, + "nterm": "decision" + }, + "options set": { + "id": 100, + "nterm": "alternatives" + }, + "paperclip": { + "id": 7, + "nterm": "paperclip" + }, + "privilege": { + "id": 5, + "nterm": "honour" + }, + "rubber": { + "id": 2, + "nterm": "eraser" + }, + "use": { + "id": 8, + "nterm": "use" + }, + "utilise": { + "id": 8, + "nterm": "use" + }, + "variants": { + "id": 100, + "nterm": "alternatives" + } + } +} diff --git a/static/demos/synonym-search/captions.srt b/static/demos/synonym-search/captions.srt new file mode 100644 index 0000000..42e48a8 --- /dev/null +++ b/static/demos/synonym-search/captions.srt @@ -0,0 +1,75 @@ +1 +00:00:00,250 --> 00:00:04,443 +When people use different words for the same idea, useful decisions can + +2 +00:00:04,443 --> 00:00:06,190 +become surprisingly hard to find. + +3 +00:00:07,250 --> 00:00:10,852 +Here is our community garden brief. It records three risks, and the + +4 +00:00:10,852 --> 00:00:13,553 +decisions we have made to deal with each one. + +5 +00:00:15,250 --> 00:00:18,996 +I add concern as an alternative to risk. Now I can swap + +6 +00:00:18,996 --> 00:00:22,742 +between the two words, choosing the wording that fits without losing the + +7 +00:00:22,742 --> 00:00:23,366 +other option. + +8 +00:00:26,250 --> 00:00:30,840 +The editor connects those alternatives to one idea in the knowledge graph. + +9 +00:00:30,840 --> 00:00:35,047 +Here is the actual synonym definition: risk and concern belong together. + +10 +00:00:37,250 --> 00:00:41,059 +I download that graph and the finished text. Notice that I leave + +11 +00:00:41,059 --> 00:00:43,915 +risk in the document. The word concern is absent. + +12 +00:00:46,250 --> 00:00:50,497 +Now I search for concern using the graph I just downloaded. It + +13 +00:00:50,497 --> 00:00:54,744 +finds all three risk passages, including the related decisions, even though the + +14 +00:00:54,744 --> 00:00:55,805 +wording is different. + +15 +00:00:58,250 --> 00:01:02,632 +Without synthesis, I get the original passages and their locations. Adding the + +16 +00:01:02,632 --> 00:01:07,014 +answer flag gives me a summary from the same evidence, with source + +17 +00:01:07,014 --> 00:01:07,379 +references. + +18 +00:01:10,250 --> 00:01:14,735 +The summary keeps decisions distinct from completed actions. From choosing a word + +19 +00:01:14,735 --> 00:01:19,219 +to finding a decision, the same knowledge graph keeps the meaning connected. diff --git a/static/demos/synonym-search/released-before-sharing.json b/static/demos/synonym-search/released-before-sharing.json new file mode 100644 index 0000000..e88fb9a --- /dev/null +++ b/static/demos/synonym-search/released-before-sharing.json @@ -0,0 +1,13 @@ +{ + "chunks": [], + "answer": null, + "concepts": [], + "sufficiency": "RlmInsufficient", + "sufficiency_explanation": "No chunks or knowledge-graph concepts matched the query; there is nothing to synthesise an answer from.", + "stats": { + "search_latency_ms": 4, + "rlm_latency_ms": null, + "chunks_returned": 0, + "kg_hits": 0 + } +} diff --git a/static/demos/synonym-search/released-with-synthesis.json b/static/demos/synonym-search/released-with-synthesis.json new file mode 100644 index 0000000..7776363 --- /dev/null +++ b/static/demos/synonym-search/released-with-synthesis.json @@ -0,0 +1,71 @@ +{ + "chunks": [ + { + "content": "Risk: Timber may arrive late. Decision: Keep a backup supplier.", + "source": "project-brief.md", + "line_start": 7, + "line_end": 7, + "relevance_score": 2.0, + "haystack": "code" + }, + { + "content": "Risk: Rain may delay planting. Decision: Reserve a covered area.", + "source": "project-brief.md", + "line_start": 10, + "line_end": 10, + "relevance_score": 2.0, + "haystack": "code" + }, + { + "content": "Risk: Volunteers may cancel. Decision: Keep a reserve list.", + "source": "project-brief.md", + "line_start": 13, + "line_end": 13, + "relevance_score": 2.0, + "haystack": "code" + } + ], + "answer": { + "answer": "The project brief records three concerns/risks, each paired with a decision. It does not establish whether any of these decisions have been implemented or completed. The concerns are: timber may arrive late, rain may delay planting, and volunteers may cancel. The corresponding decisions are: keep a backup supplier, reserve a covered area, and keep a reserve list.", + "citations": [ + { + "source": "project-brief.md", + "line": 7, + "excerpt": "Risk: Timber may arrive late. Decision: Keep a backup supplier." + }, + { + "source": "project-brief.md", + "line": 10, + "excerpt": "Risk: Rain may delay planting. Decision: Reserve a covered area." + }, + { + "source": "project-brief.md", + "line": 13, + "excerpt": "Risk: Volunteers may cancel. Decision: Keep a reserve list." + } + ], + "confidence": 1.0 + }, + "concepts": [ + { + "id": 0, + "name": "concern", + "display_value": null, + "score": 1.0 + }, + { + "id": 0, + "name": "risk", + "display_value": null, + "score": 1.0 + } + ], + "sufficiency": "RlmSynthesis", + "sufficiency_explanation": "Found 3 chunks (coverage 1.00, KG confidence 1.00); the answer was synthesised by the LLM in 15349ms.", + "stats": { + "search_latency_ms": 15354, + "rlm_latency_ms": 15349, + "chunks_returned": 3, + "kg_hits": 2 + } +} diff --git a/static/demos/synonym-search/released-without-synthesis.json b/static/demos/synonym-search/released-without-synthesis.json new file mode 100644 index 0000000..3d1b2b5 --- /dev/null +++ b/static/demos/synonym-search/released-without-synthesis.json @@ -0,0 +1,51 @@ +{ + "chunks": [ + { + "content": "Risk: Timber may arrive late. Decision: Keep a backup supplier.", + "source": "project-brief.md", + "line_start": 7, + "line_end": 7, + "relevance_score": 2.0, + "haystack": "code" + }, + { + "content": "Risk: Rain may delay planting. Decision: Reserve a covered area.", + "source": "project-brief.md", + "line_start": 10, + "line_end": 10, + "relevance_score": 2.0, + "haystack": "code" + }, + { + "content": "Risk: Volunteers may cancel. Decision: Keep a reserve list.", + "source": "project-brief.md", + "line_start": 13, + "line_end": 13, + "relevance_score": 2.0, + "haystack": "code" + } + ], + "answer": null, + "concepts": [ + { + "id": 0, + "name": "concern", + "display_value": null, + "score": 1.0 + }, + { + "id": 0, + "name": "risk", + "display_value": null, + "score": 1.0 + } + ], + "sufficiency": "SearchOnly", + "sufficiency_explanation": "Found 3 chunks but diversity 1 < 2; returning search results only (pass --answer or --force-rlm to synthesise).", + "stats": { + "search_latency_ms": 2, + "rlm_latency_ms": null, + "chunks_returned": 3, + "kg_hits": 2 + } +} diff --git a/static/demos/synonym-search/reproduction.json b/static/demos/synonym-search/reproduction.json new file mode 100644 index 0000000..e174a56 --- /dev/null +++ b/static/demos/synonym-search/reproduction.json @@ -0,0 +1,152 @@ +{ + "schema": 1, + "verifiedAt": "2026-10-12", + "source": "https://terraphim.ai/how-tos/synonym-search/", + "editorVersion": "0.1.0-rc.1", + "grepVersion": "1.21.19", + "editorSourceHead": "05d0aa50151c131db4a3b30b56aba67c00add5fc", + "clientsSourceHead": "2d1820e81d2a9458d4d5eca012e7d0e0d2accf49", + "editorArchiveSha256": "a514f45276397b93f38d8e14c9e3bde6203bd9c625bc13c81829de31ffa9eb79", + "grepMacArmArchiveSha256": "2e9c8fc8b54124458a54120134ae5437f8b7e023df28fc1d515dd059c8f86a3e", + "checks": { + "graphSha256": "f8648b16470e764bdff5c95064078419d71e8d41d2ca30d4b1508017c166a45d", + "textSha256": "ea78a26e4d5a1105891bed67288a924cbbd5656defc95de4c511f4302b8d0d8f", + "binarySha256": "ce20e2bf87c6753c717dade4ac7baac98b05d0be9cb39af1f3afbcbf6e5c47de", + "binaryVersion": "terraphim-grep 1.21.19", + "status": "PASS", + "literalConcernAbsent": true, + "beforeSharingNoResults": true, + "aliasRetrieval": true, + "sameRetrievedChunks": true, + "sourceExcerptsExact": true, + "actualSynthesis": true, + "provider": "deepseek/deepseek-v4-flash-0731" + }, + "commands": [ + [ + "terraphim-grep", + "concern", + "--thesaurus", + "baseline-role.json", + "--paths", + "corpus", + "-C", + "2", + "--json", + "--search-only" + ], + [ + "terraphim-grep", + "concern", + "--thesaurus", + "knowledge-graph.json", + "--paths", + "corpus", + "-C", + "2", + "--json", + "--search-only" + ], + [ + "terraphim-grep", + "concern", + "--thesaurus", + "knowledge-graph.json", + "--paths", + "corpus", + "-C", + "2", + "--json", + "--answer" + ] + ], + "bundleFiles": [ + "README.md", + "annotated.md", + "baseline-role.json", + "knowledge-graph.json", + "project-brief.md", + "without-synthesis.json", + "with-synthesis.json", + "released-before-sharing.json", + "released-without-synthesis.json", + "released-with-synthesis.json", + "captions.vtt", + "captions.srt", + "transcript.txt", + "manifest.json", + "reproduction.json" + ], + "files": [ + { + "file": "README.md", + "bytes": 3267, + "sha256": "f4ac5c7d681ad5a99e688da04575bf21aae2cdc1dfded4395c7a20ee3b5d07fb" + }, + { + "file": "annotated.md", + "bytes": 793, + "sha256": "036d8e65b847fc03c68814b610be94e2b7a27573188947451348f9f674150e6e" + }, + { + "file": "baseline-role.json", + "bytes": 1506, + "sha256": "e850422ec72faa06aae0d6c2893a9f1d2e36d60a5aef79bd8f863daa2d71b015" + }, + { + "file": "knowledge-graph.json", + "bytes": 281, + "sha256": "f8648b16470e764bdff5c95064078419d71e8d41d2ca30d4b1508017c166a45d" + }, + { + "file": "project-brief.md", + "bytes": 265, + "sha256": "ea78a26e4d5a1105891bed67288a924cbbd5656defc95de4c511f4302b8d0d8f" + }, + { + "file": "without-synthesis.json", + "bytes": 1248, + "sha256": "302eb12c12e9f8a68daca280ee783c152221214969d630929d4666c5236c5365" + }, + { + "file": "with-synthesis.json", + "bytes": 2288, + "sha256": "d6381390ae7ce09b91cf406195b01ade90a753aad72594a7c3a1676443bf5b82" + }, + { + "file": "released-before-sharing.json", + "bytes": 344, + "sha256": "c79167288ff37166e9bb9e6c0d19bab2b86454d959db13680e3786349e58b7ae" + }, + { + "file": "released-without-synthesis.json", + "bytes": 1247, + "sha256": "6dd67609b8443b6f750788988d1d2433b83cb8e8016654424fab07ccb073570c" + }, + { + "file": "released-with-synthesis.json", + "bytes": 2151, + "sha256": "722bdd2b8aaf6e5f9910b8fecb84ae39ccb6d7dabd2a61a87b767e5347210352" + }, + { + "file": "captions.vtt", + "bytes": 1704, + "sha256": "8c1c3013e992032bcc8fa93c72718303bdc9e492142feaede595c70d2292cf28" + }, + { + "file": "captions.srt", + "bytes": 1744, + "sha256": "1842758bdc5b65be32400f47d8fb71401759f3826ecaa01621a3e5f03d084173" + }, + { + "file": "transcript.txt", + "bytes": 1540, + "sha256": "1eb1999a04add460c1474a2889e7fb12238b0cafd07a77ef6246ad97ce07c9b4" + }, + { + "file": "manifest.json", + "bytes": 4236, + "sha256": "af6ff6f0719b560d0eee3c71a3ba60ffed81857185ff1817f9839729ad170f9b" + } + ] +} diff --git a/static/demos/synonym-search/synonym-search-example.zip b/static/demos/synonym-search/synonym-search-example.zip new file mode 100644 index 0000000000000000000000000000000000000000..61821c04966a83dfd2fcc58901551e1ba8a1c5c7 GIT binary patch literal 12127 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 W2K|UI008)pZ{J5*EsXltum1xMfvMR5 literal 0 HcmV?d00001 diff --git a/themes/WarpDrive/templates/base.html b/themes/WarpDrive/templates/base.html index e789fc1..8cdf7c9 100644 --- a/themes/WarpDrive/templates/base.html +++ b/themes/WarpDrive/templates/base.html @@ -35,6 +35,31 @@ {% endblock title %} + {% set share_title = config.title %} + {% set share_description = config.description %} + {% set share_image = config.base_url ~ "/images/terraphim_logo.png" %} + {% if page %} + {% set share_title = page.title %} + {% if page.description %}{% set share_description = page.description %}{% endif %} + {% if page.extra.social_image %}{% set share_image = config.base_url ~ page.extra.social_image %}{% endif %} + {% elif section %} + {% if section.title %}{% set share_title = section.title %}{% endif %} + {% if section.description %}{% set share_description = section.description %}{% endif %} + {% endif %} + {% set canonical_path = current_path | default(value="/404.html") %} + {% set canonical = config.base_url ~ canonical_path %} + + + + + + + + + + + + {% if config.extra.analytics.google %}