From af46dbff555f0f31a129025d799c19d78acb8223 Mon Sep 17 00:00:00 2001 From: danielcampagnolitg <138441775+danielcampagnolitg@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:08:55 +0800 Subject: [PATCH] Initial chat (#27) * sophia rename. Initial chat service * Update package-lock.json * Initial chat functionality * chore: Add allowImportingTsExtensions option to tsconfig.json * fix: add noEmit option to tsconfig.json * fix: Add spinner and emit message sent event * fix: Update chat-message.component.html with margin adjustments * fix: Update chat message component * feat: Add updatedAt field to Chat model * fix: Update LlmMessage interface and ChatMessageComponent * feat: Add chat message display without header * fix: Update chat component layout * fix: Update chat component layout * Update chat * Fix updatedAt and test user id * Update api-chat.service.spec.ts * disable default test * feat: Generate summary documentation for a project * feat: Update `generateFolderSummary` to include the parent summaries and other additions to the prompt * various updates * frontend lint * feat: Implement scrolling to the bottom of the chat after loading * fix: Resolve TypeScript error in ChatComponent * fix: Implement scrolling to bottom of chat after loading * feat: Add console logs for debugging chat component lifecycle hooks * fix: Implement scrolling improvements in chat component * fix: Implement scrolling improvements in ChatComponent * feat: Add LLM selection to chat controls * fix: Update chat controls component * fix: Resolve compile errors in ChatControlsComponent * feat: Implement shared LLM service and update components * feat: use LlmService to fetch LLMs * feat: Add LLM service * feat: add LlmService and import it in shared module * fix: Update ChatControlsComponent to use LlmService feat: Add error handling and retry logic to LlmService test: Add unit tests for LlmService * update chat * lint and test fix --- bin/aider | 3 +- docs/docs/chatbot.md | 7 +- docs/docs/environment-variables.md | 2 +- docs/docs/index.md | 6 +- docs/docs/setup.md | 2 +- docs/mkdocs.yml | 1 + frontend/package-lock.json | 216 +++++++----- frontend/package.json | 2 + .../src/app/@shared/services/llm.service.ts | 23 ++ frontend/src/app/@shared/shared.module.ts | 2 + frontend/src/app/app-routing.module.ts | 6 - frontend/src/app/app.module.ts | 2 + .../chat-controls.component.html | 80 +++-- .../chat-controls.component.scss | 7 + .../chat-controls/chat-controls.component.ts | 115 ++++--- .../chat-header/chat-header.component.html | 2 +- .../chat/chat-list/chat-list.component.html | 30 ++ .../chat/chat-list/chat-list.component.scss | 9 + .../app/chat/chat-list/chat-list.component.ts | 66 ++++ .../chat-message/chat-message.component.html | 64 +--- .../chat-message/chat-message.component.scss | 29 ++ .../chat-message/chat-message.component.ts | 66 ++-- frontend/src/app/chat/chat-routing.module.ts | 7 +- frontend/src/app/chat/chat.component.html | 38 --- frontend/src/app/chat/chat.component.scss | 3 - frontend/src/app/chat/chat.component.ts | 64 ---- frontend/src/app/chat/chat.module.ts | 21 +- .../src/app/chat/chat/chat.component.html | 8 + .../src/app/chat/chat/chat.component.scss | 21 ++ frontend/src/app/chat/chat/chat.component.ts | 97 ++++++ frontend/src/app/chat/model/chat.ts | 37 ++- frontend/src/app/chat/model/message.ts | 24 +- frontend/src/app/chat/model/user.ts | 6 - .../services/api/api-chat.service.spec.ts | 8 +- .../app/chat/services/api/api-chat.service.ts | 37 ++- .../app/chat/services/chat-base.service.ts | 3 +- .../firebase/firebase-chat.service.ts | 166 ---------- .../src/app/runAgent/runAgent.component.ts | 32 +- .../app/shared/services/llm.service.spec.ts | 68 ++++ .../src/app/shared/services/llm.service.ts | 55 ++++ package-lock.json | 4 +- package.json | 4 + src/agent/agentContextLocalStorage.ts | 2 +- src/agent/agentContextTypes.ts | 7 +- .../fileAgentStateService.ts | 15 +- src/agent/agentWorkflowRunner.ts | 2 +- src/agent/pythonAgentRunner.ts | 30 +- src/agent/xmlAgentRunner.ts | 5 + src/app.ts | 28 +- src/appVars.ts | 8 + src/cache/fileFunctionCacheService.ts | 3 +- src/chat/chatService.test.ts | 147 +++++++++ src/chat/chatTypes.ts | 21 +- src/cli/agent.ts | 1 + src/cli/blueberry.ts | 45 +++ src/cli/cli.test.ts | 3 +- src/cli/cli.ts | 5 +- src/cli/docs.ts | 17 +- src/cli/easy.ts | 72 ++++ src/cli/gaia.ts | 4 +- src/cli/gen.ts | 2 + src/cli/query.ts | 60 ++++ src/cli/research.ts | 7 +- src/cli/swebench.ts | 2 +- .../functionSchemaParser.test.ts | 3 +- src/functionSchema/functionSchemaParser.ts | 3 +- src/functions/scm/github.ts | 3 +- src/functions/scm/gitlab.ts | 3 +- src/functions/storage/chroma.ts | 35 ++ src/functions/storage/filesystem.ts | 36 +- src/functions/storage/localFileStore.ts | 3 +- src/llm/base-llm.ts | 2 +- src/llm/llm.ts | 2 + src/llm/llmFactory.ts | 2 + src/llm/models/anthropic-vertex.ts | 14 +- src/llm/models/deepseek.ts | 26 +- src/llm/models/fireworks.ts | 3 +- src/llm/models/groq.ts | 53 +-- src/llm/models/llm.int.ts | 4 +- src/llm/models/mock-llm.ts | 4 +- src/llm/models/openai.ts | 27 +- src/llm/models/vertexai.ts | 1 - src/llm/multi-agent/blackberry.ts | 153 +++++++++ src/llm/multi-agent/blueberry.ts | 186 +++++++++++ src/llm/multi-llm.ts | 8 +- src/{ => modules/firestore}/firestore.ts | 2 +- .../firestore/firestoreAgentStateService.ts | 2 +- .../firestore/firestoreApplicationContext.ts | 18 + .../firestore/firestoreChatService.test.ts | 7 + src/modules/firestore/firestoreChatService.ts | 82 ++++- .../firestore/firestoreCodeReviewService.ts | 2 +- .../firestore}/firestoreFunctionCache.test.ts | 4 +- .../firestoreFunctionCacheService.ts | 4 +- .../firestore/firestoreLlmCallService.ts | 2 +- .../firestore/firestoreUserService.test.ts | 25 +- src/modules/firestore/firestoreUserService.ts | 11 +- .../firestore/resetFirestoreEmulator.ts | 23 ++ src/routes/chat/chat-routes.ts | 105 ++++++ src/routes/llms/llm-routes.ts | 8 +- src/swe/codeEditingAgent.ts | 11 +- src/swe/codeEditor.ts | 11 +- src/swe/codebaseQuery.ts | 65 ++++ src/swe/documentationBuilder.ts | 309 +++++++++++++----- src/swe/lang/nodejs/typescriptTools.ts | 3 +- src/swe/{projectMap.ts => repositoryMap.ts} | 60 +++- src/swe/selectFilesToEdit.test.ts | 2 +- src/swe/selectFilesToEdit.ts | 15 +- src/user/userService/fileUserService.ts | 3 +- src/user/userService/inMemoryUserService.ts | 2 +- tsconfig.json | 2 + variables/local.env.example | 4 +- 111 files changed, 2374 insertions(+), 908 deletions(-) create mode 100644 frontend/src/app/@shared/services/llm.service.ts create mode 100644 frontend/src/app/chat/chat-list/chat-list.component.html create mode 100644 frontend/src/app/chat/chat-list/chat-list.component.scss create mode 100644 frontend/src/app/chat/chat-list/chat-list.component.ts delete mode 100644 frontend/src/app/chat/chat.component.html delete mode 100644 frontend/src/app/chat/chat.component.scss delete mode 100644 frontend/src/app/chat/chat.component.ts create mode 100644 frontend/src/app/chat/chat/chat.component.html create mode 100644 frontend/src/app/chat/chat/chat.component.scss create mode 100644 frontend/src/app/chat/chat/chat.component.ts delete mode 100644 frontend/src/app/chat/model/user.ts delete mode 100644 frontend/src/app/chat/services/firebase/firebase-chat.service.ts create mode 100644 frontend/src/app/shared/services/llm.service.spec.ts create mode 100644 frontend/src/app/shared/services/llm.service.ts create mode 100644 src/appVars.ts create mode 100644 src/chat/chatService.test.ts create mode 100644 src/cli/blueberry.ts create mode 100644 src/cli/easy.ts create mode 100644 src/cli/query.ts create mode 100644 src/functions/storage/chroma.ts create mode 100644 src/llm/multi-agent/blackberry.ts create mode 100644 src/llm/multi-agent/blueberry.ts rename src/{ => modules/firestore}/firestore.ts (76%) create mode 100644 src/modules/firestore/firestoreApplicationContext.ts create mode 100644 src/modules/firestore/firestoreChatService.test.ts rename src/{cache => modules/firestore}/firestoreFunctionCache.test.ts (97%) rename src/{cache => modules/firestore}/firestoreFunctionCacheService.ts (96%) create mode 100644 src/modules/firestore/resetFirestoreEmulator.ts create mode 100644 src/routes/chat/chat-routes.ts create mode 100644 src/swe/codebaseQuery.ts rename src/swe/{projectMap.ts => repositoryMap.ts} (56%) diff --git a/bin/aider b/bin/aider index 66523557..3dbfd979 100755 --- a/bin/aider +++ b/bin/aider @@ -1,5 +1,6 @@ # Convenience script for running Aider source variables/local.env export VERTEXAI_PROJECT=$GCLOUD_PROJECT -export VERTEXAI_LOCATION=$GCLOUD_REGION +export VERTEXAI_LOCATION=$GCLOUD_CLAUDE_REGION +echo $VERTEXAI_PROJECT $VERTEXAI_LOCATION aider --model vertex_ai/claude-3-5-sonnet@20240620 diff --git a/docs/docs/chatbot.md b/docs/docs/chatbot.md index 3448a7ae..69119dc5 100644 --- a/docs/docs/chatbot.md +++ b/docs/docs/chatbot.md @@ -1,2 +1,7 @@ -# ChatBot +# Slack Chat Bot +Slack chatbot + +https://github.com/TrafficGuard/sophia/blob/main/src/modules/slack/slackChatBotService.ts + +Work in progress, documentation coming soon. \ No newline at end of file diff --git a/docs/docs/environment-variables.md b/docs/docs/environment-variables.md index 920babee..058286fb 100644 --- a/docs/docs/environment-variables.md +++ b/docs/docs/environment-variables.md @@ -30,7 +30,7 @@ This document provides comprehensive details about the environment variables uti - **Description**: The base URL for the user interface. - **Default Value**: `http://localhost:4200/` -**NOUS_FS** +**SOPHIA_FS** - **Description**: The base path for the FileSystem interface/tool. Useful for editing code in other local repositories. Alternatively use the -fs= arg. - **Default Value**: (Not set - defaults to `process.cwd()`) diff --git a/docs/docs/index.md b/docs/docs/index.md index bdd7de0b..a617087e 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -1,3 +1,4 @@ +#

nous logo @@ -5,10 +6,13 @@

The open-source TypeScript platform for autonomous AI agents and LLM based workflows

-The Ancient Greek word sophía (σοφία) is the abstract noun of σοφός (sophós), which variously translates to "clever, skillful, intelligent, wise" +

+

## The Sophia Story +The Ancient Greek word sophía (σοφία) variously translates to "clever, skillful, intelligent, wise" + Sophia started from a simple goal: to harness AI's potential to enhance real-world productivity, born in DevOps and Platform Engineering space. We envisioned a tool that could: - Automate various processes and support requests, and triage build failures. diff --git a/docs/docs/setup.md b/docs/docs/setup.md index c44ce4b7..17e6b9e9 100644 --- a/docs/docs/setup.md +++ b/docs/docs/setup.md @@ -111,7 +111,7 @@ Documentation for deploying on Google Cloud will be provided soon. Keep the Firestore emulator running in a separate shell or in the background ```bash -gcloud emulators firestore start --host-port=127.0.0.1:8243 +npm run emulators ``` ```bash npm run test diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index f9093551..c9d24fe1 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -44,6 +44,7 @@ nav: - autonomous-agents.md - software-engineer.md - code-review.md + - chatbot.md - integrations.md - roadmap.md - Blog: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f8769653..721b0689 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -25,7 +25,9 @@ "@ngx-translate/core": "^14.0.0", "date-fns": "^2.29.2", "lodash": "^4.17.20", + "marked": "^12.0.2", "material-design-icons-iconfont": "^6.1.0", + "ngx-markdown": "^14.0.1", "rxjs": "^7.5.0", "tslib": "^2.3.0", "zone.js": "~0.11.4" @@ -2994,8 +2996,7 @@ "node_modules/@braintree/sanitize-url": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", - "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==", - "dev": true + "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==" }, "node_modules/@colors/colors": { "version": "1.5.0", @@ -5228,6 +5229,11 @@ "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==", "dev": true }, + "node_modules/@types/marked": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.3.2.tgz", + "integrity": "sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -7660,6 +7666,16 @@ "node": ">= 10" } }, + "node_modules/clipboard": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", + "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "dependencies": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -8112,7 +8128,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", - "dev": true, "dependencies": { "layout-base": "^1.0.0" } @@ -8583,7 +8598,6 @@ "version": "3.30.0", "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.0.tgz", "integrity": "sha512-l590mjTHT6/Cbxp13dGPC2Y7VXdgc+rUeF8AnF/JPzhjNevbDJfObnJgaSjlldOgBQZbue+X6IUZ7r5GAgvauQ==", - "dev": true, "engines": { "node": ">=0.10" } @@ -8592,7 +8606,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", - "dev": true, "dependencies": { "cose-base": "^1.0.0" }, @@ -8604,7 +8617,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", - "dev": true, "dependencies": { "cose-base": "^2.2.0" }, @@ -8616,7 +8628,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", - "dev": true, "dependencies": { "layout-base": "^2.0.0" } @@ -8624,14 +8635,12 @@ "node_modules/cytoscape-fcose/node_modules/layout-base": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", - "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", - "dev": true + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==" }, "node_modules/d3": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", - "dev": true, "dependencies": { "d3-array": "3", "d3-axis": "3", @@ -8672,7 +8681,6 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "dev": true, "dependencies": { "internmap": "1 - 2" }, @@ -8684,7 +8692,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", - "dev": true, "engines": { "node": ">=12" } @@ -8693,7 +8700,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "dev": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -8709,7 +8715,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "dev": true, "dependencies": { "d3-path": "1 - 3" }, @@ -8721,7 +8726,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "dev": true, "engines": { "node": ">=12" } @@ -8730,7 +8734,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", - "dev": true, "dependencies": { "d3-array": "^3.2.0" }, @@ -8742,7 +8745,6 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", - "dev": true, "dependencies": { "delaunator": "5" }, @@ -8754,7 +8756,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "dev": true, "engines": { "node": ">=12" } @@ -8763,7 +8764,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "dev": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" @@ -8776,7 +8776,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "dev": true, "dependencies": { "commander": "7", "iconv-lite": "0.6", @@ -8801,7 +8800,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, "engines": { "node": ">= 10" } @@ -8810,7 +8808,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "dev": true, "engines": { "node": ">=12" } @@ -8819,7 +8816,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "dev": true, "dependencies": { "d3-dsv": "1 - 3" }, @@ -8831,7 +8827,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "dev": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", @@ -8845,7 +8840,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "dev": true, "engines": { "node": ">=12" } @@ -8854,7 +8848,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", - "dev": true, "dependencies": { "d3-array": "2.5.0 - 3" }, @@ -8866,7 +8859,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "dev": true, "engines": { "node": ">=12" } @@ -8875,7 +8867,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "dev": true, "dependencies": { "d3-color": "1 - 3" }, @@ -8887,7 +8878,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "dev": true, "engines": { "node": ">=12" } @@ -8896,7 +8886,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", - "dev": true, "engines": { "node": ">=12" } @@ -8905,7 +8894,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "dev": true, "engines": { "node": ">=12" } @@ -8914,7 +8902,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "dev": true, "engines": { "node": ">=12" } @@ -8923,7 +8910,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "dev": true, "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -8939,7 +8925,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", - "dev": true, "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" @@ -8952,7 +8937,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "dev": true, "engines": { "node": ">=12" } @@ -8961,7 +8945,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "dev": true, "dependencies": { "d3-path": "^3.1.0" }, @@ -8973,7 +8956,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "dev": true, "dependencies": { "d3-array": "2 - 3" }, @@ -8985,7 +8967,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "dev": true, "dependencies": { "d3-time": "1 - 3" }, @@ -8997,7 +8978,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "dev": true, "engines": { "node": ">=12" } @@ -9006,7 +8986,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "dev": true, "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", @@ -9025,7 +9004,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "dev": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -9041,7 +9019,6 @@ "version": "7.0.9", "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.9.tgz", "integrity": "sha512-rYR4QfVmy+sR44IBDvVtcAmOReGBvRCWDpO2QjYwqgh9yijw6eSHBqaPG/LIOEy7aBsniLvtMW6pg19qJhq60w==", - "dev": true, "dependencies": { "d3": "^7.8.2", "lodash-es": "^4.17.21" @@ -9171,8 +9148,7 @@ "node_modules/dayjs": { "version": "1.11.11", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", - "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==", - "dev": true + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" }, "node_modules/debug": { "version": "4.3.4", @@ -9387,7 +9363,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", - "dev": true, "dependencies": { "robust-predicates": "^3.0.2" } @@ -9401,6 +9376,11 @@ "node": ">=0.4.0" } }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -9602,8 +9582,7 @@ "node_modules/dompurify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz", - "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==", - "dev": true + "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==" }, "node_modules/domutils": { "version": "2.8.0", @@ -9723,8 +9702,7 @@ "node_modules/elkjs": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz", - "integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==", - "dev": true + "integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==" }, "node_modules/emittery": { "version": "0.10.2", @@ -9743,6 +9721,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/emoji-toolkit": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/emoji-toolkit/-/emoji-toolkit-6.6.0.tgz", + "integrity": "sha512-pEu0kow2p1N8zCKnn/L6H0F3rWUBB3P3hVjr/O5yl1fK7N9jU4vO4G7EFapC5Y3XwZLUCY0FZbOPyTkH+4V2eQ==" + }, "node_modules/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", @@ -12051,6 +12034,14 @@ "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", "dev": true }, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", + "dependencies": { + "delegate": "^3.1.2" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -12111,6 +12102,18 @@ "node": ">=12.0.0" } }, + "node_modules/hads/node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -12526,7 +12529,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -12821,7 +12823,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "dev": true, "engines": { "node": ">=12" } @@ -15587,6 +15588,29 @@ "source-map-support": "^0.5.5" } }, + "node_modules/katex": { + "version": "0.16.11", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", + "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -15599,8 +15623,7 @@ "node_modules/khroma": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", - "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", - "dev": true + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" }, "node_modules/kind-of": { "version": "6.0.3", @@ -15638,8 +15661,7 @@ "node_modules/layout-base": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", - "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", - "dev": true + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" }, "node_modules/lazy-ass": { "version": "1.6.0", @@ -15869,8 +15891,7 @@ "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "dev": true + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -16183,15 +16204,14 @@ } }, "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true, + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", "bin": { "marked": "bin/marked.js" }, "engines": { - "node": ">= 12" + "node": ">= 18" } }, "node_modules/material-design-icons-iconfont": { @@ -16356,7 +16376,6 @@ "version": "9.4.3", "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.4.3.tgz", "integrity": "sha512-TLkQEtqhRSuEHSE34lh5bCa94KATCyluAXmFnNI2PRZwOpXFeqiJWwZl+d2CcemE1RS6QbbueSSq9QIg8Uxcyw==", - "dev": true, "dependencies": { "@braintree/sanitize-url": "^6.0.0", "cytoscape": "^3.23.0", @@ -16380,7 +16399,6 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -16793,6 +16811,39 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/ngx-markdown": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-14.0.1.tgz", + "integrity": "sha512-y5CY4e0QM0uR6+MvU1rnh1Ks+rku14309kVVojyXLcWl4zlrt8VAYCcf/+A+8z/IDOaz38yTrxNBnvYDJzNzYA==", + "dependencies": { + "@types/marked": "^4.0.3", + "clipboard": "^2.0.11", + "emoji-toolkit": "^6.6.0", + "katex": "^0.16.0", + "marked": "^4.0.17", + "mermaid": "^9.1.2", + "prismjs": "^1.28.0", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^14.0.0", + "@angular/core": "^14.0.0", + "@angular/platform-browser": "^14.0.0", + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "^0.11.4" + } + }, + "node_modules/ngx-markdown/node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/nice-napi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", @@ -16916,8 +16967,7 @@ "node_modules/non-layered-tidy-tree-layout": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", - "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==", - "dev": true + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" }, "node_modules/nopt": { "version": "6.0.0", @@ -18934,6 +18984,14 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/proc-log": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", @@ -19818,8 +19876,7 @@ "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", - "dev": true + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, "node_modules/run-async": { "version": "2.4.1", @@ -19856,8 +19913,7 @@ "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "dev": true + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, "node_modules/rxjs": { "version": "7.8.1", @@ -19924,8 +19980,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { "version": "1.53.0", @@ -20050,6 +20105,11 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -21049,8 +21109,7 @@ "node_modules/stylis": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", - "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", - "dev": true + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==" }, "node_modules/stylus": { "version": "0.58.1", @@ -21628,6 +21687,11 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, "node_modules/tmp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", @@ -21737,7 +21801,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", - "dev": true, "engines": { "node": ">=6.10" } @@ -22408,8 +22471,7 @@ "node_modules/web-worker": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.3.0.tgz", - "integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==", - "dev": true + "integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==" }, "node_modules/webidl-conversions": { "version": "7.0.0", diff --git a/frontend/package.json b/frontend/package.json index 80b4eda0..ea9f7558 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -41,7 +41,9 @@ "@ngx-translate/core": "^14.0.0", "date-fns": "^2.29.2", "lodash": "^4.17.20", + "marked": "^12.0.2", "material-design-icons-iconfont": "^6.1.0", + "ngx-markdown": "^14.0.1", "rxjs": "^7.5.0", "tslib": "^2.3.0", "zone.js": "~0.11.4" diff --git a/frontend/src/app/@shared/services/llm.service.ts b/frontend/src/app/@shared/services/llm.service.ts new file mode 100644 index 00000000..2a0c9eb8 --- /dev/null +++ b/frontend/src/app/@shared/services/llm.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { environment } from '@env/environment'; + +export interface LLM { + id: string; + name: string; + isConfigured: boolean; +} + +@Injectable({ + providedIn: 'root', +}) +export class LlmService { + private apiUrl = `${environment.serverUrl}/api/llms`; + + constructor(private http: HttpClient) {} + + getLlms(): Observable { + return this.http.get(`${this.apiUrl}/list`); + } +} diff --git a/frontend/src/app/@shared/shared.module.ts b/frontend/src/app/@shared/shared.module.ts index 302e9884..cb54d4c4 100644 --- a/frontend/src/app/@shared/shared.module.ts +++ b/frontend/src/app/@shared/shared.module.ts @@ -6,10 +6,12 @@ import { ReactiveFormsModule, FormsModule } from '@angular/forms'; import { MaterialModule } from '@app/material.module'; import { LoaderComponent } from './loader/loader.component'; +import { LlmService } from '@app/shared/services/llm.service'; @NgModule({ imports: [FlexLayoutModule, MaterialModule, TranslateModule, CommonModule, ReactiveFormsModule, FormsModule], declarations: [LoaderComponent], exports: [LoaderComponent, ReactiveFormsModule, FormsModule], + providers: [LlmService], }) export class SharedModule {} diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 92669888..869ce876 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -1,7 +1,6 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule, PreloadAllModules } from '@angular/router'; import { Shell } from '@app/shell/shell.service'; -import { CodeReviewListComponent } from './code-review/code-review-list.component'; const routes: Routes = [ Shell.childRoutes([{ path: 'about', loadChildren: () => import('./about/about.module').then((m) => m.AboutModule) }]), @@ -17,11 +16,6 @@ const routes: Routes = [ ]), Shell.childRoutes([{ path: 'chat', loadChildren: () => import('./chat/chat.module').then((m) => m.ChatModule) }]), - Shell.childRoutes([{ path: 'chats', loadChildren: () => import('./chat/chat.module').then((m) => m.ChatModule) }]), - Shell.childRoutes([ - { path: 'chats/:id', loadChildren: () => import('./chat/chat.module').then((m) => m.ChatModule) }, - ]), - Shell.childRoutes([ { path: 'code-reviews', diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 80df1644..f9dd37fa 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -13,6 +13,7 @@ import { HomeModule } from './home/home.module'; import { ShellModule } from './shell/shell.module'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; +import { MarkdownModule } from 'ngx-markdown'; @NgModule({ imports: [ @@ -27,6 +28,7 @@ import { AppRoutingModule } from './app-routing.module'; ShellModule, HomeModule, AuthModule, + MarkdownModule.forRoot(), AppRoutingModule, // must be imported as the last module as it contains the fallback route ], declarations: [AppComponent], diff --git a/frontend/src/app/chat/chat-controls/chat-controls.component.html b/frontend/src/app/chat/chat-controls/chat-controls.component.html index ef41795e..588b22b1 100644 --- a/frontend/src/app/chat/chat-controls/chat-controls.component.html +++ b/frontend/src/app/chat/chat-controls/chat-controls.component.html @@ -1,13 +1,31 @@
- - - + + -
-
Attachments:
- - - + +
Attachments:
+ - insert_drive_file - {{ attachment.name }} - cancel -
-
- - + + insert_drive_file + {{ attachment.name }} + cancel + + +
diff --git a/frontend/src/app/chat/chat-controls/chat-controls.component.scss b/frontend/src/app/chat/chat-controls/chat-controls.component.scss index e69de29b..be68b840 100644 --- a/frontend/src/app/chat/chat-controls/chat-controls.component.scss +++ b/frontend/src/app/chat/chat-controls/chat-controls.component.scss @@ -0,0 +1,7 @@ +:host { + position: sticky; + bottom: 0; + background-color: #fff; + padding: 1rem 0; + z-index: 1; +} diff --git a/frontend/src/app/chat/chat-controls/chat-controls.component.ts b/frontend/src/app/chat/chat-controls/chat-controls.component.ts index 79a72e27..0b292335 100644 --- a/frontend/src/app/chat/chat-controls/chat-controls.component.ts +++ b/frontend/src/app/chat/chat-controls/chat-controls.component.ts @@ -1,9 +1,9 @@ -import { Component, Input, OnInit } from '@angular/core'; - -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; import { debounceTime, filter, throttleTime } from 'rxjs/operators'; -// import {FirebaseAttachmentService} from "@app/chat/services/firebase/firebase-attachment.service"; -import { FirebaseChatService } from '@app/chat/services/firebase/firebase-chat.service'; +import { ApiChatService } from '@app/chat/services/api/api-chat.service'; +import { LlmService } from '@app/shared/services/llm.service'; +import { LlmMessage } from '@app/chat/model/chat'; @Component({ selector: 'app-chat-controls', @@ -12,74 +12,101 @@ import { FirebaseChatService } from '@app/chat/services/firebase/firebase-chat.s }) export class ChatControlsComponent implements OnInit { @Input() chatId: string = ''; + @Output() messageSent = new EventEmitter(); - messageControl: FormControl; chatForm: FormGroup; + isSending: boolean = false; + llms: any[] = []; - constructor( - // private attachmentService: FirebaseAttachmentService, - private chatService: FirebaseChatService, - private fb: FormBuilder - ) { - this.messageControl = new FormControl(); - this.chatForm = this.fb.group({ message: this.messageControl }); + constructor(private chatService: ApiChatService, private llmService: LlmService, private fb: FormBuilder) { + this.chatForm = this.fb.group({ + message: [''], + selectedLlm: [''], + }); } ngOnInit() { this.scrollBottom(); + this.fetchLlms(); - this.messageControl.valueChanges - .pipe( - filter((data) => data !== ''), + this.chatForm + .get('message') + ?.valueChanges.pipe( + filter((data: string) => data !== ''), throttleTime(1400) ) - .subscribe((data) => { - // this.chatService.sendIsTyping(this.chatId).then(); + .subscribe(() => { + // Implement typing indicator if needed }); - this.messageControl.valueChanges - .pipe( - filter((data) => data !== ''), + this.chatForm + .get('message') + ?.valueChanges.pipe( + filter((data: string) => data !== ''), debounceTime(1500) ) - .subscribe((data) => { - // this.chatService.deleteIsTyping(this.chatId).then(); + .subscribe(() => { + // Implement typing indicator removal if needed }); } + private fetchLlms(): void { + this.llmService.getLlms().subscribe({ + next: (llms) => { + this.llms = llms; + if (this.llms.length > 0) { + this.chatForm.get('selectedLlm')?.setValue(this.llms[0].id); + } + }, + error: (error) => { + console.error('Error fetching LLMs:', error); + // Consider showing a user-friendly error message here + }, + }); + } + submit(): void { - const msg = this.messageControl.value; + const msg = this.chatForm.get('message')?.value; + const selectedLlmId = this.chatForm.get('selectedLlm')?.value; + if (!msg) { return alert('Please enter a message.'); } - this.chatService.sendMessage(this.chatId, msg).then(); - // this.attachmentService.uploadAttachments().subscribe( - // (res: any) => console.log(res), - // (err: any) => console.log(err) - // ); - this.messageControl.reset(); - this.scrollBottom(); + if (!selectedLlmId) { + return alert('Please select an LLM.'); + } + + this.isSending = true; + this.chatService.sendMessage(this.chatId, msg, selectedLlmId).subscribe({ + next: (data: string) => { + console.log(data); + this.isSending = false; + this.chatForm.get('message')?.reset(); + this.scrollBottom(); + this.messageSent.emit([ + { role: 'user', text: msg, index: -1 }, + { role: 'assistant', text: data, index: -1, llmId: selectedLlmId }, + ]); + }, + error: (err: Error) => { + console.error('Error sending message:', err); + this.isSending = false; + alert('Failed to send message. Please try again.'); + }, + }); } private scrollBottom(): void { setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 500); } - setSelectedFiles(event: any): void { - // this.attachmentService.setSelectedFiles(event); - } - - deleteAttachment(file: any): void { - // return this.attachmentService.deleteFile(file); - } - + // Attachment methods left as placeholders for future implementation + setSelectedFiles(event: Event): void {} + deleteAttachment(file: File): void {} getAttachments(): File[] { - // return this.attachmentService.getFiles(); return []; } - - hasAttachments() { - // return this.attachmentService.getFiles().length > 0; - false; + hasAttachments(): boolean { + return false; } } diff --git a/frontend/src/app/chat/chat-header/chat-header.component.html b/frontend/src/app/chat/chat-header/chat-header.component.html index d8abbf2b..39b193da 100644 --- a/frontend/src/app/chat/chat-header/chat-header.component.html +++ b/frontend/src/app/chat/chat-header/chat-header.component.html @@ -1,6 +1,6 @@ Asset Chat - {{ chatId }}Chat - {{ chatId }} diff --git a/frontend/src/app/chat/chat-list/chat-list.component.html b/frontend/src/app/chat/chat-list/chat-list.component.html new file mode 100644 index 00000000..155fe327 --- /dev/null +++ b/frontend/src/app/chat/chat-list/chat-list.component.html @@ -0,0 +1,30 @@ + + + Chats + + + + + + + +
+ +
+
{{ chat.title }}
+
+
+

No chats. Start one by clicking the plus icon above.

+
+ + +

{{ errorMessage }}

+
+
diff --git a/frontend/src/app/chat/chat-list/chat-list.component.scss b/frontend/src/app/chat/chat-list/chat-list.component.scss new file mode 100644 index 00000000..587a3b51 --- /dev/null +++ b/frontend/src/app/chat/chat-list/chat-list.component.scss @@ -0,0 +1,9 @@ +/* Styles for CodeReviewListComponent */ +[matListItemIcon] { + display: flex; + gap: 4px; /* Reduce the gap between buttons */ +} + +button[mat-icon-button] { + padding: 0; /* Remove default padding */ +} diff --git a/frontend/src/app/chat/chat-list/chat-list.component.ts b/frontend/src/app/chat/chat-list/chat-list.component.ts new file mode 100644 index 00000000..3ad50766 --- /dev/null +++ b/frontend/src/app/chat/chat-list/chat-list.component.ts @@ -0,0 +1,66 @@ +import { Component, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { Router } from '@angular/router'; + +import { MatDialogModule } from '@angular/material/dialog'; +import { ApiChatService } from '@app/chat/services/api/api-chat.service'; +import { ChatList } from '@app/chat/model/chat'; + +@Component({ + selector: 'app-code-chat-list', + templateUrl: './chat-list.component.html', + styleUrls: ['./chat-list.component.scss'], +}) +export class ChatListComponent implements OnInit { + chats: ChatList | null = null; + isLoading = false; + errorMessage = ''; + + constructor(private chatService: ApiChatService, private router: Router, private dialog: MatDialog) {} + + ngOnInit() { + this.loadChats(); + } + + loadChats() { + this.isLoading = true; + this.chatService.list().subscribe( + (chats) => { + console.log(chats); + this.chats = chats.data; + this.isLoading = false; + }, + (error: any) => { + console.log(error); + this.errorMessage = 'Error loading configurations'; + this.isLoading = false; + } + ); + } + + openChat(chatId?: string) { + this.router.navigate(['/chat', chatId]).catch(console.error); + } + + // confirmDelete(config: CodeReviewConfig) { + // const dialogRef = this.dialog.open(ConfirmDialogComponent, { + // width: '400px', + // data: { title: 'Confirm Deletion', message: `Are you sure you want to delete "${config.description}"?` }, + // }); + // + // dialogRef.afterClosed().subscribe((result) => { + // if (result) { + // this.deleteConfig(config.id); + // } + // }); + // } + // + // private deleteConfig(id: string) { + // this.codeReviewService.deleteCodeReviewConfig(id).subscribe( + // () => this.loadConfigs(), + // (error) => { + // this.errorMessage = 'Error deleting configuration'; + // } + // ); + // } +} diff --git a/frontend/src/app/chat/chat-message/chat-message.component.html b/frontend/src/app/chat/chat-message/chat-message.component.html index a41275fd..8e8d8495 100644 --- a/frontend/src/app/chat/chat-message/chat-message.component.html +++ b/frontend/src/app/chat/chat-message/chat-message.component.html @@ -1,67 +1,37 @@
- {{ getDateDivider(msg) }} - - - - - {{ getUserName(msg.user) }} - - - + -
- {{ getCreatedDate(msg) }} -
- {{ msg.content }} + + +