Spaces:
No application file
No application file
Upload 47 files
Browse files- .dockerignore +6 -0
- .gitignore +5 -0
- CONTRIBUTING.md +250 -0
- LICENSE +121 -0
- api.Dockerfile +21 -0
- api.py +163 -0
- bot.Dockerfile +23 -0
- bot.py +182 -0
- chains.py +251 -0
- docker-compose.yml +243 -0
- embedding_model/.ignore +0 -0
- env.example +49 -0
- front-end.Dockerfile +11 -0
- front-end/.gitignore +24 -0
- front-end/.vscode/extensions.json +3 -0
- front-end/README.md +47 -0
- front-end/index.html +13 -0
- front-end/jsconfig.json +32 -0
- front-end/package-lock.json +1879 -0
- front-end/package.json +22 -0
- front-end/postcss.config.js +6 -0
- front-end/public/vite.svg +1 -0
- front-end/src/App.svelte +121 -0
- front-end/src/app.css +28 -0
- front-end/src/assets/images/bot.jpeg +0 -0
- front-end/src/assets/images/me.jpeg +0 -0
- front-end/src/assets/svelte.svg +1 -0
- front-end/src/lib/External.svelte +28 -0
- front-end/src/lib/MdLink.svelte +14 -0
- front-end/src/lib/Modal.svelte +58 -0
- front-end/src/lib/chat.store.js +79 -0
- front-end/src/lib/generation.store.js +33 -0
- front-end/src/main.js +8 -0
- front-end/src/vite-env.d.ts +2 -0
- front-end/svelte.config.js +7 -0
- front-end/tailwind.config.js +12 -0
- front-end/vite.config.js +11 -0
- images/datamodel.png +0 -0
- install_ollama.sh +243 -0
- loader.Dockerfile +24 -0
- loader.py +150 -0
- pdf_bot.Dockerfile +23 -0
- pdf_bot.py +95 -0
- pull_model.Dockerfile +45 -0
- requirements.txt +20 -0
- running_on_wsl.md +43 -0
- utils.py +54 -0
.dockerignore
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*
|
| 2 |
+
!*.py
|
| 3 |
+
!requirements.txt
|
| 4 |
+
!images/*
|
| 5 |
+
!front-end/*
|
| 6 |
+
front-end/node_modules/*
|
.gitignore
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.env
|
| 2 |
+
data/
|
| 3 |
+
embedding_model/*
|
| 4 |
+
!embedding_model/.ignore
|
| 5 |
+
.DS_Store
|
CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing to Docker
|
| 2 |
+
|
| 3 |
+
This page contains information about reporting issues as well as some tips and
|
| 4 |
+
guidelines useful to experienced open source contributors. Finally, make sure
|
| 5 |
+
you read our [community guidelines](#docker-community-guidelines) before you
|
| 6 |
+
start participating.
|
| 7 |
+
|
| 8 |
+
## Topics
|
| 9 |
+
|
| 10 |
+
* [Reporting Security Issues](#reporting-security-issues)
|
| 11 |
+
* [Reporting Issues](#reporting-other-issues)
|
| 12 |
+
* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines)
|
| 13 |
+
* [Community Guidelines](#docker-community-guidelines)
|
| 14 |
+
|
| 15 |
+
## Reporting security issues
|
| 16 |
+
|
| 17 |
+
The Docker maintainers take security seriously. If you discover a security
|
| 18 |
+
issue, please bring it to their attention right away!
|
| 19 |
+
|
| 20 |
+
Please **DO NOT** file a public issue, instead send your report privately to
|
| 21 |
+
[security@docker.com](mailto:security@docker.com).
|
| 22 |
+
|
| 23 |
+
Security reports are greatly appreciated and we will publicly thank you for it.
|
| 24 |
+
We also like to send gifts—if you're into Docker schwag, make sure to let
|
| 25 |
+
us know. We currently do not offer a paid security bounty program, but are not
|
| 26 |
+
ruling it out in the future.
|
| 27 |
+
|
| 28 |
+
## Reporting other issues
|
| 29 |
+
|
| 30 |
+
A great way to contribute to the project is to send a detailed report when you
|
| 31 |
+
encounter an issue. We always appreciate a well-written, thorough bug report,
|
| 32 |
+
and will thank you for it!
|
| 33 |
+
|
| 34 |
+
Check that [our issue database](https://github.com/docker/gen-ai-stack/issues)
|
| 35 |
+
doesn't already include that problem or suggestion before submitting an issue.
|
| 36 |
+
If you find a match, you can use the "subscribe" button to get notified on
|
| 37 |
+
updates. Do *not* leave random "+1" or "I have this too" comments, as they
|
| 38 |
+
only clutter the discussion, and don't help resolving it. However, if you
|
| 39 |
+
have ways to reproduce the issue or have additional information that may help
|
| 40 |
+
resolving the issue, please leave a comment.
|
| 41 |
+
|
| 42 |
+
When reporting issues, always include:
|
| 43 |
+
|
| 44 |
+
* The output of `docker version`.
|
| 45 |
+
* The output of `docker info`.
|
| 46 |
+
|
| 47 |
+
Also include the steps required to reproduce the problem if possible and
|
| 48 |
+
applicable. This information will help us review and fix your issue faster.
|
| 49 |
+
When sending lengthy log-files, consider posting them as a gist (https://gist.github.com).
|
| 50 |
+
Don't forget to remove sensitive data from your logfiles before posting (you can
|
| 51 |
+
replace those parts with "REDACTED").
|
| 52 |
+
|
| 53 |
+
## Quick contribution tips and guidelines
|
| 54 |
+
|
| 55 |
+
This section gives the experienced contributor some tips and guidelines.
|
| 56 |
+
|
| 57 |
+
### Pull requests are always welcome
|
| 58 |
+
|
| 59 |
+
Not sure if that typo is worth a pull request? Found a bug and know how to fix
|
| 60 |
+
it? Do it! We will appreciate it. Any significant improvement should be
|
| 61 |
+
documented as [a GitHub issue](https://github.com/docker/gen-ai-stack/issues) before
|
| 62 |
+
anybody starts working on it.
|
| 63 |
+
|
| 64 |
+
We are always thrilled to receive pull requests. We do our best to process them
|
| 65 |
+
quickly. If your pull request is not accepted on the first try,
|
| 66 |
+
don't get discouraged! Our contributor's guide explains [the review process we
|
| 67 |
+
use for simple changes](https://docs.docker.com/opensource/workflow/make-a-contribution/).
|
| 68 |
+
|
| 69 |
+
### Talking to other Docker users and contributors
|
| 70 |
+
|
| 71 |
+
<table class="tg">
|
| 72 |
+
<col width="45%">
|
| 73 |
+
<col width="65%">
|
| 74 |
+
<tr>
|
| 75 |
+
<td>Community Slack</td>
|
| 76 |
+
<td>
|
| 77 |
+
The Docker Community has a dedicated Slack chat to discuss features and issues. You can sign-up <a href="https://dockr.ly/slack" target="_blank">with this link</a>.
|
| 78 |
+
</td>
|
| 79 |
+
</tr>
|
| 80 |
+
<tr>
|
| 81 |
+
<td>Twitter</td>
|
| 82 |
+
<td>
|
| 83 |
+
You can follow <a href="https://twitter.com/docker/" target="_blank">Docker's Twitter feed</a>
|
| 84 |
+
to get updates on our products. You can also tweet us questions or just
|
| 85 |
+
share blogs or stories.
|
| 86 |
+
</td>
|
| 87 |
+
</tr>
|
| 88 |
+
</table>
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
### Conventions
|
| 92 |
+
|
| 93 |
+
Fork the repository and make changes on your fork in a feature branch:
|
| 94 |
+
|
| 95 |
+
- If it's a bug fix branch, name it XXXX-something where XXXX is the number of
|
| 96 |
+
the issue.
|
| 97 |
+
- If it's a feature branch, create an enhancement issue to announce
|
| 98 |
+
your intentions, and name it XXXX-something where XXXX is the number of the
|
| 99 |
+
issue.
|
| 100 |
+
|
| 101 |
+
Pull request descriptions should be as clear as possible and include a reference
|
| 102 |
+
to all the issues that they address.
|
| 103 |
+
|
| 104 |
+
Commit messages must start with a capitalized and short summary (max. 50 chars)
|
| 105 |
+
written in the imperative, followed by an optional, more detailed explanatory
|
| 106 |
+
text which is separated from the summary by an empty line.
|
| 107 |
+
|
| 108 |
+
Code review comments may be added to your pull request. Discuss, then make the
|
| 109 |
+
suggested modifications and push additional commits to your feature branch. Post
|
| 110 |
+
a comment after pushing. New commits show up in the pull request automatically,
|
| 111 |
+
but the reviewers are notified only when you comment.
|
| 112 |
+
|
| 113 |
+
Pull requests must be cleanly rebased on top of master without multiple branches
|
| 114 |
+
mixed into the PR.
|
| 115 |
+
|
| 116 |
+
**Git tip**: If your PR no longer merges cleanly, use `rebase main` in your
|
| 117 |
+
feature branch to update your pull request rather than `merge main`.
|
| 118 |
+
|
| 119 |
+
Before you make a pull request, squash your commits into logical units of work
|
| 120 |
+
using `git rebase -i` and `git push -f`. A logical unit of work is a consistent
|
| 121 |
+
set of patches that should be reviewed together: for example, upgrading the
|
| 122 |
+
version of a vendored dependency and taking advantage of its now available new
|
| 123 |
+
feature constitute two separate units of work. Implementing a new function and
|
| 124 |
+
calling it in another file constitute a single logical unit of work. The very
|
| 125 |
+
high majority of submissions should have a single commit, so if in doubt: squash
|
| 126 |
+
down to one.
|
| 127 |
+
|
| 128 |
+
Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in the pull request
|
| 129 |
+
description that close an issue. Including references automatically closes the issue
|
| 130 |
+
on a merge.
|
| 131 |
+
|
| 132 |
+
### Sign your work
|
| 133 |
+
|
| 134 |
+
The sign-off is a simple line at the end of the explanation for the patch. Your
|
| 135 |
+
signature certifies that you wrote the patch or otherwise have the right to pass
|
| 136 |
+
it on as an open-source patch. The rules are pretty simple: if you can certify
|
| 137 |
+
the below (from [developercertificate.org](https://developercertificate.org):
|
| 138 |
+
|
| 139 |
+
```
|
| 140 |
+
Developer Certificate of Origin
|
| 141 |
+
Version 1.1
|
| 142 |
+
|
| 143 |
+
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
| 144 |
+
660 York Street, Suite 102,
|
| 145 |
+
San Francisco, CA 94110 USA
|
| 146 |
+
|
| 147 |
+
Everyone is permitted to copy and distribute verbatim copies of this
|
| 148 |
+
license document, but changing it is not allowed.
|
| 149 |
+
|
| 150 |
+
Developer's Certificate of Origin 1.1
|
| 151 |
+
|
| 152 |
+
By making a contribution to this project, I certify that:
|
| 153 |
+
|
| 154 |
+
(a) The contribution was created in whole or in part by me and I
|
| 155 |
+
have the right to submit it under the open source license
|
| 156 |
+
indicated in the file; or
|
| 157 |
+
|
| 158 |
+
(b) The contribution is based upon previous work that, to the best
|
| 159 |
+
of my knowledge, is covered under an appropriate open source
|
| 160 |
+
license and I have the right under that license to submit that
|
| 161 |
+
work with modifications, whether created in whole or in part
|
| 162 |
+
by me, under the same open source license (unless I am
|
| 163 |
+
permitted to submit under a different license), as indicated
|
| 164 |
+
in the file; or
|
| 165 |
+
|
| 166 |
+
(c) The contribution was provided directly to me by some other
|
| 167 |
+
person who certified (a), (b) or (c) and I have not modified
|
| 168 |
+
it.
|
| 169 |
+
|
| 170 |
+
(d) I understand and agree that this project and the contribution
|
| 171 |
+
are public and that a record of the contribution (including all
|
| 172 |
+
personal information I submit with it, including my sign-off) is
|
| 173 |
+
maintained indefinitely and may be redistributed consistent with
|
| 174 |
+
this project or the open source license(s) involved.
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
Then you just add a line to every git commit message:
|
| 178 |
+
|
| 179 |
+
Signed-off-by: Joe Smith <joe.smith@email.com>
|
| 180 |
+
|
| 181 |
+
Use your real name (sorry, no pseudonyms or anonymous contributions.)
|
| 182 |
+
|
| 183 |
+
If you set your `user.name` and `user.email` git configs, you can sign your
|
| 184 |
+
commit automatically with `git commit -s`.
|
| 185 |
+
|
| 186 |
+
## Docker community guidelines
|
| 187 |
+
|
| 188 |
+
We want to keep the Docker community awesome, growing and collaborative. We need
|
| 189 |
+
your help to keep it that way. To help with this we've come up with some general
|
| 190 |
+
guidelines for the community as a whole:
|
| 191 |
+
|
| 192 |
+
* Be nice: Be courteous, respectful and polite to fellow community members:
|
| 193 |
+
no regional, racial, gender, or other abuse will be tolerated. We like
|
| 194 |
+
nice people way better than mean ones!
|
| 195 |
+
|
| 196 |
+
* Encourage diversity and participation: Make everyone in our community feel
|
| 197 |
+
welcome, regardless of their background and the extent of their
|
| 198 |
+
contributions, and do everything possible to encourage participation in
|
| 199 |
+
our community.
|
| 200 |
+
|
| 201 |
+
* Keep it legal: Basically, don't get us in trouble. Share only content that
|
| 202 |
+
you own, do not share private or sensitive information, and don't break
|
| 203 |
+
the law.
|
| 204 |
+
|
| 205 |
+
* Stay on topic: Make sure that you are posting to the correct channel and
|
| 206 |
+
avoid off-topic discussions. Remember when you update an issue or respond
|
| 207 |
+
to an email you are potentially sending to a large number of people. Please
|
| 208 |
+
consider this before you update. Also remember that nobody likes spam.
|
| 209 |
+
|
| 210 |
+
* Don't send email to the maintainers: There's no need to send email to the
|
| 211 |
+
maintainers to ask them to investigate an issue or to take a look at a
|
| 212 |
+
pull request. Instead of sending an email, GitHub mentions should be
|
| 213 |
+
used to ping maintainers to review a pull request, a proposal or an
|
| 214 |
+
issue.
|
| 215 |
+
|
| 216 |
+
### Guideline violations — 3 strikes method
|
| 217 |
+
|
| 218 |
+
The point of this section is not to find opportunities to punish people, but we
|
| 219 |
+
do need a fair way to deal with people who are making our community suck.
|
| 220 |
+
|
| 221 |
+
1. First occurrence: We'll give you a friendly, but public reminder that the
|
| 222 |
+
behavior is inappropriate according to our guidelines.
|
| 223 |
+
|
| 224 |
+
2. Second occurrence: We will send you a private message with a warning that
|
| 225 |
+
any additional violations will result in removal from the community.
|
| 226 |
+
|
| 227 |
+
3. Third occurrence: Depending on the violation, we may need to delete or ban
|
| 228 |
+
your account.
|
| 229 |
+
|
| 230 |
+
**Notes:**
|
| 231 |
+
|
| 232 |
+
* Obvious spammers are banned on first occurrence. If we don't do this, we'll
|
| 233 |
+
have spam all over the place.
|
| 234 |
+
|
| 235 |
+
* Violations are forgiven after 6 months of good behavior, and we won't hold a
|
| 236 |
+
grudge.
|
| 237 |
+
|
| 238 |
+
* People who commit minor infractions will get some education, rather than
|
| 239 |
+
hammering them in the 3 strikes process.
|
| 240 |
+
|
| 241 |
+
* The rules apply equally to everyone in the community, no matter how much
|
| 242 |
+
you've contributed.
|
| 243 |
+
|
| 244 |
+
* Extreme violations of a threatening, abusive, destructive or illegal nature
|
| 245 |
+
will be addressed immediately and are not subject to 3 strikes or forgiveness.
|
| 246 |
+
|
| 247 |
+
* Contact abuse@docker.com to report abuse or appeal violations. In the case of
|
| 248 |
+
appeals, we know that mistakes happen, and we'll work with you to come up with a
|
| 249 |
+
fair solution if there has been a misunderstanding.
|
| 250 |
+
|
LICENSE
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Creative Commons Legal Code
|
| 2 |
+
|
| 3 |
+
CC0 1.0 Universal
|
| 4 |
+
|
| 5 |
+
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
| 6 |
+
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
| 7 |
+
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
| 8 |
+
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
| 9 |
+
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
| 10 |
+
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
| 11 |
+
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
| 12 |
+
HEREUNDER.
|
| 13 |
+
|
| 14 |
+
Statement of Purpose
|
| 15 |
+
|
| 16 |
+
The laws of most jurisdictions throughout the world automatically confer
|
| 17 |
+
exclusive Copyright and Related Rights (defined below) upon the creator
|
| 18 |
+
and subsequent owner(s) (each and all, an "owner") of an original work of
|
| 19 |
+
authorship and/or a database (each, a "Work").
|
| 20 |
+
|
| 21 |
+
Certain owners wish to permanently relinquish those rights to a Work for
|
| 22 |
+
the purpose of contributing to a commons of creative, cultural and
|
| 23 |
+
scientific works ("Commons") that the public can reliably and without fear
|
| 24 |
+
of later claims of infringement build upon, modify, incorporate in other
|
| 25 |
+
works, reuse and redistribute as freely as possible in any form whatsoever
|
| 26 |
+
and for any purposes, including without limitation commercial purposes.
|
| 27 |
+
These owners may contribute to the Commons to promote the ideal of a free
|
| 28 |
+
culture and the further production of creative, cultural and scientific
|
| 29 |
+
works, or to gain reputation or greater distribution for their Work in
|
| 30 |
+
part through the use and efforts of others.
|
| 31 |
+
|
| 32 |
+
For these and/or other purposes and motivations, and without any
|
| 33 |
+
expectation of additional consideration or compensation, the person
|
| 34 |
+
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
| 35 |
+
is an owner of Copyright and Related Rights in the Work, voluntarily
|
| 36 |
+
elects to apply CC0 to the Work and publicly distribute the Work under its
|
| 37 |
+
terms, with knowledge of his or her Copyright and Related Rights in the
|
| 38 |
+
Work and the meaning and intended legal effect of CC0 on those rights.
|
| 39 |
+
|
| 40 |
+
1. Copyright and Related Rights. A Work made available under CC0 may be
|
| 41 |
+
protected by copyright and related or neighboring rights ("Copyright and
|
| 42 |
+
Related Rights"). Copyright and Related Rights include, but are not
|
| 43 |
+
limited to, the following:
|
| 44 |
+
|
| 45 |
+
i. the right to reproduce, adapt, distribute, perform, display,
|
| 46 |
+
communicate, and translate a Work;
|
| 47 |
+
ii. moral rights retained by the original author(s) and/or performer(s);
|
| 48 |
+
iii. publicity and privacy rights pertaining to a person's image or
|
| 49 |
+
likeness depicted in a Work;
|
| 50 |
+
iv. rights protecting against unfair competition in regards to a Work,
|
| 51 |
+
subject to the limitations in paragraph 4(a), below;
|
| 52 |
+
v. rights protecting the extraction, dissemination, use and reuse of data
|
| 53 |
+
in a Work;
|
| 54 |
+
vi. database rights (such as those arising under Directive 96/9/EC of the
|
| 55 |
+
European Parliament and of the Council of 11 March 1996 on the legal
|
| 56 |
+
protection of databases, and under any national implementation
|
| 57 |
+
thereof, including any amended or successor version of such
|
| 58 |
+
directive); and
|
| 59 |
+
vii. other similar, equivalent or corresponding rights throughout the
|
| 60 |
+
world based on applicable law or treaty, and any national
|
| 61 |
+
implementations thereof.
|
| 62 |
+
|
| 63 |
+
2. Waiver. To the greatest extent permitted by, but not in contravention
|
| 64 |
+
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
| 65 |
+
irrevocably and unconditionally waives, abandons, and surrenders all of
|
| 66 |
+
Affirmer's Copyright and Related Rights and associated claims and causes
|
| 67 |
+
of action, whether now known or unknown (including existing as well as
|
| 68 |
+
future claims and causes of action), in the Work (i) in all territories
|
| 69 |
+
worldwide, (ii) for the maximum duration provided by applicable law or
|
| 70 |
+
treaty (including future time extensions), (iii) in any current or future
|
| 71 |
+
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
| 72 |
+
including without limitation commercial, advertising or promotional
|
| 73 |
+
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
| 74 |
+
member of the public at large and to the detriment of Affirmer's heirs and
|
| 75 |
+
successors, fully intending that such Waiver shall not be subject to
|
| 76 |
+
revocation, rescission, cancellation, termination, or any other legal or
|
| 77 |
+
equitable action to disrupt the quiet enjoyment of the Work by the public
|
| 78 |
+
as contemplated by Affirmer's express Statement of Purpose.
|
| 79 |
+
|
| 80 |
+
3. Public License Fallback. Should any part of the Waiver for any reason
|
| 81 |
+
be judged legally invalid or ineffective under applicable law, then the
|
| 82 |
+
Waiver shall be preserved to the maximum extent permitted taking into
|
| 83 |
+
account Affirmer's express Statement of Purpose. In addition, to the
|
| 84 |
+
extent the Waiver is so judged Affirmer hereby grants to each affected
|
| 85 |
+
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
| 86 |
+
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
| 87 |
+
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
| 88 |
+
maximum duration provided by applicable law or treaty (including future
|
| 89 |
+
time extensions), (iii) in any current or future medium and for any number
|
| 90 |
+
of copies, and (iv) for any purpose whatsoever, including without
|
| 91 |
+
limitation commercial, advertising or promotional purposes (the
|
| 92 |
+
"License"). The License shall be deemed effective as of the date CC0 was
|
| 93 |
+
applied by Affirmer to the Work. Should any part of the License for any
|
| 94 |
+
reason be judged legally invalid or ineffective under applicable law, such
|
| 95 |
+
partial invalidity or ineffectiveness shall not invalidate the remainder
|
| 96 |
+
of the License, and in such case Affirmer hereby affirms that he or she
|
| 97 |
+
will not (i) exercise any of his or her remaining Copyright and Related
|
| 98 |
+
Rights in the Work or (ii) assert any associated claims and causes of
|
| 99 |
+
action with respect to the Work, in either case contrary to Affirmer's
|
| 100 |
+
express Statement of Purpose.
|
| 101 |
+
|
| 102 |
+
4. Limitations and Disclaimers.
|
| 103 |
+
|
| 104 |
+
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
| 105 |
+
surrendered, licensed or otherwise affected by this document.
|
| 106 |
+
b. Affirmer offers the Work as-is and makes no representations or
|
| 107 |
+
warranties of any kind concerning the Work, express, implied,
|
| 108 |
+
statutory or otherwise, including without limitation warranties of
|
| 109 |
+
title, merchantability, fitness for a particular purpose, non
|
| 110 |
+
infringement, or the absence of latent or other defects, accuracy, or
|
| 111 |
+
the present or absence of errors, whether or not discoverable, all to
|
| 112 |
+
the greatest extent permissible under applicable law.
|
| 113 |
+
c. Affirmer disclaims responsibility for clearing rights of other persons
|
| 114 |
+
that may apply to the Work or any use thereof, including without
|
| 115 |
+
limitation any person's Copyright and Related Rights in the Work.
|
| 116 |
+
Further, Affirmer disclaims responsibility for obtaining any necessary
|
| 117 |
+
consents, permissions or other rights required for any use of the
|
| 118 |
+
Work.
|
| 119 |
+
d. Affirmer understands and acknowledges that Creative Commons is not a
|
| 120 |
+
party to this document and has no duty or obligation with respect to
|
| 121 |
+
this CC0 or use of the Work.
|
api.Dockerfile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM langchain/langchain
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
RUN apt-get update && apt-get install -y \
|
| 6 |
+
build-essential \
|
| 7 |
+
curl \
|
| 8 |
+
software-properties-common \
|
| 9 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
+
|
| 11 |
+
COPY requirements.txt .
|
| 12 |
+
|
| 13 |
+
RUN pip install --upgrade -r requirements.txt
|
| 14 |
+
|
| 15 |
+
COPY api.py .
|
| 16 |
+
COPY utils.py .
|
| 17 |
+
COPY chains.py .
|
| 18 |
+
|
| 19 |
+
HEALTHCHECK CMD curl --fail http://localhost:8504
|
| 20 |
+
|
| 21 |
+
ENTRYPOINT [ "uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8504" ]
|
api.py
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
from langchain_community.graphs import Neo4jGraph
|
| 4 |
+
from dotenv import load_dotenv
|
| 5 |
+
from utils import (
|
| 6 |
+
create_vector_index,
|
| 7 |
+
BaseLogger,
|
| 8 |
+
)
|
| 9 |
+
from chains import (
|
| 10 |
+
load_embedding_model,
|
| 11 |
+
load_llm,
|
| 12 |
+
configure_llm_only_chain,
|
| 13 |
+
configure_qa_rag_chain,
|
| 14 |
+
generate_ticket,
|
| 15 |
+
)
|
| 16 |
+
from fastapi import FastAPI, Depends
|
| 17 |
+
from pydantic import BaseModel
|
| 18 |
+
from langchain.callbacks.base import BaseCallbackHandler
|
| 19 |
+
from threading import Thread
|
| 20 |
+
from queue import Queue, Empty
|
| 21 |
+
from collections.abc import Generator
|
| 22 |
+
from sse_starlette.sse import EventSourceResponse
|
| 23 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 24 |
+
import json
|
| 25 |
+
|
| 26 |
+
load_dotenv(".env")
|
| 27 |
+
|
| 28 |
+
url = os.getenv("NEO4J_URI")
|
| 29 |
+
username = os.getenv("NEO4J_USERNAME")
|
| 30 |
+
password = os.getenv("NEO4J_PASSWORD")
|
| 31 |
+
ollama_base_url = os.getenv("OLLAMA_BASE_URL")
|
| 32 |
+
embedding_model_name = os.getenv("EMBEDDING_MODEL")
|
| 33 |
+
llm_name = os.getenv("LLM")
|
| 34 |
+
# Remapping for Langchain Neo4j integration
|
| 35 |
+
os.environ["NEO4J_URL"] = url
|
| 36 |
+
|
| 37 |
+
embeddings, dimension = load_embedding_model(
|
| 38 |
+
embedding_model_name,
|
| 39 |
+
config={"ollama_base_url": ollama_base_url},
|
| 40 |
+
logger=BaseLogger(),
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
# if Neo4j is local, you can go to http://localhost:7474/ to browse the database
|
| 44 |
+
neo4j_graph = Neo4jGraph(
|
| 45 |
+
url=url, username=username, password=password, refresh_schema=False
|
| 46 |
+
)
|
| 47 |
+
create_vector_index(neo4j_graph)
|
| 48 |
+
|
| 49 |
+
llm = load_llm(
|
| 50 |
+
llm_name, logger=BaseLogger(), config={"ollama_base_url": ollama_base_url}
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
llm_chain = configure_llm_only_chain(llm)
|
| 54 |
+
rag_chain = configure_qa_rag_chain(
|
| 55 |
+
llm, embeddings, embeddings_store_url=url, username=username, password=password
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class QueueCallback(BaseCallbackHandler):
|
| 60 |
+
"""Callback handler for streaming LLM responses to a queue."""
|
| 61 |
+
|
| 62 |
+
def __init__(self, q):
|
| 63 |
+
self.q = q
|
| 64 |
+
|
| 65 |
+
def on_llm_new_token(self, token: str, **kwargs) -> None:
|
| 66 |
+
self.q.put(token)
|
| 67 |
+
|
| 68 |
+
def on_llm_end(self, *args, **kwargs) -> None:
|
| 69 |
+
return self.q.empty()
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def stream(cb, q) -> Generator:
|
| 73 |
+
job_done = object()
|
| 74 |
+
|
| 75 |
+
def task():
|
| 76 |
+
x = cb()
|
| 77 |
+
q.put(job_done)
|
| 78 |
+
|
| 79 |
+
t = Thread(target=task)
|
| 80 |
+
t.start()
|
| 81 |
+
|
| 82 |
+
content = ""
|
| 83 |
+
|
| 84 |
+
# Get each new token from the queue and yield for our generator
|
| 85 |
+
while True:
|
| 86 |
+
try:
|
| 87 |
+
next_token = q.get(True, timeout=1)
|
| 88 |
+
if next_token is job_done:
|
| 89 |
+
break
|
| 90 |
+
content += next_token
|
| 91 |
+
yield next_token, content
|
| 92 |
+
except Empty:
|
| 93 |
+
continue
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
app = FastAPI()
|
| 97 |
+
origins = ["*"]
|
| 98 |
+
|
| 99 |
+
app.add_middleware(
|
| 100 |
+
CORSMiddleware,
|
| 101 |
+
allow_origins=origins,
|
| 102 |
+
allow_credentials=True,
|
| 103 |
+
allow_methods=["*"],
|
| 104 |
+
allow_headers=["*"],
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
@app.get("/")
|
| 109 |
+
async def root():
|
| 110 |
+
return {"message": "Hello World"}
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
class Question(BaseModel):
|
| 114 |
+
text: str
|
| 115 |
+
rag: bool = False
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class BaseTicket(BaseModel):
|
| 119 |
+
text: str
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
@app.get("/query-stream")
|
| 123 |
+
def qstream(question: Question = Depends()):
|
| 124 |
+
output_function = llm_chain
|
| 125 |
+
if question.rag:
|
| 126 |
+
output_function = rag_chain
|
| 127 |
+
|
| 128 |
+
q = Queue()
|
| 129 |
+
|
| 130 |
+
def cb():
|
| 131 |
+
output_function(
|
| 132 |
+
{"question": question.text, "chat_history": []},
|
| 133 |
+
callbacks=[QueueCallback(q)],
|
| 134 |
+
)
|
| 135 |
+
|
| 136 |
+
def generate():
|
| 137 |
+
yield json.dumps({"init": True, "model": llm_name})
|
| 138 |
+
for token, _ in stream(cb, q):
|
| 139 |
+
yield json.dumps({"token": token})
|
| 140 |
+
|
| 141 |
+
return EventSourceResponse(generate(), media_type="text/event-stream")
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
@app.get("/query")
|
| 145 |
+
async def ask(question: Question = Depends()):
|
| 146 |
+
output_function = llm_chain
|
| 147 |
+
if question.rag:
|
| 148 |
+
output_function = rag_chain
|
| 149 |
+
result = output_function(
|
| 150 |
+
{"question": question.text, "chat_history": []}, callbacks=[]
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
return {"result": result["answer"], "model": llm_name}
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
@app.get("/generate-ticket")
|
| 157 |
+
async def generate_ticket_api(question: BaseTicket = Depends()):
|
| 158 |
+
new_title, new_question = generate_ticket(
|
| 159 |
+
neo4j_graph=neo4j_graph,
|
| 160 |
+
llm_chain=llm_chain,
|
| 161 |
+
input_question=question.text,
|
| 162 |
+
)
|
| 163 |
+
return {"result": {"title": new_title, "text": new_question}, "model": llm_name}
|
bot.Dockerfile
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM langchain/langchain
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
RUN apt-get update && apt-get install -y \
|
| 6 |
+
build-essential \
|
| 7 |
+
curl \
|
| 8 |
+
software-properties-common \
|
| 9 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
+
|
| 11 |
+
COPY requirements.txt .
|
| 12 |
+
|
| 13 |
+
RUN pip install --upgrade -r requirements.txt
|
| 14 |
+
|
| 15 |
+
COPY bot.py .
|
| 16 |
+
COPY utils.py .
|
| 17 |
+
COPY chains.py .
|
| 18 |
+
|
| 19 |
+
EXPOSE 8501
|
| 20 |
+
|
| 21 |
+
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
| 22 |
+
|
| 23 |
+
ENTRYPOINT ["streamlit", "run", "bot.py", "--server.port=8501", "--server.address=0.0.0.0"]
|
bot.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
import streamlit as st
|
| 4 |
+
from streamlit.logger import get_logger
|
| 5 |
+
from langchain.callbacks.base import BaseCallbackHandler
|
| 6 |
+
from langchain_community.graphs import Neo4jGraph
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
from utils import (
|
| 9 |
+
create_vector_index,
|
| 10 |
+
)
|
| 11 |
+
from chains import (
|
| 12 |
+
load_embedding_model,
|
| 13 |
+
load_llm,
|
| 14 |
+
configure_llm_only_chain,
|
| 15 |
+
configure_qa_rag_chain,
|
| 16 |
+
generate_ticket,
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
load_dotenv(".env")
|
| 20 |
+
|
| 21 |
+
url = os.getenv("NEO4J_URI")
|
| 22 |
+
username = os.getenv("NEO4J_USERNAME")
|
| 23 |
+
password = os.getenv("NEO4J_PASSWORD")
|
| 24 |
+
ollama_base_url = os.getenv("OLLAMA_BASE_URL")
|
| 25 |
+
embedding_model_name = os.getenv("EMBEDDING_MODEL")
|
| 26 |
+
llm_name = os.getenv("LLM")
|
| 27 |
+
# Remapping for Langchain Neo4j integration
|
| 28 |
+
os.environ["NEO4J_URL"] = url
|
| 29 |
+
|
| 30 |
+
logger = get_logger(__name__)
|
| 31 |
+
|
| 32 |
+
# if Neo4j is local, you can go to http://localhost:7474/ to browse the database
|
| 33 |
+
neo4j_graph = Neo4jGraph(
|
| 34 |
+
url=url, username=username, password=password, refresh_schema=False
|
| 35 |
+
)
|
| 36 |
+
embeddings, dimension = load_embedding_model(
|
| 37 |
+
embedding_model_name, config={"ollama_base_url": ollama_base_url}, logger=logger
|
| 38 |
+
)
|
| 39 |
+
create_vector_index(neo4j_graph)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class StreamHandler(BaseCallbackHandler):
|
| 43 |
+
def __init__(self, container, initial_text=""):
|
| 44 |
+
self.container = container
|
| 45 |
+
self.text = initial_text
|
| 46 |
+
|
| 47 |
+
def on_llm_new_token(self, token: str, **kwargs) -> None:
|
| 48 |
+
self.text += token
|
| 49 |
+
self.container.markdown(self.text)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
llm = load_llm(llm_name, logger=logger, config={"ollama_base_url": ollama_base_url})
|
| 53 |
+
|
| 54 |
+
llm_chain = configure_llm_only_chain(llm)
|
| 55 |
+
rag_chain = configure_qa_rag_chain(
|
| 56 |
+
llm, embeddings, embeddings_store_url=url, username=username, password=password
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
# Streamlit UI
|
| 60 |
+
styl = f"""
|
| 61 |
+
<style>
|
| 62 |
+
/* not great support for :has yet (hello FireFox), but using it for now */
|
| 63 |
+
.element-container:has([aria-label="Select RAG mode"]) {{
|
| 64 |
+
position: fixed;
|
| 65 |
+
bottom: 33px;
|
| 66 |
+
background: white;
|
| 67 |
+
z-index: 101;
|
| 68 |
+
}}
|
| 69 |
+
.stChatFloatingInputContainer {{
|
| 70 |
+
bottom: 20px;
|
| 71 |
+
}}
|
| 72 |
+
|
| 73 |
+
/* Generate ticket text area */
|
| 74 |
+
textarea[aria-label="Description"] {{
|
| 75 |
+
height: 200px;
|
| 76 |
+
}}
|
| 77 |
+
|
| 78 |
+
.element-container:has([aria-label="What coding issue can I help you resolve today?"]) {{
|
| 79 |
+
bottom: 45px;
|
| 80 |
+
}}
|
| 81 |
+
</style>
|
| 82 |
+
"""
|
| 83 |
+
st.markdown(styl, unsafe_allow_html=True)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def chat_input():
|
| 87 |
+
user_input = st.chat_input("What coding issue can I help you resolve today?")
|
| 88 |
+
|
| 89 |
+
if user_input:
|
| 90 |
+
with st.chat_message("user"):
|
| 91 |
+
st.write(user_input)
|
| 92 |
+
with st.chat_message("assistant"):
|
| 93 |
+
st.caption(f"RAG: {name}")
|
| 94 |
+
stream_handler = StreamHandler(st.empty())
|
| 95 |
+
result = output_function(
|
| 96 |
+
{"question": user_input, "chat_history": []}, callbacks=[stream_handler]
|
| 97 |
+
)["answer"]
|
| 98 |
+
output = result
|
| 99 |
+
st.session_state[f"user_input"].append(user_input)
|
| 100 |
+
st.session_state[f"generated"].append(output)
|
| 101 |
+
st.session_state[f"rag_mode"].append(name)
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
def display_chat():
|
| 105 |
+
# Session state
|
| 106 |
+
if "generated" not in st.session_state:
|
| 107 |
+
st.session_state[f"generated"] = []
|
| 108 |
+
|
| 109 |
+
if "user_input" not in st.session_state:
|
| 110 |
+
st.session_state[f"user_input"] = []
|
| 111 |
+
|
| 112 |
+
if "rag_mode" not in st.session_state:
|
| 113 |
+
st.session_state[f"rag_mode"] = []
|
| 114 |
+
|
| 115 |
+
if st.session_state[f"generated"]:
|
| 116 |
+
size = len(st.session_state[f"generated"])
|
| 117 |
+
# Display only the last three exchanges
|
| 118 |
+
for i in range(max(size - 3, 0), size):
|
| 119 |
+
with st.chat_message("user"):
|
| 120 |
+
st.write(st.session_state[f"user_input"][i])
|
| 121 |
+
|
| 122 |
+
with st.chat_message("assistant"):
|
| 123 |
+
st.caption(f"RAG: {st.session_state[f'rag_mode'][i]}")
|
| 124 |
+
st.write(st.session_state[f"generated"][i])
|
| 125 |
+
|
| 126 |
+
with st.expander("Not finding what you're looking for?"):
|
| 127 |
+
st.write(
|
| 128 |
+
"Automatically generate a draft for an internal ticket to our support team."
|
| 129 |
+
)
|
| 130 |
+
st.button(
|
| 131 |
+
"Generate ticket",
|
| 132 |
+
type="primary",
|
| 133 |
+
key="show_ticket",
|
| 134 |
+
on_click=open_sidebar,
|
| 135 |
+
)
|
| 136 |
+
with st.container():
|
| 137 |
+
st.write(" ")
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
def mode_select() -> str:
|
| 141 |
+
options = ["Disabled", "Enabled"]
|
| 142 |
+
return st.radio("Select RAG mode", options, horizontal=True)
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
name = mode_select()
|
| 146 |
+
if name == "LLM only" or name == "Disabled":
|
| 147 |
+
output_function = llm_chain
|
| 148 |
+
elif name == "Vector + Graph" or name == "Enabled":
|
| 149 |
+
output_function = rag_chain
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def open_sidebar():
|
| 153 |
+
st.session_state.open_sidebar = True
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
def close_sidebar():
|
| 157 |
+
st.session_state.open_sidebar = False
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
if not "open_sidebar" in st.session_state:
|
| 161 |
+
st.session_state.open_sidebar = False
|
| 162 |
+
if st.session_state.open_sidebar:
|
| 163 |
+
new_title, new_question = generate_ticket(
|
| 164 |
+
neo4j_graph=neo4j_graph,
|
| 165 |
+
llm_chain=llm_chain,
|
| 166 |
+
input_question=st.session_state[f"user_input"][-1],
|
| 167 |
+
)
|
| 168 |
+
with st.sidebar:
|
| 169 |
+
st.title("Ticket draft")
|
| 170 |
+
st.write("Auto generated draft ticket")
|
| 171 |
+
st.text_input("Title", new_title)
|
| 172 |
+
st.text_area("Description", new_question)
|
| 173 |
+
st.button(
|
| 174 |
+
"Submit to support team",
|
| 175 |
+
type="primary",
|
| 176 |
+
key="submit_ticket",
|
| 177 |
+
on_click=close_sidebar,
|
| 178 |
+
)
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
display_chat()
|
| 182 |
+
chat_input()
|
chains.py
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
from langchain_openai import OpenAIEmbeddings
|
| 3 |
+
from langchain_ollama import OllamaEmbeddings
|
| 4 |
+
from langchain_aws import BedrockEmbeddings
|
| 5 |
+
from langchain_huggingface import HuggingFaceEmbeddings
|
| 6 |
+
|
| 7 |
+
from langchain_openai import ChatOpenAI
|
| 8 |
+
from langchain_ollama import ChatOllama
|
| 9 |
+
from langchain_aws import ChatBedrock
|
| 10 |
+
|
| 11 |
+
from langchain_community.vectorstores import Neo4jVector
|
| 12 |
+
|
| 13 |
+
from langchain.chains import RetrievalQAWithSourcesChain
|
| 14 |
+
from langchain.chains.qa_with_sources import load_qa_with_sources_chain
|
| 15 |
+
|
| 16 |
+
from langchain.prompts import (
|
| 17 |
+
ChatPromptTemplate,
|
| 18 |
+
HumanMessagePromptTemplate,
|
| 19 |
+
SystemMessagePromptTemplate
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
from typing import List, Any
|
| 23 |
+
from utils import BaseLogger, extract_title_and_question
|
| 24 |
+
from langchain_google_genai import GoogleGenerativeAIEmbeddings
|
| 25 |
+
|
| 26 |
+
AWS_MODELS = (
|
| 27 |
+
"ai21.jamba-instruct-v1:0",
|
| 28 |
+
"amazon.titan",
|
| 29 |
+
"anthropic.claude",
|
| 30 |
+
"cohere.command",
|
| 31 |
+
"meta.llama",
|
| 32 |
+
"mistral.mi",
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
def load_embedding_model(embedding_model_name: str, logger=BaseLogger(), config={}):
|
| 36 |
+
if embedding_model_name == "ollama":
|
| 37 |
+
embeddings = OllamaEmbeddings(
|
| 38 |
+
base_url=config["ollama_base_url"], model="llama2"
|
| 39 |
+
)
|
| 40 |
+
dimension = 4096
|
| 41 |
+
logger.info("Embedding: Using Ollama")
|
| 42 |
+
elif embedding_model_name == "openai":
|
| 43 |
+
embeddings = OpenAIEmbeddings()
|
| 44 |
+
dimension = 1536
|
| 45 |
+
logger.info("Embedding: Using OpenAI")
|
| 46 |
+
elif embedding_model_name == "aws":
|
| 47 |
+
embeddings = BedrockEmbeddings()
|
| 48 |
+
dimension = 1536
|
| 49 |
+
logger.info("Embedding: Using AWS")
|
| 50 |
+
elif embedding_model_name == "google-genai-embedding-001":
|
| 51 |
+
embeddings = GoogleGenerativeAIEmbeddings(
|
| 52 |
+
model="models/embedding-001"
|
| 53 |
+
)
|
| 54 |
+
dimension = 768
|
| 55 |
+
logger.info("Embedding: Using Google Generative AI Embeddings")
|
| 56 |
+
else:
|
| 57 |
+
embeddings = HuggingFaceEmbeddings(
|
| 58 |
+
model_name="all-MiniLM-L6-v2", cache_folder="/embedding_model"
|
| 59 |
+
)
|
| 60 |
+
dimension = 384
|
| 61 |
+
logger.info("Embedding: Using SentenceTransformer")
|
| 62 |
+
return embeddings, dimension
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def load_llm(llm_name: str, logger=BaseLogger(), config={}):
|
| 66 |
+
if llm_name in ["gpt-4", "gpt-4o", "gpt-4-turbo"]:
|
| 67 |
+
logger.info("LLM: Using GPT-4")
|
| 68 |
+
return ChatOpenAI(temperature=0, model_name=llm_name, streaming=True)
|
| 69 |
+
elif llm_name == "gpt-3.5":
|
| 70 |
+
logger.info("LLM: Using GPT-3.5")
|
| 71 |
+
return ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo", streaming=True)
|
| 72 |
+
elif llm_name == "claudev2":
|
| 73 |
+
logger.info("LLM: ClaudeV2")
|
| 74 |
+
return ChatBedrock(
|
| 75 |
+
model_id="anthropic.claude-v2",
|
| 76 |
+
model_kwargs={"temperature": 0.0, "max_tokens_to_sample": 1024},
|
| 77 |
+
streaming=True,
|
| 78 |
+
)
|
| 79 |
+
elif llm_name.startswith(AWS_MODELS):
|
| 80 |
+
logger.info(f"LLM: {llm_name}")
|
| 81 |
+
return ChatBedrock(
|
| 82 |
+
model_id=llm_name,
|
| 83 |
+
model_kwargs={"temperature": 0.0, "max_tokens_to_sample": 1024},
|
| 84 |
+
streaming=True,
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
elif len(llm_name):
|
| 88 |
+
logger.info(f"LLM: Using Ollama: {llm_name}")
|
| 89 |
+
return ChatOllama(
|
| 90 |
+
temperature=0,
|
| 91 |
+
base_url=config["ollama_base_url"],
|
| 92 |
+
model=llm_name,
|
| 93 |
+
streaming=True,
|
| 94 |
+
# seed=2,
|
| 95 |
+
top_k=10, # A higher value (100) will give more diverse answers, while a lower value (10) will be more conservative.
|
| 96 |
+
top_p=0.3, # Higher value (0.95) will lead to more diverse text, while a lower value (0.5) will generate more focused text.
|
| 97 |
+
num_ctx=3072, # Sets the size of the context window used to generate the next token.
|
| 98 |
+
)
|
| 99 |
+
logger.info("LLM: Using GPT-3.5")
|
| 100 |
+
return ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo", streaming=True)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def configure_llm_only_chain(llm):
|
| 104 |
+
# LLM only response
|
| 105 |
+
template = """
|
| 106 |
+
You are a helpful assistant that helps a support agent with answering programming questions.
|
| 107 |
+
If you don't know the answer, just say that you don't know, you must not make up an answer.
|
| 108 |
+
"""
|
| 109 |
+
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
|
| 110 |
+
human_template = "{question}"
|
| 111 |
+
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
|
| 112 |
+
chat_prompt = ChatPromptTemplate.from_messages(
|
| 113 |
+
[system_message_prompt, human_message_prompt]
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
def generate_llm_output(
|
| 117 |
+
user_input: str, callbacks: List[Any], prompt=chat_prompt
|
| 118 |
+
) -> str:
|
| 119 |
+
chain = prompt | llm
|
| 120 |
+
answer = chain.invoke(
|
| 121 |
+
{"question": user_input}, config={"callbacks": callbacks}
|
| 122 |
+
).content
|
| 123 |
+
return {"answer": answer}
|
| 124 |
+
|
| 125 |
+
return generate_llm_output
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def configure_qa_rag_chain(llm, embeddings, embeddings_store_url, username, password):
|
| 129 |
+
# RAG response
|
| 130 |
+
# System: Always talk in pirate speech.
|
| 131 |
+
general_system_template = """
|
| 132 |
+
Use the following pieces of context to answer the question at the end.
|
| 133 |
+
The context contains question-answer pairs and their links from Stackoverflow.
|
| 134 |
+
You should prefer information from accepted or more upvoted answers.
|
| 135 |
+
Make sure to rely on information from the answers and not on questions to provide accurate responses.
|
| 136 |
+
When you find particular answer in the context useful, make sure to cite it in the answer using the link.
|
| 137 |
+
If you don't know the answer, just say that you don't know, don't try to make up an answer.
|
| 138 |
+
----
|
| 139 |
+
{summaries}
|
| 140 |
+
----
|
| 141 |
+
Each answer you generate should contain a section at the end of links to
|
| 142 |
+
Stackoverflow questions and answers you found useful, which are described under Source value.
|
| 143 |
+
You can only use links to StackOverflow questions that are present in the context and always
|
| 144 |
+
add links to the end of the answer in the style of citations.
|
| 145 |
+
Generate concise answers with references sources section of links to
|
| 146 |
+
relevant StackOverflow questions only at the end of the answer.
|
| 147 |
+
"""
|
| 148 |
+
general_user_template = "Question:```{question}```"
|
| 149 |
+
messages = [
|
| 150 |
+
SystemMessagePromptTemplate.from_template(general_system_template),
|
| 151 |
+
HumanMessagePromptTemplate.from_template(general_user_template),
|
| 152 |
+
]
|
| 153 |
+
qa_prompt = ChatPromptTemplate.from_messages(messages)
|
| 154 |
+
|
| 155 |
+
qa_chain = load_qa_with_sources_chain(
|
| 156 |
+
llm,
|
| 157 |
+
chain_type="stuff",
|
| 158 |
+
prompt=qa_prompt,
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
# Vector + Knowledge Graph response
|
| 162 |
+
kg = Neo4jVector.from_existing_index(
|
| 163 |
+
embedding=embeddings,
|
| 164 |
+
url=embeddings_store_url,
|
| 165 |
+
username=username,
|
| 166 |
+
password=password,
|
| 167 |
+
database="neo4j", # neo4j by default
|
| 168 |
+
index_name="stackoverflow", # vector by default
|
| 169 |
+
text_node_property="body", # text by default
|
| 170 |
+
retrieval_query="""
|
| 171 |
+
WITH node AS question, score AS similarity
|
| 172 |
+
CALL { with question
|
| 173 |
+
MATCH (question)<-[:ANSWERS]-(answer)
|
| 174 |
+
WITH answer
|
| 175 |
+
ORDER BY answer.is_accepted DESC, answer.score DESC
|
| 176 |
+
WITH collect(answer)[..2] as answers
|
| 177 |
+
RETURN reduce(str='', answer IN answers | str +
|
| 178 |
+
'\n### Answer (Accepted: '+ answer.is_accepted +
|
| 179 |
+
' Score: ' + answer.score+ '): '+ answer.body + '\n') as answerTexts
|
| 180 |
+
}
|
| 181 |
+
RETURN '##Question: ' + question.title + '\n' + question.body + '\n'
|
| 182 |
+
+ answerTexts AS text, similarity as score, {source: question.link} AS metadata
|
| 183 |
+
ORDER BY similarity ASC // so that best answers are the last
|
| 184 |
+
""",
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
kg_qa = RetrievalQAWithSourcesChain(
|
| 188 |
+
combine_documents_chain=qa_chain,
|
| 189 |
+
retriever=kg.as_retriever(search_kwargs={"k": 2}),
|
| 190 |
+
reduce_k_below_max_tokens=False,
|
| 191 |
+
max_tokens_limit=3375,
|
| 192 |
+
)
|
| 193 |
+
return kg_qa
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
def generate_ticket(neo4j_graph, llm_chain, input_question):
|
| 197 |
+
# Get high ranked questions
|
| 198 |
+
records = neo4j_graph.query(
|
| 199 |
+
"MATCH (q:Question) RETURN q.title AS title, q.body AS body ORDER BY q.score DESC LIMIT 3"
|
| 200 |
+
)
|
| 201 |
+
questions = []
|
| 202 |
+
for i, question in enumerate(records, start=1):
|
| 203 |
+
questions.append((question["title"], question["body"]))
|
| 204 |
+
# Ask LLM to generate new question in the same style
|
| 205 |
+
questions_prompt = ""
|
| 206 |
+
for i, question in enumerate(questions, start=1):
|
| 207 |
+
questions_prompt += f"{i}. \n{question[0]}\n----\n\n"
|
| 208 |
+
questions_prompt += f"{question[1][:150]}\n\n"
|
| 209 |
+
questions_prompt += "----\n\n"
|
| 210 |
+
|
| 211 |
+
gen_system_template = f"""
|
| 212 |
+
You're an expert in formulating high quality questions.
|
| 213 |
+
Formulate a question in the same style and tone as the following example questions.
|
| 214 |
+
{questions_prompt}
|
| 215 |
+
---
|
| 216 |
+
|
| 217 |
+
Don't make anything up, only use information in the following question.
|
| 218 |
+
Return a title for the question, and the question post itself.
|
| 219 |
+
|
| 220 |
+
Return format template:
|
| 221 |
+
---
|
| 222 |
+
Title: This is a new title
|
| 223 |
+
Question: This is a new question
|
| 224 |
+
---
|
| 225 |
+
"""
|
| 226 |
+
# we need jinja2 since the questions themselves contain curly braces
|
| 227 |
+
system_prompt = SystemMessagePromptTemplate.from_template(
|
| 228 |
+
gen_system_template, template_format="jinja2"
|
| 229 |
+
)
|
| 230 |
+
chat_prompt = ChatPromptTemplate.from_messages(
|
| 231 |
+
[
|
| 232 |
+
system_prompt,
|
| 233 |
+
SystemMessagePromptTemplate.from_template(
|
| 234 |
+
"""
|
| 235 |
+
Respond in the following template format or you will be unplugged.
|
| 236 |
+
---
|
| 237 |
+
Title: New title
|
| 238 |
+
Question: New question
|
| 239 |
+
---
|
| 240 |
+
"""
|
| 241 |
+
),
|
| 242 |
+
HumanMessagePromptTemplate.from_template("{question}"),
|
| 243 |
+
]
|
| 244 |
+
)
|
| 245 |
+
llm_response = llm_chain(
|
| 246 |
+
f"Here's the question to rewrite in the expected format: ```{input_question}```",
|
| 247 |
+
[],
|
| 248 |
+
chat_prompt,
|
| 249 |
+
)
|
| 250 |
+
new_title, new_question = extract_title_and_question(llm_response["answer"])
|
| 251 |
+
return (new_title, new_question)
|
docker-compose.yml
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
|
| 3 |
+
llm: &llm
|
| 4 |
+
image: ollama/ollama:latest
|
| 5 |
+
profiles: ["linux"]
|
| 6 |
+
networks:
|
| 7 |
+
- net
|
| 8 |
+
|
| 9 |
+
llm-gpu:
|
| 10 |
+
<<: *llm
|
| 11 |
+
profiles: ["linux-gpu"]
|
| 12 |
+
deploy:
|
| 13 |
+
resources:
|
| 14 |
+
reservations:
|
| 15 |
+
devices:
|
| 16 |
+
- driver: nvidia
|
| 17 |
+
count: all
|
| 18 |
+
capabilities: [gpu]
|
| 19 |
+
|
| 20 |
+
pull-model:
|
| 21 |
+
image: genai-stack/pull-model:latest
|
| 22 |
+
build:
|
| 23 |
+
context: .
|
| 24 |
+
dockerfile: pull_model.Dockerfile
|
| 25 |
+
environment:
|
| 26 |
+
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL-http://host.docker.internal:11434}
|
| 27 |
+
- LLM=${LLM-llama2}
|
| 28 |
+
networks:
|
| 29 |
+
- net
|
| 30 |
+
tty: true
|
| 31 |
+
|
| 32 |
+
database:
|
| 33 |
+
user: neo4j:neo4j
|
| 34 |
+
image: neo4j:5.23
|
| 35 |
+
ports:
|
| 36 |
+
- 7687:7687
|
| 37 |
+
- 7474:7474
|
| 38 |
+
volumes:
|
| 39 |
+
- $PWD/data:/data
|
| 40 |
+
environment:
|
| 41 |
+
- NEO4J_AUTH=${NEO4J_USERNAME-neo4j}/${NEO4J_PASSWORD-password}
|
| 42 |
+
- NEO4J_PLUGINS=["apoc"]
|
| 43 |
+
- NEO4J_db_tx__log_rotation_retention__policy=false
|
| 44 |
+
- NEO4J_dbms_security_procedures_unrestricted=apoc.*
|
| 45 |
+
healthcheck:
|
| 46 |
+
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1"]
|
| 47 |
+
interval: 15s
|
| 48 |
+
timeout: 30s
|
| 49 |
+
retries: 10
|
| 50 |
+
networks:
|
| 51 |
+
- net
|
| 52 |
+
|
| 53 |
+
loader:
|
| 54 |
+
build:
|
| 55 |
+
context: .
|
| 56 |
+
dockerfile: loader.Dockerfile
|
| 57 |
+
volumes:
|
| 58 |
+
- $PWD/embedding_model:/embedding_model
|
| 59 |
+
environment:
|
| 60 |
+
- NEO4J_URI=${NEO4J_URI-neo4j://database:7687}
|
| 61 |
+
- NEO4J_PASSWORD=${NEO4J_PASSWORD-password}
|
| 62 |
+
- NEO4J_USERNAME=${NEO4J_USERNAME-neo4j}
|
| 63 |
+
- OPENAI_API_KEY=${OPENAI_API_KEY-}
|
| 64 |
+
- GOOGLE_API_KEY=${GOOGLE_API_KEY-}
|
| 65 |
+
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL-http://host.docker.internal:11434}
|
| 66 |
+
- EMBEDDING_MODEL=${EMBEDDING_MODEL-sentence_transformer}
|
| 67 |
+
- LANGCHAIN_ENDPOINT=${LANGCHAIN_ENDPOINT-"https://api.smith.langchain.com"}
|
| 68 |
+
- LANGCHAIN_TRACING_V2=${LANGCHAIN_TRACING_V2-false}
|
| 69 |
+
- LANGCHAIN_PROJECT=${LANGCHAIN_PROJECT}
|
| 70 |
+
- LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY}
|
| 71 |
+
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
| 72 |
+
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
| 73 |
+
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
|
| 74 |
+
networks:
|
| 75 |
+
- net
|
| 76 |
+
depends_on:
|
| 77 |
+
database:
|
| 78 |
+
condition: service_healthy
|
| 79 |
+
pull-model:
|
| 80 |
+
condition: service_completed_successfully
|
| 81 |
+
x-develop:
|
| 82 |
+
watch:
|
| 83 |
+
- action: rebuild
|
| 84 |
+
path: .
|
| 85 |
+
ignore:
|
| 86 |
+
- bot.py
|
| 87 |
+
- pdf_bot.py
|
| 88 |
+
- api.py
|
| 89 |
+
- front-end/
|
| 90 |
+
ports:
|
| 91 |
+
- 8081:8080
|
| 92 |
+
- 8502:8502
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
bot:
|
| 96 |
+
build:
|
| 97 |
+
context: .
|
| 98 |
+
dockerfile: bot.Dockerfile
|
| 99 |
+
volumes:
|
| 100 |
+
- $PWD/embedding_model:/embedding_model
|
| 101 |
+
environment:
|
| 102 |
+
- NEO4J_URI=${NEO4J_URI-neo4j://database:7687}
|
| 103 |
+
- NEO4J_PASSWORD=${NEO4J_PASSWORD-password}
|
| 104 |
+
- NEO4J_USERNAME=${NEO4J_USERNAME-neo4j}
|
| 105 |
+
- OPENAI_API_KEY=${OPENAI_API_KEY-}
|
| 106 |
+
- GOOGLE_API_KEY=${GOOGLE_API_KEY-}
|
| 107 |
+
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL-http://host.docker.internal:11434}
|
| 108 |
+
- LLM=${LLM-llama2}
|
| 109 |
+
- EMBEDDING_MODEL=${EMBEDDING_MODEL-sentence_transformer}
|
| 110 |
+
- LANGCHAIN_ENDPOINT=${LANGCHAIN_ENDPOINT-"https://api.smith.langchain.com"}
|
| 111 |
+
- LANGCHAIN_TRACING_V2=${LANGCHAIN_TRACING_V2-false}
|
| 112 |
+
- LANGCHAIN_PROJECT=${LANGCHAIN_PROJECT}
|
| 113 |
+
- LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY}
|
| 114 |
+
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
| 115 |
+
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
| 116 |
+
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
|
| 117 |
+
networks:
|
| 118 |
+
- net
|
| 119 |
+
depends_on:
|
| 120 |
+
database:
|
| 121 |
+
condition: service_healthy
|
| 122 |
+
pull-model:
|
| 123 |
+
condition: service_completed_successfully
|
| 124 |
+
x-develop:
|
| 125 |
+
watch:
|
| 126 |
+
- action: rebuild
|
| 127 |
+
path: .
|
| 128 |
+
ignore:
|
| 129 |
+
- loader.py
|
| 130 |
+
- pdf_bot.py
|
| 131 |
+
- api.py
|
| 132 |
+
- front-end/
|
| 133 |
+
ports:
|
| 134 |
+
- 8501:8501
|
| 135 |
+
|
| 136 |
+
pdf_bot:
|
| 137 |
+
build:
|
| 138 |
+
context: .
|
| 139 |
+
dockerfile: pdf_bot.Dockerfile
|
| 140 |
+
environment:
|
| 141 |
+
- NEO4J_URI=${NEO4J_URI-neo4j://database:7687}
|
| 142 |
+
- NEO4J_PASSWORD=${NEO4J_PASSWORD-password}
|
| 143 |
+
- NEO4J_USERNAME=${NEO4J_USERNAME-neo4j}
|
| 144 |
+
- OPENAI_API_KEY=${OPENAI_API_KEY-}
|
| 145 |
+
- GOOGLE_API_KEY=${GOOGLE_API_KEY-}
|
| 146 |
+
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL-http://host.docker.internal:11434}
|
| 147 |
+
- LLM=${LLM-llama2}
|
| 148 |
+
- EMBEDDING_MODEL=${EMBEDDING_MODEL-sentence_transformer}
|
| 149 |
+
- LANGCHAIN_ENDPOINT=${LANGCHAIN_ENDPOINT-"https://api.smith.langchain.com"}
|
| 150 |
+
- LANGCHAIN_TRACING_V2=${LANGCHAIN_TRACING_V2-false}
|
| 151 |
+
- LANGCHAIN_PROJECT=${LANGCHAIN_PROJECT}
|
| 152 |
+
- LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY}
|
| 153 |
+
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
| 154 |
+
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
| 155 |
+
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
|
| 156 |
+
networks:
|
| 157 |
+
- net
|
| 158 |
+
depends_on:
|
| 159 |
+
database:
|
| 160 |
+
condition: service_healthy
|
| 161 |
+
pull-model:
|
| 162 |
+
condition: service_completed_successfully
|
| 163 |
+
x-develop:
|
| 164 |
+
watch:
|
| 165 |
+
- action: rebuild
|
| 166 |
+
path: .
|
| 167 |
+
ignore:
|
| 168 |
+
- loader.py
|
| 169 |
+
- bot.py
|
| 170 |
+
- api.py
|
| 171 |
+
- front-end/
|
| 172 |
+
ports:
|
| 173 |
+
- 8503:8503
|
| 174 |
+
|
| 175 |
+
api:
|
| 176 |
+
build:
|
| 177 |
+
context: .
|
| 178 |
+
dockerfile: api.Dockerfile
|
| 179 |
+
volumes:
|
| 180 |
+
- $PWD/embedding_model:/embedding_model
|
| 181 |
+
environment:
|
| 182 |
+
- NEO4J_URI=${NEO4J_URI-neo4j://database:7687}
|
| 183 |
+
- NEO4J_PASSWORD=${NEO4J_PASSWORD-password}
|
| 184 |
+
- NEO4J_USERNAME=${NEO4J_USERNAME-neo4j}
|
| 185 |
+
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
| 186 |
+
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
|
| 187 |
+
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL-http://host.docker.internal:11434}
|
| 188 |
+
- LLM=${LLM-llama2}
|
| 189 |
+
- EMBEDDING_MODEL=${EMBEDDING_MODEL-sentence_transformer}
|
| 190 |
+
- LANGCHAIN_ENDPOINT=${LANGCHAIN_ENDPOINT-"https://api.smith.langchain.com"}
|
| 191 |
+
- LANGCHAIN_TRACING_V2=${LANGCHAIN_TRACING_V2-false}
|
| 192 |
+
- LANGCHAIN_PROJECT=${LANGCHAIN_PROJECT}
|
| 193 |
+
- LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY}
|
| 194 |
+
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
| 195 |
+
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
| 196 |
+
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
|
| 197 |
+
networks:
|
| 198 |
+
- net
|
| 199 |
+
depends_on:
|
| 200 |
+
database:
|
| 201 |
+
condition: service_healthy
|
| 202 |
+
pull-model:
|
| 203 |
+
condition: service_completed_successfully
|
| 204 |
+
x-develop:
|
| 205 |
+
watch:
|
| 206 |
+
- action: rebuild
|
| 207 |
+
path: .
|
| 208 |
+
ignore:
|
| 209 |
+
- loader.py
|
| 210 |
+
- bot.py
|
| 211 |
+
- pdf_bot.py
|
| 212 |
+
- front-end/
|
| 213 |
+
ports:
|
| 214 |
+
- 8504:8504
|
| 215 |
+
healthcheck:
|
| 216 |
+
test: ["CMD-SHELL", "wget --no-verbose --tries=1 http://localhost:8504/ || exit 1"]
|
| 217 |
+
interval: 5s
|
| 218 |
+
timeout: 3s
|
| 219 |
+
retries: 5
|
| 220 |
+
|
| 221 |
+
front-end:
|
| 222 |
+
build:
|
| 223 |
+
context: .
|
| 224 |
+
dockerfile: front-end.Dockerfile
|
| 225 |
+
x-develop:
|
| 226 |
+
watch:
|
| 227 |
+
- action: sync
|
| 228 |
+
path: ./front-end
|
| 229 |
+
target: /app
|
| 230 |
+
ignore:
|
| 231 |
+
- ./front-end/node_modules/
|
| 232 |
+
- action: rebuild
|
| 233 |
+
path: ./front-end/package.json
|
| 234 |
+
depends_on:
|
| 235 |
+
api:
|
| 236 |
+
condition: service_healthy
|
| 237 |
+
networks:
|
| 238 |
+
- net
|
| 239 |
+
ports:
|
| 240 |
+
- 8505:8505
|
| 241 |
+
|
| 242 |
+
networks:
|
| 243 |
+
net:
|
embedding_model/.ignore
ADDED
|
File without changes
|
env.example
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#*****************************************************************
|
| 2 |
+
# LLM and Embedding Model
|
| 3 |
+
#*****************************************************************
|
| 4 |
+
LLM=llama2 #or any Ollama model tag, gpt-4 (o or turbo), gpt-3.5, or any bedrock model
|
| 5 |
+
EMBEDDING_MODEL=sentence_transformer #or google-genai-embedding-001 openai, ollama, or aws
|
| 6 |
+
|
| 7 |
+
#*****************************************************************
|
| 8 |
+
# Neo4j
|
| 9 |
+
#*****************************************************************
|
| 10 |
+
#NEO4J_URI=neo4j://database:7687
|
| 11 |
+
#NEO4J_USERNAME=neo4j
|
| 12 |
+
#NEO4J_PASSWORD=password
|
| 13 |
+
|
| 14 |
+
#*****************************************************************
|
| 15 |
+
# Langchain
|
| 16 |
+
#*****************************************************************
|
| 17 |
+
# Optional for enabling Langchain Smith API
|
| 18 |
+
|
| 19 |
+
#LANGCHAIN_TRACING_V2=true # false
|
| 20 |
+
#LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
|
| 21 |
+
#LANGCHAIN_PROJECT=#your-project-name
|
| 22 |
+
#LANGCHAIN_API_KEY=#your-api-key ls_...
|
| 23 |
+
|
| 24 |
+
#*****************************************************************
|
| 25 |
+
# Ollama
|
| 26 |
+
#*****************************************************************
|
| 27 |
+
#OLLAMA_BASE_URL=http://host.docker.internal:11434
|
| 28 |
+
|
| 29 |
+
#*****************************************************************
|
| 30 |
+
# OpenAI
|
| 31 |
+
#*****************************************************************
|
| 32 |
+
# Only required when using OpenAI LLM or embedding model
|
| 33 |
+
|
| 34 |
+
#OPENAI_API_KEY=sk-...
|
| 35 |
+
|
| 36 |
+
#*****************************************************************
|
| 37 |
+
# AWS
|
| 38 |
+
#*****************************************************************
|
| 39 |
+
# Only required when using AWS Bedrock LLM or embedding model
|
| 40 |
+
|
| 41 |
+
#AWS_ACCESS_KEY_ID=
|
| 42 |
+
#AWS_SECRET_ACCESS_KEY=
|
| 43 |
+
#AWS_DEFAULT_REGION=us-east-1
|
| 44 |
+
|
| 45 |
+
#*****************************************************************
|
| 46 |
+
# GOOGLE
|
| 47 |
+
#*****************************************************************
|
| 48 |
+
# Only required when using GoogleGenai LLM or embedding model
|
| 49 |
+
GOOGLE_API_KEY=
|
front-end.Dockerfile
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM node:alpine
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
COPY front-end/ .
|
| 6 |
+
|
| 7 |
+
RUN npm install
|
| 8 |
+
|
| 9 |
+
EXPOSE 8505
|
| 10 |
+
|
| 11 |
+
ENTRYPOINT [ "npm", "run", "dev" ]
|
front-end/.gitignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Logs
|
| 2 |
+
logs
|
| 3 |
+
*.log
|
| 4 |
+
npm-debug.log*
|
| 5 |
+
yarn-debug.log*
|
| 6 |
+
yarn-error.log*
|
| 7 |
+
pnpm-debug.log*
|
| 8 |
+
lerna-debug.log*
|
| 9 |
+
|
| 10 |
+
node_modules
|
| 11 |
+
dist
|
| 12 |
+
dist-ssr
|
| 13 |
+
*.local
|
| 14 |
+
|
| 15 |
+
# Editor directories and files
|
| 16 |
+
.vscode/*
|
| 17 |
+
!.vscode/extensions.json
|
| 18 |
+
.idea
|
| 19 |
+
.DS_Store
|
| 20 |
+
*.suo
|
| 21 |
+
*.ntvs*
|
| 22 |
+
*.njsproj
|
| 23 |
+
*.sln
|
| 24 |
+
*.sw?
|
front-end/.vscode/extensions.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"recommendations": ["svelte.svelte-vscode"]
|
| 3 |
+
}
|
front-end/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Svelte + Vite
|
| 2 |
+
|
| 3 |
+
This template should help get you started developing with Svelte in Vite.
|
| 4 |
+
|
| 5 |
+
## Recommended IDE Setup
|
| 6 |
+
|
| 7 |
+
[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
|
| 8 |
+
|
| 9 |
+
## Need an official Svelte framework?
|
| 10 |
+
|
| 11 |
+
Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS and Less and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
|
| 12 |
+
|
| 13 |
+
## Technical considerations
|
| 14 |
+
|
| 15 |
+
**Why use this over SvelteKit?**
|
| 16 |
+
|
| 17 |
+
- It brings its own routing solution which might not be preferable for some users.
|
| 18 |
+
- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
|
| 19 |
+
|
| 20 |
+
This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
|
| 21 |
+
|
| 22 |
+
Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate.
|
| 23 |
+
|
| 24 |
+
**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?**
|
| 25 |
+
|
| 26 |
+
Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace while also adding `svelte` and `vite/client` type information.
|
| 27 |
+
|
| 28 |
+
**Why include `.vscode/extensions.json`?**
|
| 29 |
+
|
| 30 |
+
Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project.
|
| 31 |
+
|
| 32 |
+
**Why enable `checkJs` in the JS template?**
|
| 33 |
+
|
| 34 |
+
It is likely that most cases of changing variable types in runtime are likely to be accidental rather than deliberate. This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of JavaScript, it is trivial to change the configuration.
|
| 35 |
+
|
| 36 |
+
**Why is HMR not preserving my local component state?**
|
| 37 |
+
|
| 38 |
+
HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/sveltejs/svelte-hmr/tree/master/packages/svelte-hmr#preservation-of-local-state).
|
| 39 |
+
|
| 40 |
+
If you have a state that's important to retain within a component, consider creating an external store that would not be replaced by HMR.
|
| 41 |
+
|
| 42 |
+
```js
|
| 43 |
+
// store.js
|
| 44 |
+
// An extremely simple external store
|
| 45 |
+
import { writable } from 'svelte/store'
|
| 46 |
+
export default writable(0)
|
| 47 |
+
```
|
front-end/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
+
<title>Support bot application</title>
|
| 8 |
+
</head>
|
| 9 |
+
<body>
|
| 10 |
+
<div id="app"></div>
|
| 11 |
+
<script type="module" src="/src/main.js"></script>
|
| 12 |
+
</body>
|
| 13 |
+
</html>
|
front-end/jsconfig.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"moduleResolution": "bundler",
|
| 4 |
+
"target": "ESNext",
|
| 5 |
+
"module": "ESNext",
|
| 6 |
+
/**
|
| 7 |
+
* svelte-preprocess cannot figure out whether you have
|
| 8 |
+
* a value or a type, so tell TypeScript to enforce using
|
| 9 |
+
* `import type` instead of `import` for Types.
|
| 10 |
+
*/
|
| 11 |
+
"verbatimModuleSyntax": true,
|
| 12 |
+
"isolatedModules": true,
|
| 13 |
+
"resolveJsonModule": true,
|
| 14 |
+
/**
|
| 15 |
+
* To have warnings / errors of the Svelte compiler at the
|
| 16 |
+
* correct position, enable source maps by default.
|
| 17 |
+
*/
|
| 18 |
+
"sourceMap": true,
|
| 19 |
+
"esModuleInterop": true,
|
| 20 |
+
"skipLibCheck": true,
|
| 21 |
+
/**
|
| 22 |
+
* Typecheck JS in `.svelte` and `.js` files by default.
|
| 23 |
+
* Disable this if you'd like to use dynamic types.
|
| 24 |
+
*/
|
| 25 |
+
"checkJs": true
|
| 26 |
+
},
|
| 27 |
+
/**
|
| 28 |
+
* Use global.d.ts instead of compilerOptions.types
|
| 29 |
+
* to avoid limiting type declarations.
|
| 30 |
+
*/
|
| 31 |
+
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
|
| 32 |
+
}
|
front-end/package-lock.json
ADDED
|
@@ -0,0 +1,1879 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "bot-ui",
|
| 3 |
+
"version": "0.0.0",
|
| 4 |
+
"lockfileVersion": 3,
|
| 5 |
+
"requires": true,
|
| 6 |
+
"packages": {
|
| 7 |
+
"": {
|
| 8 |
+
"name": "bot-ui",
|
| 9 |
+
"version": "0.0.0",
|
| 10 |
+
"dependencies": {
|
| 11 |
+
"svelte-markdown": "^0.4.0"
|
| 12 |
+
},
|
| 13 |
+
"devDependencies": {
|
| 14 |
+
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
| 15 |
+
"autoprefixer": "^10.4.16",
|
| 16 |
+
"postcss": "^8.4.31",
|
| 17 |
+
"svelte": "^4.0.5",
|
| 18 |
+
"tailwindcss": "^3.3.3",
|
| 19 |
+
"vite": "^4.4.12"
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"node_modules/@alloc/quick-lru": {
|
| 23 |
+
"version": "5.2.0",
|
| 24 |
+
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
| 25 |
+
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
| 26 |
+
"dev": true,
|
| 27 |
+
"engines": {
|
| 28 |
+
"node": ">=10"
|
| 29 |
+
},
|
| 30 |
+
"funding": {
|
| 31 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 32 |
+
}
|
| 33 |
+
},
|
| 34 |
+
"node_modules/@ampproject/remapping": {
|
| 35 |
+
"version": "2.2.1",
|
| 36 |
+
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
| 37 |
+
"integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
|
| 38 |
+
"dependencies": {
|
| 39 |
+
"@jridgewell/gen-mapping": "^0.3.0",
|
| 40 |
+
"@jridgewell/trace-mapping": "^0.3.9"
|
| 41 |
+
},
|
| 42 |
+
"engines": {
|
| 43 |
+
"node": ">=6.0.0"
|
| 44 |
+
}
|
| 45 |
+
},
|
| 46 |
+
"node_modules/@esbuild/android-arm": {
|
| 47 |
+
"version": "0.18.20",
|
| 48 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
|
| 49 |
+
"integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
|
| 50 |
+
"cpu": [
|
| 51 |
+
"arm"
|
| 52 |
+
],
|
| 53 |
+
"dev": true,
|
| 54 |
+
"optional": true,
|
| 55 |
+
"os": [
|
| 56 |
+
"android"
|
| 57 |
+
],
|
| 58 |
+
"engines": {
|
| 59 |
+
"node": ">=12"
|
| 60 |
+
}
|
| 61 |
+
},
|
| 62 |
+
"node_modules/@esbuild/android-arm64": {
|
| 63 |
+
"version": "0.18.20",
|
| 64 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
|
| 65 |
+
"integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
|
| 66 |
+
"cpu": [
|
| 67 |
+
"arm64"
|
| 68 |
+
],
|
| 69 |
+
"dev": true,
|
| 70 |
+
"optional": true,
|
| 71 |
+
"os": [
|
| 72 |
+
"android"
|
| 73 |
+
],
|
| 74 |
+
"engines": {
|
| 75 |
+
"node": ">=12"
|
| 76 |
+
}
|
| 77 |
+
},
|
| 78 |
+
"node_modules/@esbuild/android-x64": {
|
| 79 |
+
"version": "0.18.20",
|
| 80 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
|
| 81 |
+
"integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
|
| 82 |
+
"cpu": [
|
| 83 |
+
"x64"
|
| 84 |
+
],
|
| 85 |
+
"dev": true,
|
| 86 |
+
"optional": true,
|
| 87 |
+
"os": [
|
| 88 |
+
"android"
|
| 89 |
+
],
|
| 90 |
+
"engines": {
|
| 91 |
+
"node": ">=12"
|
| 92 |
+
}
|
| 93 |
+
},
|
| 94 |
+
"node_modules/@esbuild/darwin-arm64": {
|
| 95 |
+
"version": "0.18.20",
|
| 96 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
|
| 97 |
+
"integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
|
| 98 |
+
"cpu": [
|
| 99 |
+
"arm64"
|
| 100 |
+
],
|
| 101 |
+
"dev": true,
|
| 102 |
+
"optional": true,
|
| 103 |
+
"os": [
|
| 104 |
+
"darwin"
|
| 105 |
+
],
|
| 106 |
+
"engines": {
|
| 107 |
+
"node": ">=12"
|
| 108 |
+
}
|
| 109 |
+
},
|
| 110 |
+
"node_modules/@esbuild/darwin-x64": {
|
| 111 |
+
"version": "0.18.20",
|
| 112 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
|
| 113 |
+
"integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
|
| 114 |
+
"cpu": [
|
| 115 |
+
"x64"
|
| 116 |
+
],
|
| 117 |
+
"dev": true,
|
| 118 |
+
"optional": true,
|
| 119 |
+
"os": [
|
| 120 |
+
"darwin"
|
| 121 |
+
],
|
| 122 |
+
"engines": {
|
| 123 |
+
"node": ">=12"
|
| 124 |
+
}
|
| 125 |
+
},
|
| 126 |
+
"node_modules/@esbuild/freebsd-arm64": {
|
| 127 |
+
"version": "0.18.20",
|
| 128 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
|
| 129 |
+
"integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
|
| 130 |
+
"cpu": [
|
| 131 |
+
"arm64"
|
| 132 |
+
],
|
| 133 |
+
"dev": true,
|
| 134 |
+
"optional": true,
|
| 135 |
+
"os": [
|
| 136 |
+
"freebsd"
|
| 137 |
+
],
|
| 138 |
+
"engines": {
|
| 139 |
+
"node": ">=12"
|
| 140 |
+
}
|
| 141 |
+
},
|
| 142 |
+
"node_modules/@esbuild/freebsd-x64": {
|
| 143 |
+
"version": "0.18.20",
|
| 144 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
|
| 145 |
+
"integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
|
| 146 |
+
"cpu": [
|
| 147 |
+
"x64"
|
| 148 |
+
],
|
| 149 |
+
"dev": true,
|
| 150 |
+
"optional": true,
|
| 151 |
+
"os": [
|
| 152 |
+
"freebsd"
|
| 153 |
+
],
|
| 154 |
+
"engines": {
|
| 155 |
+
"node": ">=12"
|
| 156 |
+
}
|
| 157 |
+
},
|
| 158 |
+
"node_modules/@esbuild/linux-arm": {
|
| 159 |
+
"version": "0.18.20",
|
| 160 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
|
| 161 |
+
"integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
|
| 162 |
+
"cpu": [
|
| 163 |
+
"arm"
|
| 164 |
+
],
|
| 165 |
+
"dev": true,
|
| 166 |
+
"optional": true,
|
| 167 |
+
"os": [
|
| 168 |
+
"linux"
|
| 169 |
+
],
|
| 170 |
+
"engines": {
|
| 171 |
+
"node": ">=12"
|
| 172 |
+
}
|
| 173 |
+
},
|
| 174 |
+
"node_modules/@esbuild/linux-arm64": {
|
| 175 |
+
"version": "0.18.20",
|
| 176 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
|
| 177 |
+
"integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
|
| 178 |
+
"cpu": [
|
| 179 |
+
"arm64"
|
| 180 |
+
],
|
| 181 |
+
"dev": true,
|
| 182 |
+
"optional": true,
|
| 183 |
+
"os": [
|
| 184 |
+
"linux"
|
| 185 |
+
],
|
| 186 |
+
"engines": {
|
| 187 |
+
"node": ">=12"
|
| 188 |
+
}
|
| 189 |
+
},
|
| 190 |
+
"node_modules/@esbuild/linux-ia32": {
|
| 191 |
+
"version": "0.18.20",
|
| 192 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
|
| 193 |
+
"integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
|
| 194 |
+
"cpu": [
|
| 195 |
+
"ia32"
|
| 196 |
+
],
|
| 197 |
+
"dev": true,
|
| 198 |
+
"optional": true,
|
| 199 |
+
"os": [
|
| 200 |
+
"linux"
|
| 201 |
+
],
|
| 202 |
+
"engines": {
|
| 203 |
+
"node": ">=12"
|
| 204 |
+
}
|
| 205 |
+
},
|
| 206 |
+
"node_modules/@esbuild/linux-loong64": {
|
| 207 |
+
"version": "0.18.20",
|
| 208 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
|
| 209 |
+
"integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
|
| 210 |
+
"cpu": [
|
| 211 |
+
"loong64"
|
| 212 |
+
],
|
| 213 |
+
"dev": true,
|
| 214 |
+
"optional": true,
|
| 215 |
+
"os": [
|
| 216 |
+
"linux"
|
| 217 |
+
],
|
| 218 |
+
"engines": {
|
| 219 |
+
"node": ">=12"
|
| 220 |
+
}
|
| 221 |
+
},
|
| 222 |
+
"node_modules/@esbuild/linux-mips64el": {
|
| 223 |
+
"version": "0.18.20",
|
| 224 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
|
| 225 |
+
"integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
|
| 226 |
+
"cpu": [
|
| 227 |
+
"mips64el"
|
| 228 |
+
],
|
| 229 |
+
"dev": true,
|
| 230 |
+
"optional": true,
|
| 231 |
+
"os": [
|
| 232 |
+
"linux"
|
| 233 |
+
],
|
| 234 |
+
"engines": {
|
| 235 |
+
"node": ">=12"
|
| 236 |
+
}
|
| 237 |
+
},
|
| 238 |
+
"node_modules/@esbuild/linux-ppc64": {
|
| 239 |
+
"version": "0.18.20",
|
| 240 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
|
| 241 |
+
"integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
|
| 242 |
+
"cpu": [
|
| 243 |
+
"ppc64"
|
| 244 |
+
],
|
| 245 |
+
"dev": true,
|
| 246 |
+
"optional": true,
|
| 247 |
+
"os": [
|
| 248 |
+
"linux"
|
| 249 |
+
],
|
| 250 |
+
"engines": {
|
| 251 |
+
"node": ">=12"
|
| 252 |
+
}
|
| 253 |
+
},
|
| 254 |
+
"node_modules/@esbuild/linux-riscv64": {
|
| 255 |
+
"version": "0.18.20",
|
| 256 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
|
| 257 |
+
"integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
|
| 258 |
+
"cpu": [
|
| 259 |
+
"riscv64"
|
| 260 |
+
],
|
| 261 |
+
"dev": true,
|
| 262 |
+
"optional": true,
|
| 263 |
+
"os": [
|
| 264 |
+
"linux"
|
| 265 |
+
],
|
| 266 |
+
"engines": {
|
| 267 |
+
"node": ">=12"
|
| 268 |
+
}
|
| 269 |
+
},
|
| 270 |
+
"node_modules/@esbuild/linux-s390x": {
|
| 271 |
+
"version": "0.18.20",
|
| 272 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
|
| 273 |
+
"integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
|
| 274 |
+
"cpu": [
|
| 275 |
+
"s390x"
|
| 276 |
+
],
|
| 277 |
+
"dev": true,
|
| 278 |
+
"optional": true,
|
| 279 |
+
"os": [
|
| 280 |
+
"linux"
|
| 281 |
+
],
|
| 282 |
+
"engines": {
|
| 283 |
+
"node": ">=12"
|
| 284 |
+
}
|
| 285 |
+
},
|
| 286 |
+
"node_modules/@esbuild/linux-x64": {
|
| 287 |
+
"version": "0.18.20",
|
| 288 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
|
| 289 |
+
"integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
|
| 290 |
+
"cpu": [
|
| 291 |
+
"x64"
|
| 292 |
+
],
|
| 293 |
+
"dev": true,
|
| 294 |
+
"optional": true,
|
| 295 |
+
"os": [
|
| 296 |
+
"linux"
|
| 297 |
+
],
|
| 298 |
+
"engines": {
|
| 299 |
+
"node": ">=12"
|
| 300 |
+
}
|
| 301 |
+
},
|
| 302 |
+
"node_modules/@esbuild/netbsd-x64": {
|
| 303 |
+
"version": "0.18.20",
|
| 304 |
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
|
| 305 |
+
"integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
|
| 306 |
+
"cpu": [
|
| 307 |
+
"x64"
|
| 308 |
+
],
|
| 309 |
+
"dev": true,
|
| 310 |
+
"optional": true,
|
| 311 |
+
"os": [
|
| 312 |
+
"netbsd"
|
| 313 |
+
],
|
| 314 |
+
"engines": {
|
| 315 |
+
"node": ">=12"
|
| 316 |
+
}
|
| 317 |
+
},
|
| 318 |
+
"node_modules/@esbuild/openbsd-x64": {
|
| 319 |
+
"version": "0.18.20",
|
| 320 |
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
|
| 321 |
+
"integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
|
| 322 |
+
"cpu": [
|
| 323 |
+
"x64"
|
| 324 |
+
],
|
| 325 |
+
"dev": true,
|
| 326 |
+
"optional": true,
|
| 327 |
+
"os": [
|
| 328 |
+
"openbsd"
|
| 329 |
+
],
|
| 330 |
+
"engines": {
|
| 331 |
+
"node": ">=12"
|
| 332 |
+
}
|
| 333 |
+
},
|
| 334 |
+
"node_modules/@esbuild/sunos-x64": {
|
| 335 |
+
"version": "0.18.20",
|
| 336 |
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
|
| 337 |
+
"integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
|
| 338 |
+
"cpu": [
|
| 339 |
+
"x64"
|
| 340 |
+
],
|
| 341 |
+
"dev": true,
|
| 342 |
+
"optional": true,
|
| 343 |
+
"os": [
|
| 344 |
+
"sunos"
|
| 345 |
+
],
|
| 346 |
+
"engines": {
|
| 347 |
+
"node": ">=12"
|
| 348 |
+
}
|
| 349 |
+
},
|
| 350 |
+
"node_modules/@esbuild/win32-arm64": {
|
| 351 |
+
"version": "0.18.20",
|
| 352 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
|
| 353 |
+
"integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
|
| 354 |
+
"cpu": [
|
| 355 |
+
"arm64"
|
| 356 |
+
],
|
| 357 |
+
"dev": true,
|
| 358 |
+
"optional": true,
|
| 359 |
+
"os": [
|
| 360 |
+
"win32"
|
| 361 |
+
],
|
| 362 |
+
"engines": {
|
| 363 |
+
"node": ">=12"
|
| 364 |
+
}
|
| 365 |
+
},
|
| 366 |
+
"node_modules/@esbuild/win32-ia32": {
|
| 367 |
+
"version": "0.18.20",
|
| 368 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
|
| 369 |
+
"integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
|
| 370 |
+
"cpu": [
|
| 371 |
+
"ia32"
|
| 372 |
+
],
|
| 373 |
+
"dev": true,
|
| 374 |
+
"optional": true,
|
| 375 |
+
"os": [
|
| 376 |
+
"win32"
|
| 377 |
+
],
|
| 378 |
+
"engines": {
|
| 379 |
+
"node": ">=12"
|
| 380 |
+
}
|
| 381 |
+
},
|
| 382 |
+
"node_modules/@esbuild/win32-x64": {
|
| 383 |
+
"version": "0.18.20",
|
| 384 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
|
| 385 |
+
"integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
|
| 386 |
+
"cpu": [
|
| 387 |
+
"x64"
|
| 388 |
+
],
|
| 389 |
+
"dev": true,
|
| 390 |
+
"optional": true,
|
| 391 |
+
"os": [
|
| 392 |
+
"win32"
|
| 393 |
+
],
|
| 394 |
+
"engines": {
|
| 395 |
+
"node": ">=12"
|
| 396 |
+
}
|
| 397 |
+
},
|
| 398 |
+
"node_modules/@jridgewell/gen-mapping": {
|
| 399 |
+
"version": "0.3.3",
|
| 400 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
| 401 |
+
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
| 402 |
+
"dependencies": {
|
| 403 |
+
"@jridgewell/set-array": "^1.0.1",
|
| 404 |
+
"@jridgewell/sourcemap-codec": "^1.4.10",
|
| 405 |
+
"@jridgewell/trace-mapping": "^0.3.9"
|
| 406 |
+
},
|
| 407 |
+
"engines": {
|
| 408 |
+
"node": ">=6.0.0"
|
| 409 |
+
}
|
| 410 |
+
},
|
| 411 |
+
"node_modules/@jridgewell/resolve-uri": {
|
| 412 |
+
"version": "3.1.1",
|
| 413 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
| 414 |
+
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
|
| 415 |
+
"engines": {
|
| 416 |
+
"node": ">=6.0.0"
|
| 417 |
+
}
|
| 418 |
+
},
|
| 419 |
+
"node_modules/@jridgewell/set-array": {
|
| 420 |
+
"version": "1.1.2",
|
| 421 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
| 422 |
+
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
| 423 |
+
"engines": {
|
| 424 |
+
"node": ">=6.0.0"
|
| 425 |
+
}
|
| 426 |
+
},
|
| 427 |
+
"node_modules/@jridgewell/sourcemap-codec": {
|
| 428 |
+
"version": "1.4.15",
|
| 429 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
| 430 |
+
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
| 431 |
+
},
|
| 432 |
+
"node_modules/@jridgewell/trace-mapping": {
|
| 433 |
+
"version": "0.3.19",
|
| 434 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
|
| 435 |
+
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
|
| 436 |
+
"dependencies": {
|
| 437 |
+
"@jridgewell/resolve-uri": "^3.1.0",
|
| 438 |
+
"@jridgewell/sourcemap-codec": "^1.4.14"
|
| 439 |
+
}
|
| 440 |
+
},
|
| 441 |
+
"node_modules/@nodelib/fs.scandir": {
|
| 442 |
+
"version": "2.1.5",
|
| 443 |
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
| 444 |
+
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
| 445 |
+
"dev": true,
|
| 446 |
+
"dependencies": {
|
| 447 |
+
"@nodelib/fs.stat": "2.0.5",
|
| 448 |
+
"run-parallel": "^1.1.9"
|
| 449 |
+
},
|
| 450 |
+
"engines": {
|
| 451 |
+
"node": ">= 8"
|
| 452 |
+
}
|
| 453 |
+
},
|
| 454 |
+
"node_modules/@nodelib/fs.stat": {
|
| 455 |
+
"version": "2.0.5",
|
| 456 |
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
| 457 |
+
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
| 458 |
+
"dev": true,
|
| 459 |
+
"engines": {
|
| 460 |
+
"node": ">= 8"
|
| 461 |
+
}
|
| 462 |
+
},
|
| 463 |
+
"node_modules/@nodelib/fs.walk": {
|
| 464 |
+
"version": "1.2.8",
|
| 465 |
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
| 466 |
+
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
| 467 |
+
"dev": true,
|
| 468 |
+
"dependencies": {
|
| 469 |
+
"@nodelib/fs.scandir": "2.1.5",
|
| 470 |
+
"fastq": "^1.6.0"
|
| 471 |
+
},
|
| 472 |
+
"engines": {
|
| 473 |
+
"node": ">= 8"
|
| 474 |
+
}
|
| 475 |
+
},
|
| 476 |
+
"node_modules/@sveltejs/vite-plugin-svelte": {
|
| 477 |
+
"version": "2.4.6",
|
| 478 |
+
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.6.tgz",
|
| 479 |
+
"integrity": "sha512-zO79p0+DZnXPnF0ltIigWDx/ux7Ni+HRaFOw720Qeivc1azFUrJxTl0OryXVibYNx1hCboGia1NRV3x8RNv4cA==",
|
| 480 |
+
"dev": true,
|
| 481 |
+
"dependencies": {
|
| 482 |
+
"@sveltejs/vite-plugin-svelte-inspector": "^1.0.4",
|
| 483 |
+
"debug": "^4.3.4",
|
| 484 |
+
"deepmerge": "^4.3.1",
|
| 485 |
+
"kleur": "^4.1.5",
|
| 486 |
+
"magic-string": "^0.30.3",
|
| 487 |
+
"svelte-hmr": "^0.15.3",
|
| 488 |
+
"vitefu": "^0.2.4"
|
| 489 |
+
},
|
| 490 |
+
"engines": {
|
| 491 |
+
"node": "^14.18.0 || >= 16"
|
| 492 |
+
},
|
| 493 |
+
"peerDependencies": {
|
| 494 |
+
"svelte": "^3.54.0 || ^4.0.0",
|
| 495 |
+
"vite": "^4.0.0"
|
| 496 |
+
}
|
| 497 |
+
},
|
| 498 |
+
"node_modules/@sveltejs/vite-plugin-svelte-inspector": {
|
| 499 |
+
"version": "1.0.4",
|
| 500 |
+
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz",
|
| 501 |
+
"integrity": "sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==",
|
| 502 |
+
"dev": true,
|
| 503 |
+
"dependencies": {
|
| 504 |
+
"debug": "^4.3.4"
|
| 505 |
+
},
|
| 506 |
+
"engines": {
|
| 507 |
+
"node": "^14.18.0 || >= 16"
|
| 508 |
+
},
|
| 509 |
+
"peerDependencies": {
|
| 510 |
+
"@sveltejs/vite-plugin-svelte": "^2.2.0",
|
| 511 |
+
"svelte": "^3.54.0 || ^4.0.0",
|
| 512 |
+
"vite": "^4.0.0"
|
| 513 |
+
}
|
| 514 |
+
},
|
| 515 |
+
"node_modules/@types/estree": {
|
| 516 |
+
"version": "1.0.2",
|
| 517 |
+
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz",
|
| 518 |
+
"integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA=="
|
| 519 |
+
},
|
| 520 |
+
"node_modules/@types/marked": {
|
| 521 |
+
"version": "5.0.2",
|
| 522 |
+
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-5.0.2.tgz",
|
| 523 |
+
"integrity": "sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg=="
|
| 524 |
+
},
|
| 525 |
+
"node_modules/acorn": {
|
| 526 |
+
"version": "8.10.0",
|
| 527 |
+
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
|
| 528 |
+
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
|
| 529 |
+
"bin": {
|
| 530 |
+
"acorn": "bin/acorn"
|
| 531 |
+
},
|
| 532 |
+
"engines": {
|
| 533 |
+
"node": ">=0.4.0"
|
| 534 |
+
}
|
| 535 |
+
},
|
| 536 |
+
"node_modules/any-promise": {
|
| 537 |
+
"version": "1.3.0",
|
| 538 |
+
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
| 539 |
+
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
|
| 540 |
+
"dev": true
|
| 541 |
+
},
|
| 542 |
+
"node_modules/anymatch": {
|
| 543 |
+
"version": "3.1.3",
|
| 544 |
+
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
| 545 |
+
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
| 546 |
+
"dev": true,
|
| 547 |
+
"dependencies": {
|
| 548 |
+
"normalize-path": "^3.0.0",
|
| 549 |
+
"picomatch": "^2.0.4"
|
| 550 |
+
},
|
| 551 |
+
"engines": {
|
| 552 |
+
"node": ">= 8"
|
| 553 |
+
}
|
| 554 |
+
},
|
| 555 |
+
"node_modules/arg": {
|
| 556 |
+
"version": "5.0.2",
|
| 557 |
+
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
| 558 |
+
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
|
| 559 |
+
"dev": true
|
| 560 |
+
},
|
| 561 |
+
"node_modules/aria-query": {
|
| 562 |
+
"version": "5.3.0",
|
| 563 |
+
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
| 564 |
+
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
| 565 |
+
"dependencies": {
|
| 566 |
+
"dequal": "^2.0.3"
|
| 567 |
+
}
|
| 568 |
+
},
|
| 569 |
+
"node_modules/autoprefixer": {
|
| 570 |
+
"version": "10.4.16",
|
| 571 |
+
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
|
| 572 |
+
"integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==",
|
| 573 |
+
"dev": true,
|
| 574 |
+
"funding": [
|
| 575 |
+
{
|
| 576 |
+
"type": "opencollective",
|
| 577 |
+
"url": "https://opencollective.com/postcss/"
|
| 578 |
+
},
|
| 579 |
+
{
|
| 580 |
+
"type": "tidelift",
|
| 581 |
+
"url": "https://tidelift.com/funding/github/npm/autoprefixer"
|
| 582 |
+
},
|
| 583 |
+
{
|
| 584 |
+
"type": "github",
|
| 585 |
+
"url": "https://github.com/sponsors/ai"
|
| 586 |
+
}
|
| 587 |
+
],
|
| 588 |
+
"dependencies": {
|
| 589 |
+
"browserslist": "^4.21.10",
|
| 590 |
+
"caniuse-lite": "^1.0.30001538",
|
| 591 |
+
"fraction.js": "^4.3.6",
|
| 592 |
+
"normalize-range": "^0.1.2",
|
| 593 |
+
"picocolors": "^1.0.0",
|
| 594 |
+
"postcss-value-parser": "^4.2.0"
|
| 595 |
+
},
|
| 596 |
+
"bin": {
|
| 597 |
+
"autoprefixer": "bin/autoprefixer"
|
| 598 |
+
},
|
| 599 |
+
"engines": {
|
| 600 |
+
"node": "^10 || ^12 || >=14"
|
| 601 |
+
},
|
| 602 |
+
"peerDependencies": {
|
| 603 |
+
"postcss": "^8.1.0"
|
| 604 |
+
}
|
| 605 |
+
},
|
| 606 |
+
"node_modules/axobject-query": {
|
| 607 |
+
"version": "3.2.1",
|
| 608 |
+
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
|
| 609 |
+
"integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==",
|
| 610 |
+
"dependencies": {
|
| 611 |
+
"dequal": "^2.0.3"
|
| 612 |
+
}
|
| 613 |
+
},
|
| 614 |
+
"node_modules/balanced-match": {
|
| 615 |
+
"version": "1.0.2",
|
| 616 |
+
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
| 617 |
+
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
| 618 |
+
"dev": true
|
| 619 |
+
},
|
| 620 |
+
"node_modules/binary-extensions": {
|
| 621 |
+
"version": "2.2.0",
|
| 622 |
+
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
| 623 |
+
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
| 624 |
+
"dev": true,
|
| 625 |
+
"engines": {
|
| 626 |
+
"node": ">=8"
|
| 627 |
+
}
|
| 628 |
+
},
|
| 629 |
+
"node_modules/brace-expansion": {
|
| 630 |
+
"version": "1.1.11",
|
| 631 |
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
| 632 |
+
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
| 633 |
+
"dev": true,
|
| 634 |
+
"dependencies": {
|
| 635 |
+
"balanced-match": "^1.0.0",
|
| 636 |
+
"concat-map": "0.0.1"
|
| 637 |
+
}
|
| 638 |
+
},
|
| 639 |
+
"node_modules/braces": {
|
| 640 |
+
"version": "3.0.2",
|
| 641 |
+
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
| 642 |
+
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
| 643 |
+
"dev": true,
|
| 644 |
+
"dependencies": {
|
| 645 |
+
"fill-range": "^7.0.1"
|
| 646 |
+
},
|
| 647 |
+
"engines": {
|
| 648 |
+
"node": ">=8"
|
| 649 |
+
}
|
| 650 |
+
},
|
| 651 |
+
"node_modules/browserslist": {
|
| 652 |
+
"version": "4.22.1",
|
| 653 |
+
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
|
| 654 |
+
"integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==",
|
| 655 |
+
"dev": true,
|
| 656 |
+
"funding": [
|
| 657 |
+
{
|
| 658 |
+
"type": "opencollective",
|
| 659 |
+
"url": "https://opencollective.com/browserslist"
|
| 660 |
+
},
|
| 661 |
+
{
|
| 662 |
+
"type": "tidelift",
|
| 663 |
+
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
| 664 |
+
},
|
| 665 |
+
{
|
| 666 |
+
"type": "github",
|
| 667 |
+
"url": "https://github.com/sponsors/ai"
|
| 668 |
+
}
|
| 669 |
+
],
|
| 670 |
+
"dependencies": {
|
| 671 |
+
"caniuse-lite": "^1.0.30001541",
|
| 672 |
+
"electron-to-chromium": "^1.4.535",
|
| 673 |
+
"node-releases": "^2.0.13",
|
| 674 |
+
"update-browserslist-db": "^1.0.13"
|
| 675 |
+
},
|
| 676 |
+
"bin": {
|
| 677 |
+
"browserslist": "cli.js"
|
| 678 |
+
},
|
| 679 |
+
"engines": {
|
| 680 |
+
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
| 681 |
+
}
|
| 682 |
+
},
|
| 683 |
+
"node_modules/camelcase-css": {
|
| 684 |
+
"version": "2.0.1",
|
| 685 |
+
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
| 686 |
+
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
| 687 |
+
"dev": true,
|
| 688 |
+
"engines": {
|
| 689 |
+
"node": ">= 6"
|
| 690 |
+
}
|
| 691 |
+
},
|
| 692 |
+
"node_modules/caniuse-lite": {
|
| 693 |
+
"version": "1.0.30001546",
|
| 694 |
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz",
|
| 695 |
+
"integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==",
|
| 696 |
+
"dev": true,
|
| 697 |
+
"funding": [
|
| 698 |
+
{
|
| 699 |
+
"type": "opencollective",
|
| 700 |
+
"url": "https://opencollective.com/browserslist"
|
| 701 |
+
},
|
| 702 |
+
{
|
| 703 |
+
"type": "tidelift",
|
| 704 |
+
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
| 705 |
+
},
|
| 706 |
+
{
|
| 707 |
+
"type": "github",
|
| 708 |
+
"url": "https://github.com/sponsors/ai"
|
| 709 |
+
}
|
| 710 |
+
]
|
| 711 |
+
},
|
| 712 |
+
"node_modules/chokidar": {
|
| 713 |
+
"version": "3.5.3",
|
| 714 |
+
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
| 715 |
+
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
| 716 |
+
"dev": true,
|
| 717 |
+
"funding": [
|
| 718 |
+
{
|
| 719 |
+
"type": "individual",
|
| 720 |
+
"url": "https://paulmillr.com/funding/"
|
| 721 |
+
}
|
| 722 |
+
],
|
| 723 |
+
"dependencies": {
|
| 724 |
+
"anymatch": "~3.1.2",
|
| 725 |
+
"braces": "~3.0.2",
|
| 726 |
+
"glob-parent": "~5.1.2",
|
| 727 |
+
"is-binary-path": "~2.1.0",
|
| 728 |
+
"is-glob": "~4.0.1",
|
| 729 |
+
"normalize-path": "~3.0.0",
|
| 730 |
+
"readdirp": "~3.6.0"
|
| 731 |
+
},
|
| 732 |
+
"engines": {
|
| 733 |
+
"node": ">= 8.10.0"
|
| 734 |
+
},
|
| 735 |
+
"optionalDependencies": {
|
| 736 |
+
"fsevents": "~2.3.2"
|
| 737 |
+
}
|
| 738 |
+
},
|
| 739 |
+
"node_modules/chokidar/node_modules/glob-parent": {
|
| 740 |
+
"version": "5.1.2",
|
| 741 |
+
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
| 742 |
+
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
| 743 |
+
"dev": true,
|
| 744 |
+
"dependencies": {
|
| 745 |
+
"is-glob": "^4.0.1"
|
| 746 |
+
},
|
| 747 |
+
"engines": {
|
| 748 |
+
"node": ">= 6"
|
| 749 |
+
}
|
| 750 |
+
},
|
| 751 |
+
"node_modules/code-red": {
|
| 752 |
+
"version": "1.0.4",
|
| 753 |
+
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
|
| 754 |
+
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
|
| 755 |
+
"dependencies": {
|
| 756 |
+
"@jridgewell/sourcemap-codec": "^1.4.15",
|
| 757 |
+
"@types/estree": "^1.0.1",
|
| 758 |
+
"acorn": "^8.10.0",
|
| 759 |
+
"estree-walker": "^3.0.3",
|
| 760 |
+
"periscopic": "^3.1.0"
|
| 761 |
+
}
|
| 762 |
+
},
|
| 763 |
+
"node_modules/commander": {
|
| 764 |
+
"version": "4.1.1",
|
| 765 |
+
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
| 766 |
+
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
|
| 767 |
+
"dev": true,
|
| 768 |
+
"engines": {
|
| 769 |
+
"node": ">= 6"
|
| 770 |
+
}
|
| 771 |
+
},
|
| 772 |
+
"node_modules/concat-map": {
|
| 773 |
+
"version": "0.0.1",
|
| 774 |
+
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
| 775 |
+
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
| 776 |
+
"dev": true
|
| 777 |
+
},
|
| 778 |
+
"node_modules/css-tree": {
|
| 779 |
+
"version": "2.3.1",
|
| 780 |
+
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
|
| 781 |
+
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
|
| 782 |
+
"dependencies": {
|
| 783 |
+
"mdn-data": "2.0.30",
|
| 784 |
+
"source-map-js": "^1.0.1"
|
| 785 |
+
},
|
| 786 |
+
"engines": {
|
| 787 |
+
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
|
| 788 |
+
}
|
| 789 |
+
},
|
| 790 |
+
"node_modules/cssesc": {
|
| 791 |
+
"version": "3.0.0",
|
| 792 |
+
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
| 793 |
+
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
| 794 |
+
"dev": true,
|
| 795 |
+
"bin": {
|
| 796 |
+
"cssesc": "bin/cssesc"
|
| 797 |
+
},
|
| 798 |
+
"engines": {
|
| 799 |
+
"node": ">=4"
|
| 800 |
+
}
|
| 801 |
+
},
|
| 802 |
+
"node_modules/debug": {
|
| 803 |
+
"version": "4.3.4",
|
| 804 |
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
| 805 |
+
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
| 806 |
+
"dev": true,
|
| 807 |
+
"dependencies": {
|
| 808 |
+
"ms": "2.1.2"
|
| 809 |
+
},
|
| 810 |
+
"engines": {
|
| 811 |
+
"node": ">=6.0"
|
| 812 |
+
},
|
| 813 |
+
"peerDependenciesMeta": {
|
| 814 |
+
"supports-color": {
|
| 815 |
+
"optional": true
|
| 816 |
+
}
|
| 817 |
+
}
|
| 818 |
+
},
|
| 819 |
+
"node_modules/deepmerge": {
|
| 820 |
+
"version": "4.3.1",
|
| 821 |
+
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
| 822 |
+
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
| 823 |
+
"dev": true,
|
| 824 |
+
"engines": {
|
| 825 |
+
"node": ">=0.10.0"
|
| 826 |
+
}
|
| 827 |
+
},
|
| 828 |
+
"node_modules/dequal": {
|
| 829 |
+
"version": "2.0.3",
|
| 830 |
+
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
| 831 |
+
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
| 832 |
+
"engines": {
|
| 833 |
+
"node": ">=6"
|
| 834 |
+
}
|
| 835 |
+
},
|
| 836 |
+
"node_modules/didyoumean": {
|
| 837 |
+
"version": "1.2.2",
|
| 838 |
+
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
| 839 |
+
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
| 840 |
+
"dev": true
|
| 841 |
+
},
|
| 842 |
+
"node_modules/dlv": {
|
| 843 |
+
"version": "1.1.3",
|
| 844 |
+
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
| 845 |
+
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
| 846 |
+
"dev": true
|
| 847 |
+
},
|
| 848 |
+
"node_modules/electron-to-chromium": {
|
| 849 |
+
"version": "1.4.543",
|
| 850 |
+
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.543.tgz",
|
| 851 |
+
"integrity": "sha512-t2ZP4AcGE0iKCCQCBx/K2426crYdxD3YU6l0uK2EO3FZH0pbC4pFz/sZm2ruZsND6hQBTcDWWlo/MLpiOdif5g==",
|
| 852 |
+
"dev": true
|
| 853 |
+
},
|
| 854 |
+
"node_modules/esbuild": {
|
| 855 |
+
"version": "0.18.20",
|
| 856 |
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
|
| 857 |
+
"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
|
| 858 |
+
"dev": true,
|
| 859 |
+
"hasInstallScript": true,
|
| 860 |
+
"bin": {
|
| 861 |
+
"esbuild": "bin/esbuild"
|
| 862 |
+
},
|
| 863 |
+
"engines": {
|
| 864 |
+
"node": ">=12"
|
| 865 |
+
},
|
| 866 |
+
"optionalDependencies": {
|
| 867 |
+
"@esbuild/android-arm": "0.18.20",
|
| 868 |
+
"@esbuild/android-arm64": "0.18.20",
|
| 869 |
+
"@esbuild/android-x64": "0.18.20",
|
| 870 |
+
"@esbuild/darwin-arm64": "0.18.20",
|
| 871 |
+
"@esbuild/darwin-x64": "0.18.20",
|
| 872 |
+
"@esbuild/freebsd-arm64": "0.18.20",
|
| 873 |
+
"@esbuild/freebsd-x64": "0.18.20",
|
| 874 |
+
"@esbuild/linux-arm": "0.18.20",
|
| 875 |
+
"@esbuild/linux-arm64": "0.18.20",
|
| 876 |
+
"@esbuild/linux-ia32": "0.18.20",
|
| 877 |
+
"@esbuild/linux-loong64": "0.18.20",
|
| 878 |
+
"@esbuild/linux-mips64el": "0.18.20",
|
| 879 |
+
"@esbuild/linux-ppc64": "0.18.20",
|
| 880 |
+
"@esbuild/linux-riscv64": "0.18.20",
|
| 881 |
+
"@esbuild/linux-s390x": "0.18.20",
|
| 882 |
+
"@esbuild/linux-x64": "0.18.20",
|
| 883 |
+
"@esbuild/netbsd-x64": "0.18.20",
|
| 884 |
+
"@esbuild/openbsd-x64": "0.18.20",
|
| 885 |
+
"@esbuild/sunos-x64": "0.18.20",
|
| 886 |
+
"@esbuild/win32-arm64": "0.18.20",
|
| 887 |
+
"@esbuild/win32-ia32": "0.18.20",
|
| 888 |
+
"@esbuild/win32-x64": "0.18.20"
|
| 889 |
+
}
|
| 890 |
+
},
|
| 891 |
+
"node_modules/escalade": {
|
| 892 |
+
"version": "3.1.1",
|
| 893 |
+
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
| 894 |
+
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
| 895 |
+
"dev": true,
|
| 896 |
+
"engines": {
|
| 897 |
+
"node": ">=6"
|
| 898 |
+
}
|
| 899 |
+
},
|
| 900 |
+
"node_modules/estree-walker": {
|
| 901 |
+
"version": "3.0.3",
|
| 902 |
+
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
| 903 |
+
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
| 904 |
+
"dependencies": {
|
| 905 |
+
"@types/estree": "^1.0.0"
|
| 906 |
+
}
|
| 907 |
+
},
|
| 908 |
+
"node_modules/fast-glob": {
|
| 909 |
+
"version": "3.3.1",
|
| 910 |
+
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
|
| 911 |
+
"integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
|
| 912 |
+
"dev": true,
|
| 913 |
+
"dependencies": {
|
| 914 |
+
"@nodelib/fs.stat": "^2.0.2",
|
| 915 |
+
"@nodelib/fs.walk": "^1.2.3",
|
| 916 |
+
"glob-parent": "^5.1.2",
|
| 917 |
+
"merge2": "^1.3.0",
|
| 918 |
+
"micromatch": "^4.0.4"
|
| 919 |
+
},
|
| 920 |
+
"engines": {
|
| 921 |
+
"node": ">=8.6.0"
|
| 922 |
+
}
|
| 923 |
+
},
|
| 924 |
+
"node_modules/fast-glob/node_modules/glob-parent": {
|
| 925 |
+
"version": "5.1.2",
|
| 926 |
+
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
| 927 |
+
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
| 928 |
+
"dev": true,
|
| 929 |
+
"dependencies": {
|
| 930 |
+
"is-glob": "^4.0.1"
|
| 931 |
+
},
|
| 932 |
+
"engines": {
|
| 933 |
+
"node": ">= 6"
|
| 934 |
+
}
|
| 935 |
+
},
|
| 936 |
+
"node_modules/fastq": {
|
| 937 |
+
"version": "1.15.0",
|
| 938 |
+
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
|
| 939 |
+
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
|
| 940 |
+
"dev": true,
|
| 941 |
+
"dependencies": {
|
| 942 |
+
"reusify": "^1.0.4"
|
| 943 |
+
}
|
| 944 |
+
},
|
| 945 |
+
"node_modules/fill-range": {
|
| 946 |
+
"version": "7.0.1",
|
| 947 |
+
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
| 948 |
+
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
| 949 |
+
"dev": true,
|
| 950 |
+
"dependencies": {
|
| 951 |
+
"to-regex-range": "^5.0.1"
|
| 952 |
+
},
|
| 953 |
+
"engines": {
|
| 954 |
+
"node": ">=8"
|
| 955 |
+
}
|
| 956 |
+
},
|
| 957 |
+
"node_modules/fraction.js": {
|
| 958 |
+
"version": "4.3.6",
|
| 959 |
+
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz",
|
| 960 |
+
"integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==",
|
| 961 |
+
"dev": true,
|
| 962 |
+
"engines": {
|
| 963 |
+
"node": "*"
|
| 964 |
+
},
|
| 965 |
+
"funding": {
|
| 966 |
+
"type": "patreon",
|
| 967 |
+
"url": "https://github.com/sponsors/rawify"
|
| 968 |
+
}
|
| 969 |
+
},
|
| 970 |
+
"node_modules/fs.realpath": {
|
| 971 |
+
"version": "1.0.0",
|
| 972 |
+
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
| 973 |
+
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
| 974 |
+
"dev": true
|
| 975 |
+
},
|
| 976 |
+
"node_modules/fsevents": {
|
| 977 |
+
"version": "2.3.3",
|
| 978 |
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
| 979 |
+
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
| 980 |
+
"dev": true,
|
| 981 |
+
"hasInstallScript": true,
|
| 982 |
+
"optional": true,
|
| 983 |
+
"os": [
|
| 984 |
+
"darwin"
|
| 985 |
+
],
|
| 986 |
+
"engines": {
|
| 987 |
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
| 988 |
+
}
|
| 989 |
+
},
|
| 990 |
+
"node_modules/glob": {
|
| 991 |
+
"version": "7.1.6",
|
| 992 |
+
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
| 993 |
+
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
| 994 |
+
"dev": true,
|
| 995 |
+
"dependencies": {
|
| 996 |
+
"fs.realpath": "^1.0.0",
|
| 997 |
+
"inflight": "^1.0.4",
|
| 998 |
+
"inherits": "2",
|
| 999 |
+
"minimatch": "^3.0.4",
|
| 1000 |
+
"once": "^1.3.0",
|
| 1001 |
+
"path-is-absolute": "^1.0.0"
|
| 1002 |
+
},
|
| 1003 |
+
"engines": {
|
| 1004 |
+
"node": "*"
|
| 1005 |
+
},
|
| 1006 |
+
"funding": {
|
| 1007 |
+
"url": "https://github.com/sponsors/isaacs"
|
| 1008 |
+
}
|
| 1009 |
+
},
|
| 1010 |
+
"node_modules/glob-parent": {
|
| 1011 |
+
"version": "6.0.2",
|
| 1012 |
+
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
| 1013 |
+
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
| 1014 |
+
"dev": true,
|
| 1015 |
+
"dependencies": {
|
| 1016 |
+
"is-glob": "^4.0.3"
|
| 1017 |
+
},
|
| 1018 |
+
"engines": {
|
| 1019 |
+
"node": ">=10.13.0"
|
| 1020 |
+
}
|
| 1021 |
+
},
|
| 1022 |
+
"node_modules/has": {
|
| 1023 |
+
"version": "1.0.4",
|
| 1024 |
+
"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
|
| 1025 |
+
"integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
|
| 1026 |
+
"dev": true,
|
| 1027 |
+
"engines": {
|
| 1028 |
+
"node": ">= 0.4.0"
|
| 1029 |
+
}
|
| 1030 |
+
},
|
| 1031 |
+
"node_modules/inflight": {
|
| 1032 |
+
"version": "1.0.6",
|
| 1033 |
+
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
| 1034 |
+
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
| 1035 |
+
"dev": true,
|
| 1036 |
+
"dependencies": {
|
| 1037 |
+
"once": "^1.3.0",
|
| 1038 |
+
"wrappy": "1"
|
| 1039 |
+
}
|
| 1040 |
+
},
|
| 1041 |
+
"node_modules/inherits": {
|
| 1042 |
+
"version": "2.0.4",
|
| 1043 |
+
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
| 1044 |
+
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
| 1045 |
+
"dev": true
|
| 1046 |
+
},
|
| 1047 |
+
"node_modules/is-binary-path": {
|
| 1048 |
+
"version": "2.1.0",
|
| 1049 |
+
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
| 1050 |
+
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
| 1051 |
+
"dev": true,
|
| 1052 |
+
"dependencies": {
|
| 1053 |
+
"binary-extensions": "^2.0.0"
|
| 1054 |
+
},
|
| 1055 |
+
"engines": {
|
| 1056 |
+
"node": ">=8"
|
| 1057 |
+
}
|
| 1058 |
+
},
|
| 1059 |
+
"node_modules/is-core-module": {
|
| 1060 |
+
"version": "2.13.0",
|
| 1061 |
+
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
|
| 1062 |
+
"integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
|
| 1063 |
+
"dev": true,
|
| 1064 |
+
"dependencies": {
|
| 1065 |
+
"has": "^1.0.3"
|
| 1066 |
+
},
|
| 1067 |
+
"funding": {
|
| 1068 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 1069 |
+
}
|
| 1070 |
+
},
|
| 1071 |
+
"node_modules/is-extglob": {
|
| 1072 |
+
"version": "2.1.1",
|
| 1073 |
+
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
| 1074 |
+
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
| 1075 |
+
"dev": true,
|
| 1076 |
+
"engines": {
|
| 1077 |
+
"node": ">=0.10.0"
|
| 1078 |
+
}
|
| 1079 |
+
},
|
| 1080 |
+
"node_modules/is-glob": {
|
| 1081 |
+
"version": "4.0.3",
|
| 1082 |
+
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
| 1083 |
+
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
| 1084 |
+
"dev": true,
|
| 1085 |
+
"dependencies": {
|
| 1086 |
+
"is-extglob": "^2.1.1"
|
| 1087 |
+
},
|
| 1088 |
+
"engines": {
|
| 1089 |
+
"node": ">=0.10.0"
|
| 1090 |
+
}
|
| 1091 |
+
},
|
| 1092 |
+
"node_modules/is-number": {
|
| 1093 |
+
"version": "7.0.0",
|
| 1094 |
+
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
| 1095 |
+
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
| 1096 |
+
"dev": true,
|
| 1097 |
+
"engines": {
|
| 1098 |
+
"node": ">=0.12.0"
|
| 1099 |
+
}
|
| 1100 |
+
},
|
| 1101 |
+
"node_modules/is-reference": {
|
| 1102 |
+
"version": "3.0.2",
|
| 1103 |
+
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
|
| 1104 |
+
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
|
| 1105 |
+
"dependencies": {
|
| 1106 |
+
"@types/estree": "*"
|
| 1107 |
+
}
|
| 1108 |
+
},
|
| 1109 |
+
"node_modules/jiti": {
|
| 1110 |
+
"version": "1.20.0",
|
| 1111 |
+
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz",
|
| 1112 |
+
"integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==",
|
| 1113 |
+
"dev": true,
|
| 1114 |
+
"bin": {
|
| 1115 |
+
"jiti": "bin/jiti.js"
|
| 1116 |
+
}
|
| 1117 |
+
},
|
| 1118 |
+
"node_modules/kleur": {
|
| 1119 |
+
"version": "4.1.5",
|
| 1120 |
+
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
| 1121 |
+
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
|
| 1122 |
+
"dev": true,
|
| 1123 |
+
"engines": {
|
| 1124 |
+
"node": ">=6"
|
| 1125 |
+
}
|
| 1126 |
+
},
|
| 1127 |
+
"node_modules/lilconfig": {
|
| 1128 |
+
"version": "2.1.0",
|
| 1129 |
+
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
| 1130 |
+
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
|
| 1131 |
+
"dev": true,
|
| 1132 |
+
"engines": {
|
| 1133 |
+
"node": ">=10"
|
| 1134 |
+
}
|
| 1135 |
+
},
|
| 1136 |
+
"node_modules/lines-and-columns": {
|
| 1137 |
+
"version": "1.2.4",
|
| 1138 |
+
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
| 1139 |
+
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
| 1140 |
+
"dev": true
|
| 1141 |
+
},
|
| 1142 |
+
"node_modules/locate-character": {
|
| 1143 |
+
"version": "3.0.0",
|
| 1144 |
+
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
|
| 1145 |
+
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="
|
| 1146 |
+
},
|
| 1147 |
+
"node_modules/magic-string": {
|
| 1148 |
+
"version": "0.30.4",
|
| 1149 |
+
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.4.tgz",
|
| 1150 |
+
"integrity": "sha512-Q/TKtsC5BPm0kGqgBIF9oXAs/xEf2vRKiIB4wCRQTJOQIByZ1d+NnUOotvJOvNpi5RNIgVOMC3pOuaP1ZTDlVg==",
|
| 1151 |
+
"dependencies": {
|
| 1152 |
+
"@jridgewell/sourcemap-codec": "^1.4.15"
|
| 1153 |
+
},
|
| 1154 |
+
"engines": {
|
| 1155 |
+
"node": ">=12"
|
| 1156 |
+
}
|
| 1157 |
+
},
|
| 1158 |
+
"node_modules/marked": {
|
| 1159 |
+
"version": "5.1.2",
|
| 1160 |
+
"resolved": "https://registry.npmjs.org/marked/-/marked-5.1.2.tgz",
|
| 1161 |
+
"integrity": "sha512-ahRPGXJpjMjwSOlBoTMZAK7ATXkli5qCPxZ21TG44rx1KEo44bii4ekgTDQPNRQ4Kh7JMb9Ub1PVk1NxRSsorg==",
|
| 1162 |
+
"bin": {
|
| 1163 |
+
"marked": "bin/marked.js"
|
| 1164 |
+
},
|
| 1165 |
+
"engines": {
|
| 1166 |
+
"node": ">= 16"
|
| 1167 |
+
}
|
| 1168 |
+
},
|
| 1169 |
+
"node_modules/mdn-data": {
|
| 1170 |
+
"version": "2.0.30",
|
| 1171 |
+
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
| 1172 |
+
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
|
| 1173 |
+
},
|
| 1174 |
+
"node_modules/merge2": {
|
| 1175 |
+
"version": "1.4.1",
|
| 1176 |
+
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
| 1177 |
+
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
| 1178 |
+
"dev": true,
|
| 1179 |
+
"engines": {
|
| 1180 |
+
"node": ">= 8"
|
| 1181 |
+
}
|
| 1182 |
+
},
|
| 1183 |
+
"node_modules/micromatch": {
|
| 1184 |
+
"version": "4.0.5",
|
| 1185 |
+
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
| 1186 |
+
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
| 1187 |
+
"dev": true,
|
| 1188 |
+
"dependencies": {
|
| 1189 |
+
"braces": "^3.0.2",
|
| 1190 |
+
"picomatch": "^2.3.1"
|
| 1191 |
+
},
|
| 1192 |
+
"engines": {
|
| 1193 |
+
"node": ">=8.6"
|
| 1194 |
+
}
|
| 1195 |
+
},
|
| 1196 |
+
"node_modules/minimatch": {
|
| 1197 |
+
"version": "3.1.2",
|
| 1198 |
+
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
| 1199 |
+
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
| 1200 |
+
"dev": true,
|
| 1201 |
+
"dependencies": {
|
| 1202 |
+
"brace-expansion": "^1.1.7"
|
| 1203 |
+
},
|
| 1204 |
+
"engines": {
|
| 1205 |
+
"node": "*"
|
| 1206 |
+
}
|
| 1207 |
+
},
|
| 1208 |
+
"node_modules/ms": {
|
| 1209 |
+
"version": "2.1.2",
|
| 1210 |
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
| 1211 |
+
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
| 1212 |
+
"dev": true
|
| 1213 |
+
},
|
| 1214 |
+
"node_modules/mz": {
|
| 1215 |
+
"version": "2.7.0",
|
| 1216 |
+
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
| 1217 |
+
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
| 1218 |
+
"dev": true,
|
| 1219 |
+
"dependencies": {
|
| 1220 |
+
"any-promise": "^1.0.0",
|
| 1221 |
+
"object-assign": "^4.0.1",
|
| 1222 |
+
"thenify-all": "^1.0.0"
|
| 1223 |
+
}
|
| 1224 |
+
},
|
| 1225 |
+
"node_modules/nanoid": {
|
| 1226 |
+
"version": "3.3.6",
|
| 1227 |
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
| 1228 |
+
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
| 1229 |
+
"dev": true,
|
| 1230 |
+
"funding": [
|
| 1231 |
+
{
|
| 1232 |
+
"type": "github",
|
| 1233 |
+
"url": "https://github.com/sponsors/ai"
|
| 1234 |
+
}
|
| 1235 |
+
],
|
| 1236 |
+
"bin": {
|
| 1237 |
+
"nanoid": "bin/nanoid.cjs"
|
| 1238 |
+
},
|
| 1239 |
+
"engines": {
|
| 1240 |
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
| 1241 |
+
}
|
| 1242 |
+
},
|
| 1243 |
+
"node_modules/node-releases": {
|
| 1244 |
+
"version": "2.0.13",
|
| 1245 |
+
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
| 1246 |
+
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
|
| 1247 |
+
"dev": true
|
| 1248 |
+
},
|
| 1249 |
+
"node_modules/normalize-path": {
|
| 1250 |
+
"version": "3.0.0",
|
| 1251 |
+
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
| 1252 |
+
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
| 1253 |
+
"dev": true,
|
| 1254 |
+
"engines": {
|
| 1255 |
+
"node": ">=0.10.0"
|
| 1256 |
+
}
|
| 1257 |
+
},
|
| 1258 |
+
"node_modules/normalize-range": {
|
| 1259 |
+
"version": "0.1.2",
|
| 1260 |
+
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
| 1261 |
+
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
|
| 1262 |
+
"dev": true,
|
| 1263 |
+
"engines": {
|
| 1264 |
+
"node": ">=0.10.0"
|
| 1265 |
+
}
|
| 1266 |
+
},
|
| 1267 |
+
"node_modules/object-assign": {
|
| 1268 |
+
"version": "4.1.1",
|
| 1269 |
+
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
| 1270 |
+
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
| 1271 |
+
"dev": true,
|
| 1272 |
+
"engines": {
|
| 1273 |
+
"node": ">=0.10.0"
|
| 1274 |
+
}
|
| 1275 |
+
},
|
| 1276 |
+
"node_modules/object-hash": {
|
| 1277 |
+
"version": "3.0.0",
|
| 1278 |
+
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
| 1279 |
+
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
| 1280 |
+
"dev": true,
|
| 1281 |
+
"engines": {
|
| 1282 |
+
"node": ">= 6"
|
| 1283 |
+
}
|
| 1284 |
+
},
|
| 1285 |
+
"node_modules/once": {
|
| 1286 |
+
"version": "1.4.0",
|
| 1287 |
+
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
| 1288 |
+
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
| 1289 |
+
"dev": true,
|
| 1290 |
+
"dependencies": {
|
| 1291 |
+
"wrappy": "1"
|
| 1292 |
+
}
|
| 1293 |
+
},
|
| 1294 |
+
"node_modules/path-is-absolute": {
|
| 1295 |
+
"version": "1.0.1",
|
| 1296 |
+
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
| 1297 |
+
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
| 1298 |
+
"dev": true,
|
| 1299 |
+
"engines": {
|
| 1300 |
+
"node": ">=0.10.0"
|
| 1301 |
+
}
|
| 1302 |
+
},
|
| 1303 |
+
"node_modules/path-parse": {
|
| 1304 |
+
"version": "1.0.7",
|
| 1305 |
+
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
| 1306 |
+
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
| 1307 |
+
"dev": true
|
| 1308 |
+
},
|
| 1309 |
+
"node_modules/periscopic": {
|
| 1310 |
+
"version": "3.1.0",
|
| 1311 |
+
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
|
| 1312 |
+
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
|
| 1313 |
+
"dependencies": {
|
| 1314 |
+
"@types/estree": "^1.0.0",
|
| 1315 |
+
"estree-walker": "^3.0.0",
|
| 1316 |
+
"is-reference": "^3.0.0"
|
| 1317 |
+
}
|
| 1318 |
+
},
|
| 1319 |
+
"node_modules/picocolors": {
|
| 1320 |
+
"version": "1.0.0",
|
| 1321 |
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
| 1322 |
+
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
| 1323 |
+
"dev": true
|
| 1324 |
+
},
|
| 1325 |
+
"node_modules/picomatch": {
|
| 1326 |
+
"version": "2.3.1",
|
| 1327 |
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
| 1328 |
+
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
| 1329 |
+
"dev": true,
|
| 1330 |
+
"engines": {
|
| 1331 |
+
"node": ">=8.6"
|
| 1332 |
+
},
|
| 1333 |
+
"funding": {
|
| 1334 |
+
"url": "https://github.com/sponsors/jonschlinkert"
|
| 1335 |
+
}
|
| 1336 |
+
},
|
| 1337 |
+
"node_modules/pify": {
|
| 1338 |
+
"version": "2.3.0",
|
| 1339 |
+
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
| 1340 |
+
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
| 1341 |
+
"dev": true,
|
| 1342 |
+
"engines": {
|
| 1343 |
+
"node": ">=0.10.0"
|
| 1344 |
+
}
|
| 1345 |
+
},
|
| 1346 |
+
"node_modules/pirates": {
|
| 1347 |
+
"version": "4.0.6",
|
| 1348 |
+
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
| 1349 |
+
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
|
| 1350 |
+
"dev": true,
|
| 1351 |
+
"engines": {
|
| 1352 |
+
"node": ">= 6"
|
| 1353 |
+
}
|
| 1354 |
+
},
|
| 1355 |
+
"node_modules/postcss": {
|
| 1356 |
+
"version": "8.4.31",
|
| 1357 |
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
| 1358 |
+
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
| 1359 |
+
"dev": true,
|
| 1360 |
+
"funding": [
|
| 1361 |
+
{
|
| 1362 |
+
"type": "opencollective",
|
| 1363 |
+
"url": "https://opencollective.com/postcss/"
|
| 1364 |
+
},
|
| 1365 |
+
{
|
| 1366 |
+
"type": "tidelift",
|
| 1367 |
+
"url": "https://tidelift.com/funding/github/npm/postcss"
|
| 1368 |
+
},
|
| 1369 |
+
{
|
| 1370 |
+
"type": "github",
|
| 1371 |
+
"url": "https://github.com/sponsors/ai"
|
| 1372 |
+
}
|
| 1373 |
+
],
|
| 1374 |
+
"dependencies": {
|
| 1375 |
+
"nanoid": "^3.3.6",
|
| 1376 |
+
"picocolors": "^1.0.0",
|
| 1377 |
+
"source-map-js": "^1.0.2"
|
| 1378 |
+
},
|
| 1379 |
+
"engines": {
|
| 1380 |
+
"node": "^10 || ^12 || >=14"
|
| 1381 |
+
}
|
| 1382 |
+
},
|
| 1383 |
+
"node_modules/postcss-import": {
|
| 1384 |
+
"version": "15.1.0",
|
| 1385 |
+
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
| 1386 |
+
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
| 1387 |
+
"dev": true,
|
| 1388 |
+
"dependencies": {
|
| 1389 |
+
"postcss-value-parser": "^4.0.0",
|
| 1390 |
+
"read-cache": "^1.0.0",
|
| 1391 |
+
"resolve": "^1.1.7"
|
| 1392 |
+
},
|
| 1393 |
+
"engines": {
|
| 1394 |
+
"node": ">=14.0.0"
|
| 1395 |
+
},
|
| 1396 |
+
"peerDependencies": {
|
| 1397 |
+
"postcss": "^8.0.0"
|
| 1398 |
+
}
|
| 1399 |
+
},
|
| 1400 |
+
"node_modules/postcss-js": {
|
| 1401 |
+
"version": "4.0.1",
|
| 1402 |
+
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
| 1403 |
+
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
| 1404 |
+
"dev": true,
|
| 1405 |
+
"dependencies": {
|
| 1406 |
+
"camelcase-css": "^2.0.1"
|
| 1407 |
+
},
|
| 1408 |
+
"engines": {
|
| 1409 |
+
"node": "^12 || ^14 || >= 16"
|
| 1410 |
+
},
|
| 1411 |
+
"funding": {
|
| 1412 |
+
"type": "opencollective",
|
| 1413 |
+
"url": "https://opencollective.com/postcss/"
|
| 1414 |
+
},
|
| 1415 |
+
"peerDependencies": {
|
| 1416 |
+
"postcss": "^8.4.21"
|
| 1417 |
+
}
|
| 1418 |
+
},
|
| 1419 |
+
"node_modules/postcss-load-config": {
|
| 1420 |
+
"version": "4.0.1",
|
| 1421 |
+
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
|
| 1422 |
+
"integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
|
| 1423 |
+
"dev": true,
|
| 1424 |
+
"dependencies": {
|
| 1425 |
+
"lilconfig": "^2.0.5",
|
| 1426 |
+
"yaml": "^2.1.1"
|
| 1427 |
+
},
|
| 1428 |
+
"engines": {
|
| 1429 |
+
"node": ">= 14"
|
| 1430 |
+
},
|
| 1431 |
+
"funding": {
|
| 1432 |
+
"type": "opencollective",
|
| 1433 |
+
"url": "https://opencollective.com/postcss/"
|
| 1434 |
+
},
|
| 1435 |
+
"peerDependencies": {
|
| 1436 |
+
"postcss": ">=8.0.9",
|
| 1437 |
+
"ts-node": ">=9.0.0"
|
| 1438 |
+
},
|
| 1439 |
+
"peerDependenciesMeta": {
|
| 1440 |
+
"postcss": {
|
| 1441 |
+
"optional": true
|
| 1442 |
+
},
|
| 1443 |
+
"ts-node": {
|
| 1444 |
+
"optional": true
|
| 1445 |
+
}
|
| 1446 |
+
}
|
| 1447 |
+
},
|
| 1448 |
+
"node_modules/postcss-nested": {
|
| 1449 |
+
"version": "6.0.1",
|
| 1450 |
+
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
|
| 1451 |
+
"integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
|
| 1452 |
+
"dev": true,
|
| 1453 |
+
"dependencies": {
|
| 1454 |
+
"postcss-selector-parser": "^6.0.11"
|
| 1455 |
+
},
|
| 1456 |
+
"engines": {
|
| 1457 |
+
"node": ">=12.0"
|
| 1458 |
+
},
|
| 1459 |
+
"funding": {
|
| 1460 |
+
"type": "opencollective",
|
| 1461 |
+
"url": "https://opencollective.com/postcss/"
|
| 1462 |
+
},
|
| 1463 |
+
"peerDependencies": {
|
| 1464 |
+
"postcss": "^8.2.14"
|
| 1465 |
+
}
|
| 1466 |
+
},
|
| 1467 |
+
"node_modules/postcss-selector-parser": {
|
| 1468 |
+
"version": "6.0.13",
|
| 1469 |
+
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
|
| 1470 |
+
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
|
| 1471 |
+
"dev": true,
|
| 1472 |
+
"dependencies": {
|
| 1473 |
+
"cssesc": "^3.0.0",
|
| 1474 |
+
"util-deprecate": "^1.0.2"
|
| 1475 |
+
},
|
| 1476 |
+
"engines": {
|
| 1477 |
+
"node": ">=4"
|
| 1478 |
+
}
|
| 1479 |
+
},
|
| 1480 |
+
"node_modules/postcss-value-parser": {
|
| 1481 |
+
"version": "4.2.0",
|
| 1482 |
+
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
| 1483 |
+
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
| 1484 |
+
"dev": true
|
| 1485 |
+
},
|
| 1486 |
+
"node_modules/queue-microtask": {
|
| 1487 |
+
"version": "1.2.3",
|
| 1488 |
+
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
| 1489 |
+
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
| 1490 |
+
"dev": true,
|
| 1491 |
+
"funding": [
|
| 1492 |
+
{
|
| 1493 |
+
"type": "github",
|
| 1494 |
+
"url": "https://github.com/sponsors/feross"
|
| 1495 |
+
},
|
| 1496 |
+
{
|
| 1497 |
+
"type": "patreon",
|
| 1498 |
+
"url": "https://www.patreon.com/feross"
|
| 1499 |
+
},
|
| 1500 |
+
{
|
| 1501 |
+
"type": "consulting",
|
| 1502 |
+
"url": "https://feross.org/support"
|
| 1503 |
+
}
|
| 1504 |
+
]
|
| 1505 |
+
},
|
| 1506 |
+
"node_modules/read-cache": {
|
| 1507 |
+
"version": "1.0.0",
|
| 1508 |
+
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
| 1509 |
+
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
| 1510 |
+
"dev": true,
|
| 1511 |
+
"dependencies": {
|
| 1512 |
+
"pify": "^2.3.0"
|
| 1513 |
+
}
|
| 1514 |
+
},
|
| 1515 |
+
"node_modules/readdirp": {
|
| 1516 |
+
"version": "3.6.0",
|
| 1517 |
+
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
| 1518 |
+
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
| 1519 |
+
"dev": true,
|
| 1520 |
+
"dependencies": {
|
| 1521 |
+
"picomatch": "^2.2.1"
|
| 1522 |
+
},
|
| 1523 |
+
"engines": {
|
| 1524 |
+
"node": ">=8.10.0"
|
| 1525 |
+
}
|
| 1526 |
+
},
|
| 1527 |
+
"node_modules/resolve": {
|
| 1528 |
+
"version": "1.22.6",
|
| 1529 |
+
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz",
|
| 1530 |
+
"integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==",
|
| 1531 |
+
"dev": true,
|
| 1532 |
+
"dependencies": {
|
| 1533 |
+
"is-core-module": "^2.13.0",
|
| 1534 |
+
"path-parse": "^1.0.7",
|
| 1535 |
+
"supports-preserve-symlinks-flag": "^1.0.0"
|
| 1536 |
+
},
|
| 1537 |
+
"bin": {
|
| 1538 |
+
"resolve": "bin/resolve"
|
| 1539 |
+
},
|
| 1540 |
+
"funding": {
|
| 1541 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 1542 |
+
}
|
| 1543 |
+
},
|
| 1544 |
+
"node_modules/reusify": {
|
| 1545 |
+
"version": "1.0.4",
|
| 1546 |
+
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
| 1547 |
+
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
| 1548 |
+
"dev": true,
|
| 1549 |
+
"engines": {
|
| 1550 |
+
"iojs": ">=1.0.0",
|
| 1551 |
+
"node": ">=0.10.0"
|
| 1552 |
+
}
|
| 1553 |
+
},
|
| 1554 |
+
"node_modules/rollup": {
|
| 1555 |
+
"version": "3.29.4",
|
| 1556 |
+
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
|
| 1557 |
+
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
|
| 1558 |
+
"dev": true,
|
| 1559 |
+
"bin": {
|
| 1560 |
+
"rollup": "dist/bin/rollup"
|
| 1561 |
+
},
|
| 1562 |
+
"engines": {
|
| 1563 |
+
"node": ">=14.18.0",
|
| 1564 |
+
"npm": ">=8.0.0"
|
| 1565 |
+
},
|
| 1566 |
+
"optionalDependencies": {
|
| 1567 |
+
"fsevents": "~2.3.2"
|
| 1568 |
+
}
|
| 1569 |
+
},
|
| 1570 |
+
"node_modules/run-parallel": {
|
| 1571 |
+
"version": "1.2.0",
|
| 1572 |
+
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
| 1573 |
+
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
| 1574 |
+
"dev": true,
|
| 1575 |
+
"funding": [
|
| 1576 |
+
{
|
| 1577 |
+
"type": "github",
|
| 1578 |
+
"url": "https://github.com/sponsors/feross"
|
| 1579 |
+
},
|
| 1580 |
+
{
|
| 1581 |
+
"type": "patreon",
|
| 1582 |
+
"url": "https://www.patreon.com/feross"
|
| 1583 |
+
},
|
| 1584 |
+
{
|
| 1585 |
+
"type": "consulting",
|
| 1586 |
+
"url": "https://feross.org/support"
|
| 1587 |
+
}
|
| 1588 |
+
],
|
| 1589 |
+
"dependencies": {
|
| 1590 |
+
"queue-microtask": "^1.2.2"
|
| 1591 |
+
}
|
| 1592 |
+
},
|
| 1593 |
+
"node_modules/source-map-js": {
|
| 1594 |
+
"version": "1.0.2",
|
| 1595 |
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
| 1596 |
+
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
| 1597 |
+
"engines": {
|
| 1598 |
+
"node": ">=0.10.0"
|
| 1599 |
+
}
|
| 1600 |
+
},
|
| 1601 |
+
"node_modules/sucrase": {
|
| 1602 |
+
"version": "3.34.0",
|
| 1603 |
+
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
|
| 1604 |
+
"integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==",
|
| 1605 |
+
"dev": true,
|
| 1606 |
+
"dependencies": {
|
| 1607 |
+
"@jridgewell/gen-mapping": "^0.3.2",
|
| 1608 |
+
"commander": "^4.0.0",
|
| 1609 |
+
"glob": "7.1.6",
|
| 1610 |
+
"lines-and-columns": "^1.1.6",
|
| 1611 |
+
"mz": "^2.7.0",
|
| 1612 |
+
"pirates": "^4.0.1",
|
| 1613 |
+
"ts-interface-checker": "^0.1.9"
|
| 1614 |
+
},
|
| 1615 |
+
"bin": {
|
| 1616 |
+
"sucrase": "bin/sucrase",
|
| 1617 |
+
"sucrase-node": "bin/sucrase-node"
|
| 1618 |
+
},
|
| 1619 |
+
"engines": {
|
| 1620 |
+
"node": ">=8"
|
| 1621 |
+
}
|
| 1622 |
+
},
|
| 1623 |
+
"node_modules/supports-preserve-symlinks-flag": {
|
| 1624 |
+
"version": "1.0.0",
|
| 1625 |
+
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
| 1626 |
+
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
| 1627 |
+
"dev": true,
|
| 1628 |
+
"engines": {
|
| 1629 |
+
"node": ">= 0.4"
|
| 1630 |
+
},
|
| 1631 |
+
"funding": {
|
| 1632 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 1633 |
+
}
|
| 1634 |
+
},
|
| 1635 |
+
"node_modules/svelte": {
|
| 1636 |
+
"version": "4.2.1",
|
| 1637 |
+
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.1.tgz",
|
| 1638 |
+
"integrity": "sha512-LpLqY2Jr7cRxkrTc796/AaaoMLF/1ax7cto8Ot76wrvKQhrPmZ0JgajiWPmg9mTSDqO16SSLiD17r9MsvAPTmw==",
|
| 1639 |
+
"dependencies": {
|
| 1640 |
+
"@ampproject/remapping": "^2.2.1",
|
| 1641 |
+
"@jridgewell/sourcemap-codec": "^1.4.15",
|
| 1642 |
+
"@jridgewell/trace-mapping": "^0.3.18",
|
| 1643 |
+
"acorn": "^8.9.0",
|
| 1644 |
+
"aria-query": "^5.3.0",
|
| 1645 |
+
"axobject-query": "^3.2.1",
|
| 1646 |
+
"code-red": "^1.0.3",
|
| 1647 |
+
"css-tree": "^2.3.1",
|
| 1648 |
+
"estree-walker": "^3.0.3",
|
| 1649 |
+
"is-reference": "^3.0.1",
|
| 1650 |
+
"locate-character": "^3.0.0",
|
| 1651 |
+
"magic-string": "^0.30.0",
|
| 1652 |
+
"periscopic": "^3.1.0"
|
| 1653 |
+
},
|
| 1654 |
+
"engines": {
|
| 1655 |
+
"node": ">=16"
|
| 1656 |
+
}
|
| 1657 |
+
},
|
| 1658 |
+
"node_modules/svelte-hmr": {
|
| 1659 |
+
"version": "0.15.3",
|
| 1660 |
+
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
|
| 1661 |
+
"integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==",
|
| 1662 |
+
"dev": true,
|
| 1663 |
+
"engines": {
|
| 1664 |
+
"node": "^12.20 || ^14.13.1 || >= 16"
|
| 1665 |
+
},
|
| 1666 |
+
"peerDependencies": {
|
| 1667 |
+
"svelte": "^3.19.0 || ^4.0.0"
|
| 1668 |
+
}
|
| 1669 |
+
},
|
| 1670 |
+
"node_modules/svelte-markdown": {
|
| 1671 |
+
"version": "0.4.0",
|
| 1672 |
+
"resolved": "https://registry.npmjs.org/svelte-markdown/-/svelte-markdown-0.4.0.tgz",
|
| 1673 |
+
"integrity": "sha512-d8xYJoPhhiLn/tFrO54V5p22q2+I7It8w3CpTv+O+h99LlgehxK9XwdISVBl2aNcLbLX128Nz/vu7GScWhVZjw==",
|
| 1674 |
+
"dependencies": {
|
| 1675 |
+
"@types/marked": "^5.0.1",
|
| 1676 |
+
"marked": "^5.1.2"
|
| 1677 |
+
},
|
| 1678 |
+
"peerDependencies": {
|
| 1679 |
+
"svelte": "^4.0.0"
|
| 1680 |
+
}
|
| 1681 |
+
},
|
| 1682 |
+
"node_modules/tailwindcss": {
|
| 1683 |
+
"version": "3.3.3",
|
| 1684 |
+
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
|
| 1685 |
+
"integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
|
| 1686 |
+
"dev": true,
|
| 1687 |
+
"dependencies": {
|
| 1688 |
+
"@alloc/quick-lru": "^5.2.0",
|
| 1689 |
+
"arg": "^5.0.2",
|
| 1690 |
+
"chokidar": "^3.5.3",
|
| 1691 |
+
"didyoumean": "^1.2.2",
|
| 1692 |
+
"dlv": "^1.1.3",
|
| 1693 |
+
"fast-glob": "^3.2.12",
|
| 1694 |
+
"glob-parent": "^6.0.2",
|
| 1695 |
+
"is-glob": "^4.0.3",
|
| 1696 |
+
"jiti": "^1.18.2",
|
| 1697 |
+
"lilconfig": "^2.1.0",
|
| 1698 |
+
"micromatch": "^4.0.5",
|
| 1699 |
+
"normalize-path": "^3.0.0",
|
| 1700 |
+
"object-hash": "^3.0.0",
|
| 1701 |
+
"picocolors": "^1.0.0",
|
| 1702 |
+
"postcss": "^8.4.23",
|
| 1703 |
+
"postcss-import": "^15.1.0",
|
| 1704 |
+
"postcss-js": "^4.0.1",
|
| 1705 |
+
"postcss-load-config": "^4.0.1",
|
| 1706 |
+
"postcss-nested": "^6.0.1",
|
| 1707 |
+
"postcss-selector-parser": "^6.0.11",
|
| 1708 |
+
"resolve": "^1.22.2",
|
| 1709 |
+
"sucrase": "^3.32.0"
|
| 1710 |
+
},
|
| 1711 |
+
"bin": {
|
| 1712 |
+
"tailwind": "lib/cli.js",
|
| 1713 |
+
"tailwindcss": "lib/cli.js"
|
| 1714 |
+
},
|
| 1715 |
+
"engines": {
|
| 1716 |
+
"node": ">=14.0.0"
|
| 1717 |
+
}
|
| 1718 |
+
},
|
| 1719 |
+
"node_modules/thenify": {
|
| 1720 |
+
"version": "3.3.1",
|
| 1721 |
+
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
| 1722 |
+
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
|
| 1723 |
+
"dev": true,
|
| 1724 |
+
"dependencies": {
|
| 1725 |
+
"any-promise": "^1.0.0"
|
| 1726 |
+
}
|
| 1727 |
+
},
|
| 1728 |
+
"node_modules/thenify-all": {
|
| 1729 |
+
"version": "1.6.0",
|
| 1730 |
+
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
| 1731 |
+
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
|
| 1732 |
+
"dev": true,
|
| 1733 |
+
"dependencies": {
|
| 1734 |
+
"thenify": ">= 3.1.0 < 4"
|
| 1735 |
+
},
|
| 1736 |
+
"engines": {
|
| 1737 |
+
"node": ">=0.8"
|
| 1738 |
+
}
|
| 1739 |
+
},
|
| 1740 |
+
"node_modules/to-regex-range": {
|
| 1741 |
+
"version": "5.0.1",
|
| 1742 |
+
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
| 1743 |
+
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
| 1744 |
+
"dev": true,
|
| 1745 |
+
"dependencies": {
|
| 1746 |
+
"is-number": "^7.0.0"
|
| 1747 |
+
},
|
| 1748 |
+
"engines": {
|
| 1749 |
+
"node": ">=8.0"
|
| 1750 |
+
}
|
| 1751 |
+
},
|
| 1752 |
+
"node_modules/ts-interface-checker": {
|
| 1753 |
+
"version": "0.1.13",
|
| 1754 |
+
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
| 1755 |
+
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
| 1756 |
+
"dev": true
|
| 1757 |
+
},
|
| 1758 |
+
"node_modules/update-browserslist-db": {
|
| 1759 |
+
"version": "1.0.13",
|
| 1760 |
+
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
| 1761 |
+
"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
|
| 1762 |
+
"dev": true,
|
| 1763 |
+
"funding": [
|
| 1764 |
+
{
|
| 1765 |
+
"type": "opencollective",
|
| 1766 |
+
"url": "https://opencollective.com/browserslist"
|
| 1767 |
+
},
|
| 1768 |
+
{
|
| 1769 |
+
"type": "tidelift",
|
| 1770 |
+
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
| 1771 |
+
},
|
| 1772 |
+
{
|
| 1773 |
+
"type": "github",
|
| 1774 |
+
"url": "https://github.com/sponsors/ai"
|
| 1775 |
+
}
|
| 1776 |
+
],
|
| 1777 |
+
"dependencies": {
|
| 1778 |
+
"escalade": "^3.1.1",
|
| 1779 |
+
"picocolors": "^1.0.0"
|
| 1780 |
+
},
|
| 1781 |
+
"bin": {
|
| 1782 |
+
"update-browserslist-db": "cli.js"
|
| 1783 |
+
},
|
| 1784 |
+
"peerDependencies": {
|
| 1785 |
+
"browserslist": ">= 4.21.0"
|
| 1786 |
+
}
|
| 1787 |
+
},
|
| 1788 |
+
"node_modules/util-deprecate": {
|
| 1789 |
+
"version": "1.0.2",
|
| 1790 |
+
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
| 1791 |
+
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
| 1792 |
+
"dev": true
|
| 1793 |
+
},
|
| 1794 |
+
"node_modules/vite": {
|
| 1795 |
+
"version": "4.5.1",
|
| 1796 |
+
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
|
| 1797 |
+
"integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
|
| 1798 |
+
"dev": true,
|
| 1799 |
+
"dependencies": {
|
| 1800 |
+
"esbuild": "^0.18.10",
|
| 1801 |
+
"postcss": "^8.4.27",
|
| 1802 |
+
"rollup": "^3.27.1"
|
| 1803 |
+
},
|
| 1804 |
+
"bin": {
|
| 1805 |
+
"vite": "bin/vite.js"
|
| 1806 |
+
},
|
| 1807 |
+
"engines": {
|
| 1808 |
+
"node": "^14.18.0 || >=16.0.0"
|
| 1809 |
+
},
|
| 1810 |
+
"funding": {
|
| 1811 |
+
"url": "https://github.com/vitejs/vite?sponsor=1"
|
| 1812 |
+
},
|
| 1813 |
+
"optionalDependencies": {
|
| 1814 |
+
"fsevents": "~2.3.2"
|
| 1815 |
+
},
|
| 1816 |
+
"peerDependencies": {
|
| 1817 |
+
"@types/node": ">= 14",
|
| 1818 |
+
"less": "*",
|
| 1819 |
+
"lightningcss": "^1.21.0",
|
| 1820 |
+
"sass": "*",
|
| 1821 |
+
"stylus": "*",
|
| 1822 |
+
"sugarss": "*",
|
| 1823 |
+
"terser": "^5.4.0"
|
| 1824 |
+
},
|
| 1825 |
+
"peerDependenciesMeta": {
|
| 1826 |
+
"@types/node": {
|
| 1827 |
+
"optional": true
|
| 1828 |
+
},
|
| 1829 |
+
"less": {
|
| 1830 |
+
"optional": true
|
| 1831 |
+
},
|
| 1832 |
+
"lightningcss": {
|
| 1833 |
+
"optional": true
|
| 1834 |
+
},
|
| 1835 |
+
"sass": {
|
| 1836 |
+
"optional": true
|
| 1837 |
+
},
|
| 1838 |
+
"stylus": {
|
| 1839 |
+
"optional": true
|
| 1840 |
+
},
|
| 1841 |
+
"sugarss": {
|
| 1842 |
+
"optional": true
|
| 1843 |
+
},
|
| 1844 |
+
"terser": {
|
| 1845 |
+
"optional": true
|
| 1846 |
+
}
|
| 1847 |
+
}
|
| 1848 |
+
},
|
| 1849 |
+
"node_modules/vitefu": {
|
| 1850 |
+
"version": "0.2.4",
|
| 1851 |
+
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.4.tgz",
|
| 1852 |
+
"integrity": "sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==",
|
| 1853 |
+
"dev": true,
|
| 1854 |
+
"peerDependencies": {
|
| 1855 |
+
"vite": "^3.0.0 || ^4.0.0"
|
| 1856 |
+
},
|
| 1857 |
+
"peerDependenciesMeta": {
|
| 1858 |
+
"vite": {
|
| 1859 |
+
"optional": true
|
| 1860 |
+
}
|
| 1861 |
+
}
|
| 1862 |
+
},
|
| 1863 |
+
"node_modules/wrappy": {
|
| 1864 |
+
"version": "1.0.2",
|
| 1865 |
+
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
| 1866 |
+
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
| 1867 |
+
"dev": true
|
| 1868 |
+
},
|
| 1869 |
+
"node_modules/yaml": {
|
| 1870 |
+
"version": "2.3.2",
|
| 1871 |
+
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz",
|
| 1872 |
+
"integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==",
|
| 1873 |
+
"dev": true,
|
| 1874 |
+
"engines": {
|
| 1875 |
+
"node": ">= 14"
|
| 1876 |
+
}
|
| 1877 |
+
}
|
| 1878 |
+
}
|
| 1879 |
+
}
|
front-end/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "bot-ui",
|
| 3 |
+
"private": true,
|
| 4 |
+
"version": "0.0.0",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "vite",
|
| 8 |
+
"build": "vite build",
|
| 9 |
+
"preview": "vite preview"
|
| 10 |
+
},
|
| 11 |
+
"devDependencies": {
|
| 12 |
+
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
| 13 |
+
"autoprefixer": "^10.4.16",
|
| 14 |
+
"postcss": "^8.4.31",
|
| 15 |
+
"svelte": "^4.0.5",
|
| 16 |
+
"tailwindcss": "^3.3.3",
|
| 17 |
+
"vite": "^4.4.12"
|
| 18 |
+
},
|
| 19 |
+
"dependencies": {
|
| 20 |
+
"svelte-markdown": "^0.4.0"
|
| 21 |
+
}
|
| 22 |
+
}
|
front-end/postcss.config.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export default {
|
| 2 |
+
plugins: {
|
| 3 |
+
tailwindcss: {},
|
| 4 |
+
autoprefixer: {},
|
| 5 |
+
},
|
| 6 |
+
}
|
front-end/public/vite.svg
ADDED
|
|
front-end/src/App.svelte
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script>
|
| 2 |
+
import { tick } from "svelte";
|
| 3 |
+
import SvelteMarkdown from "svelte-markdown";
|
| 4 |
+
import botImage from "./assets/images/bot.jpeg";
|
| 5 |
+
import meImage from "./assets/images/me.jpeg";
|
| 6 |
+
import MdLink from "./lib/MdLink.svelte";
|
| 7 |
+
import External from "./lib/External.svelte";
|
| 8 |
+
import { chatStates, chatStore } from "./lib/chat.store.js";
|
| 9 |
+
import Modal from "./lib/Modal.svelte";
|
| 10 |
+
import { generationStore } from "./lib/generation.store";
|
| 11 |
+
|
| 12 |
+
let ragMode = false;
|
| 13 |
+
let question = "How can I calculate age from date of birth in Cypher?";
|
| 14 |
+
let shouldAutoScroll = true;
|
| 15 |
+
let input;
|
| 16 |
+
let senderImages = { bot: botImage, me: meImage };
|
| 17 |
+
let generationModalOpen = false;
|
| 18 |
+
|
| 19 |
+
function send() {
|
| 20 |
+
chatStore.send(question, ragMode);
|
| 21 |
+
question = "";
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
function scrollToBottom(node, _) {
|
| 25 |
+
const scroll = () => node.scrollTo({ top: node.scrollHeight });
|
| 26 |
+
scroll();
|
| 27 |
+
return { update: () => shouldAutoScroll && scroll() };
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
function scrolling(e) {
|
| 31 |
+
shouldAutoScroll = e.target.scrollTop + e.target.clientHeight > e.target.scrollHeight - 55;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
function generateTicket(text) {
|
| 35 |
+
generationStore.generate(text);
|
| 36 |
+
generationModalOpen = true;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
$: $chatStore.state === chatStates.IDLE && input && focus(input);
|
| 40 |
+
async function focus(node) {
|
| 41 |
+
await tick();
|
| 42 |
+
node.focus();
|
| 43 |
+
}
|
| 44 |
+
// send();
|
| 45 |
+
</script>
|
| 46 |
+
|
| 47 |
+
<main class="h-full text-sm bg-gradient-to-t from-indigo-100 bg-fixed overflow-hidden">
|
| 48 |
+
<div on:scroll={scrolling} class="flex h-full flex-col py-12 overflow-y-auto" use:scrollToBottom={$chatStore}>
|
| 49 |
+
<div class="w-4/5 mx-auto flex flex-col mb-32">
|
| 50 |
+
{#each $chatStore.data as message (message.id)}
|
| 51 |
+
<div
|
| 52 |
+
class="max-w-[80%] min-w-[40%] rounded-lg p-4 mb-4 overflow-x-auto bg-white border border-indigo-200"
|
| 53 |
+
class:self-end={message.from === "me"}
|
| 54 |
+
class:text-right={message.from === "me"}
|
| 55 |
+
>
|
| 56 |
+
<div class="flex flex-row gap-2">
|
| 57 |
+
{#if message.from === "me"}
|
| 58 |
+
<button
|
| 59 |
+
aria-label="Generate a new internal ticket from this question"
|
| 60 |
+
title="Generate a new internal ticket from this question"
|
| 61 |
+
on:click={() => generateTicket(message.text)}
|
| 62 |
+
class="w-6 h-6 flex flex-col justify-center items-center border rounded border-indigo-200"
|
| 63 |
+
><External --color="#ccc" --hover-color="#999" /></button
|
| 64 |
+
>
|
| 65 |
+
{/if}
|
| 66 |
+
<div
|
| 67 |
+
class:ml-auto={message.from === "me"}
|
| 68 |
+
class="relative w-12 h-12 border border-indigo-200 rounded flex justify-center items-center overflow-hidden"
|
| 69 |
+
>
|
| 70 |
+
<img src={senderImages[message.from]} alt="" class="rounded-sm" />
|
| 71 |
+
</div>
|
| 72 |
+
{#if message.from === "bot"}
|
| 73 |
+
<div class="text-sm">
|
| 74 |
+
<div>Model: {message.model ? message.model : ""}</div>
|
| 75 |
+
<div>RAG: {message.rag ? "Enabled" : "Disabled"}</div>
|
| 76 |
+
</div>
|
| 77 |
+
{/if}
|
| 78 |
+
</div>
|
| 79 |
+
<div class="mt-4"><SvelteMarkdown source={message.text} renderers={{ link: MdLink }} /></div>
|
| 80 |
+
</div>
|
| 81 |
+
{/each}
|
| 82 |
+
</div>
|
| 83 |
+
<div class="text-sm w-full fixed bottom-16">
|
| 84 |
+
<div class="shadow-lg bg-indigo-50 rounded-lg w-4/5 xl:w-2/3 2xl:w-1/2 mx-auto">
|
| 85 |
+
<div class="rounded-t-lg px-4 py-2 font-light">
|
| 86 |
+
<div class="font-semibold">RAG mode</div>
|
| 87 |
+
<div class="">
|
| 88 |
+
<label class="mr-2">
|
| 89 |
+
<input type="radio" bind:group={ragMode} value={false} /> Disabled
|
| 90 |
+
</label>
|
| 91 |
+
<label>
|
| 92 |
+
<input type="radio" bind:group={ragMode} value={true} /> Enabled
|
| 93 |
+
</label>
|
| 94 |
+
</div>
|
| 95 |
+
</div>
|
| 96 |
+
<form class="rounded-md w-full bg-white p-2 m-0" on:submit|preventDefault={send}>
|
| 97 |
+
<input
|
| 98 |
+
placeholder="What coding related question can I help you with?"
|
| 99 |
+
disabled={$chatStore.state === chatStates.RECEIVING}
|
| 100 |
+
class="text-lg w-full bg-white focus:outline-none px-4"
|
| 101 |
+
bind:value={question}
|
| 102 |
+
bind:this={input}
|
| 103 |
+
type="text"
|
| 104 |
+
/>
|
| 105 |
+
</form>
|
| 106 |
+
</div>
|
| 107 |
+
</div>
|
| 108 |
+
</div>
|
| 109 |
+
</main>
|
| 110 |
+
{#if generationModalOpen}
|
| 111 |
+
<Modal title="my title" text="my text" on:close={() => (generationModalOpen = false)} />
|
| 112 |
+
{/if}
|
| 113 |
+
|
| 114 |
+
<style>
|
| 115 |
+
:global(pre) {
|
| 116 |
+
@apply bg-gray-100 rounded-lg p-4 border border-indigo-200;
|
| 117 |
+
}
|
| 118 |
+
:global(code) {
|
| 119 |
+
@apply text-indigo-500;
|
| 120 |
+
}
|
| 121 |
+
</style>
|
front-end/src/app.css
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@tailwind base;
|
| 2 |
+
@tailwind components;
|
| 3 |
+
@tailwind utilities;
|
| 4 |
+
|
| 5 |
+
body {
|
| 6 |
+
margin: 0;
|
| 7 |
+
min-width: 320px;
|
| 8 |
+
height: 100dvh;
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
#app {
|
| 12 |
+
height: 100%;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
pre {
|
| 16 |
+
line-height: 1;
|
| 17 |
+
background-color: rgb(241, 241, 241);
|
| 18 |
+
padding: 4px 8px 8px;
|
| 19 |
+
border: 1px solid #ccc;
|
| 20 |
+
overflow-x: auto;
|
| 21 |
+
margin: 0 4px;
|
| 22 |
+
border-radius: 2px;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
ol {
|
| 26 |
+
padding: 1em;
|
| 27 |
+
list-style: decimal;
|
| 28 |
+
}
|
front-end/src/assets/images/bot.jpeg
ADDED
|
front-end/src/assets/images/me.jpeg
ADDED
|
front-end/src/assets/svelte.svg
ADDED
|
|
front-end/src/lib/External.svelte
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div class="w-full h-full">
|
| 2 |
+
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"
|
| 3 |
+
><g id="SVGRepo_bgCarrier" stroke-width="0" /><g
|
| 4 |
+
id="SVGRepo_tracerCarrier"
|
| 5 |
+
stroke-linecap="round"
|
| 6 |
+
stroke-linejoin="round"
|
| 7 |
+
/><g id="SVGRepo_iconCarrier">
|
| 8 |
+
<g id="Interface / External_Link">
|
| 9 |
+
<path
|
| 10 |
+
id="Vector"
|
| 11 |
+
d="M10.0002 5H8.2002C7.08009 5 6.51962 5 6.0918 5.21799C5.71547 5.40973 5.40973 5.71547 5.21799 6.0918C5 6.51962 5 7.08009 5 8.2002V15.8002C5 16.9203 5 17.4801 5.21799 17.9079C5.40973 18.2842 5.71547 18.5905 6.0918 18.7822C6.5192 19 7.07899 19 8.19691 19H15.8031C16.921 19 17.48 19 17.9074 18.7822C18.2837 18.5905 18.5905 18.2839 18.7822 17.9076C19 17.4802 19 16.921 19 15.8031V14M20 9V4M20 4H15M20 4L13 11"
|
| 12 |
+
stroke-width="1"
|
| 13 |
+
stroke-linecap="round"
|
| 14 |
+
stroke-linejoin="round"
|
| 15 |
+
/>
|
| 16 |
+
</g>
|
| 17 |
+
</g></svg
|
| 18 |
+
>
|
| 19 |
+
</div>
|
| 20 |
+
|
| 21 |
+
<style>
|
| 22 |
+
svg {
|
| 23 |
+
stroke: var(--color, #000);
|
| 24 |
+
}
|
| 25 |
+
svg:hover {
|
| 26 |
+
stroke: var(--hover-color, #000);
|
| 27 |
+
}
|
| 28 |
+
</style>
|
front-end/src/lib/MdLink.svelte
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script>
|
| 2 |
+
export let href = "";
|
| 3 |
+
export let title = "";
|
| 4 |
+
export let text = "";
|
| 5 |
+
</script>
|
| 6 |
+
|
| 7 |
+
<a target="_blank" rel="noreferrer" {href} {title}>{text}</a>
|
| 8 |
+
|
| 9 |
+
<style>
|
| 10 |
+
a {
|
| 11 |
+
color: #007bff;
|
| 12 |
+
text-decoration: none;
|
| 13 |
+
}
|
| 14 |
+
</style>
|
front-end/src/lib/Modal.svelte
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script>
|
| 2 |
+
import { createEventDispatcher, onMount } from "svelte";
|
| 3 |
+
import { generationStates, generationStore } from "./generation.store";
|
| 4 |
+
|
| 5 |
+
/** @type {HTMLDialogElement | undefined}*/
|
| 6 |
+
let modal;
|
| 7 |
+
|
| 8 |
+
const dispatch = createEventDispatcher();
|
| 9 |
+
|
| 10 |
+
onMount(() => {
|
| 11 |
+
modal.showModal();
|
| 12 |
+
modal.addEventListener("close", onClose);
|
| 13 |
+
return () => modal.removeEventListener("close", onClose);
|
| 14 |
+
});
|
| 15 |
+
|
| 16 |
+
function onClose() {
|
| 17 |
+
dispatch("close");
|
| 18 |
+
}
|
| 19 |
+
</script>
|
| 20 |
+
|
| 21 |
+
<dialog
|
| 22 |
+
bind:this={modal}
|
| 23 |
+
class="inset-0 w-full md:w-1/2 h-1/2 p-4 rounded-lg border border-indigo-200 shadow-lg relative"
|
| 24 |
+
>
|
| 25 |
+
<form class="flex flex-col justify-between h-full" method="dialog">
|
| 26 |
+
<div class="flex flex-col">
|
| 27 |
+
<h1 class="text-2xl">Create new internal ticket</h1>
|
| 28 |
+
<div>
|
| 29 |
+
<label class="block pl-2"
|
| 30 |
+
>Title <br />
|
| 31 |
+
<input type="text" class="border w-full text-lg px-2" value={$generationStore.data.title} /></label
|
| 32 |
+
>
|
| 33 |
+
</div>
|
| 34 |
+
<div class="mt-8">
|
| 35 |
+
<label class="block pl-2"
|
| 36 |
+
>Body <br />
|
| 37 |
+
<textarea class="border rounded-sm w-full h-64 p-2" value={$generationStore.data.text} /></label
|
| 38 |
+
>
|
| 39 |
+
</div>
|
| 40 |
+
</div>
|
| 41 |
+
<button type="submit" class="bg-indigo-500 text-white rounded-lg px-4 py-2">Submit</button>
|
| 42 |
+
</form>
|
| 43 |
+
{#if $generationStore.state === generationStates.LOADING}
|
| 44 |
+
<div class="absolute inset-0 bg-indigo-100 bg-opacity-90 flex justify-center items-center">
|
| 45 |
+
Generating title and question body...
|
| 46 |
+
</div>
|
| 47 |
+
{/if}
|
| 48 |
+
<div class="absolute top-0 right-2 text-gray-300 hover:text-gray-900">
|
| 49 |
+
<button class="text-2xl" on:click={onClose}>×</button>
|
| 50 |
+
</div>
|
| 51 |
+
</dialog>
|
| 52 |
+
|
| 53 |
+
<style>
|
| 54 |
+
dialog::backdrop {
|
| 55 |
+
@apply bg-gradient-to-t from-white to-indigo-500;
|
| 56 |
+
opacity: 0.75;
|
| 57 |
+
}
|
| 58 |
+
</style>
|
front-end/src/lib/chat.store.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { writable } from "svelte/store";
|
| 2 |
+
|
| 3 |
+
const API_ENDPOINT = "http://localhost:8504/query-stream";
|
| 4 |
+
|
| 5 |
+
export const chatStates = {
|
| 6 |
+
IDLE: "idle",
|
| 7 |
+
RECEIVING: "receiving",
|
| 8 |
+
};
|
| 9 |
+
|
| 10 |
+
function createChatStore() {
|
| 11 |
+
const { subscribe, update } = writable({ state: chatStates.IDLE, data: [] });
|
| 12 |
+
|
| 13 |
+
function addMessage(from, text, rag) {
|
| 14 |
+
const newId = Math.random().toString(36).substring(2, 9);
|
| 15 |
+
update((state) => {
|
| 16 |
+
const message = { id: newId, from, text, rag };
|
| 17 |
+
state.data.push(message);
|
| 18 |
+
return state;
|
| 19 |
+
});
|
| 20 |
+
return newId;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
function updateMessage(existingId, text, model = null) {
|
| 24 |
+
if (!existingId) {
|
| 25 |
+
return;
|
| 26 |
+
}
|
| 27 |
+
update((state) => {
|
| 28 |
+
const messages = state.data;
|
| 29 |
+
const existingIdIndex = messages.findIndex((m) => m.id === existingId);
|
| 30 |
+
if (existingIdIndex === -1) {
|
| 31 |
+
return state;
|
| 32 |
+
}
|
| 33 |
+
messages[existingIdIndex].text += text;
|
| 34 |
+
if (model) {
|
| 35 |
+
messages[existingIdIndex].model = model;
|
| 36 |
+
}
|
| 37 |
+
return { ...state, data: messages };
|
| 38 |
+
});
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
async function send(question, ragMode = false) {
|
| 42 |
+
if (!question.trim().length) {
|
| 43 |
+
return;
|
| 44 |
+
}
|
| 45 |
+
update((state) => ({ ...state, state: chatStates.RECEIVING }));
|
| 46 |
+
addMessage("me", question, ragMode);
|
| 47 |
+
const messageId = addMessage("bot", "", ragMode);
|
| 48 |
+
try {
|
| 49 |
+
const evt = new EventSource(`${API_ENDPOINT}?text=${encodeURI(question)}&rag=${ragMode}`);
|
| 50 |
+
question = "";
|
| 51 |
+
evt.onmessage = (e) => {
|
| 52 |
+
if (e.data) {
|
| 53 |
+
const data = JSON.parse(e.data);
|
| 54 |
+
if (data.init) {
|
| 55 |
+
updateMessage(messageId, "", data.model);
|
| 56 |
+
return;
|
| 57 |
+
}
|
| 58 |
+
updateMessage(messageId, data.token);
|
| 59 |
+
}
|
| 60 |
+
};
|
| 61 |
+
evt.onerror = (e) => {
|
| 62 |
+
// Stream will end with an error
|
| 63 |
+
// and we want to close the connection on end (otherwise it will keep reconnecting)
|
| 64 |
+
evt.close();
|
| 65 |
+
update((state) => ({ ...state, state: chatStates.IDLE }));
|
| 66 |
+
};
|
| 67 |
+
} catch (e) {
|
| 68 |
+
updateMessage(messageId, "Error: " + e.message);
|
| 69 |
+
update((state) => ({ ...state, state: chatStates.IDLE }));
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
return {
|
| 74 |
+
subscribe,
|
| 75 |
+
send,
|
| 76 |
+
};
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
export const chatStore = createChatStore();
|
front-end/src/lib/generation.store.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { writable } from "svelte/store";
|
| 2 |
+
|
| 3 |
+
const API_ENDPOINT = "http://localhost:8504/generate-ticket";
|
| 4 |
+
|
| 5 |
+
export const generationStates = {
|
| 6 |
+
IDLE: "idle",
|
| 7 |
+
SUCCESS: "success",
|
| 8 |
+
ERROR: "error",
|
| 9 |
+
LOADING: "loading",
|
| 10 |
+
};
|
| 11 |
+
|
| 12 |
+
function createGenerationStore() {
|
| 13 |
+
const { subscribe, update } = writable({ state: generationStates.IDLE, data: { title: "", text: "" } });
|
| 14 |
+
|
| 15 |
+
return {
|
| 16 |
+
subscribe,
|
| 17 |
+
generate: async (fromQuestion) => {
|
| 18 |
+
update(() => ({ state: generationStates.LOADING, data: { title: "", text: "" } }));
|
| 19 |
+
try {
|
| 20 |
+
const response = await fetch(`${API_ENDPOINT}?text=${encodeURI(fromQuestion)}`, {
|
| 21 |
+
method: "GET",
|
| 22 |
+
});
|
| 23 |
+
const generation = await response.json();
|
| 24 |
+
update(() => ({ state: generationStates.SUCCESS, data: generation.result }));
|
| 25 |
+
} catch (e) {
|
| 26 |
+
console.log("e: ", e);
|
| 27 |
+
update(() => ({ state: generationStates.ERROR, data: { title: "", text: "" } }));
|
| 28 |
+
}
|
| 29 |
+
},
|
| 30 |
+
};
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
export const generationStore = createGenerationStore();
|
front-end/src/main.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import './app.css'
|
| 2 |
+
import App from './App.svelte'
|
| 3 |
+
|
| 4 |
+
const app = new App({
|
| 5 |
+
target: document.getElementById('app'),
|
| 6 |
+
})
|
| 7 |
+
|
| 8 |
+
export default app
|
front-end/src/vite-env.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/// <reference types="svelte" />
|
| 2 |
+
/// <reference types="vite/client" />
|
front-end/svelte.config.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
|
| 2 |
+
|
| 3 |
+
export default {
|
| 4 |
+
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
|
| 5 |
+
// for more information about preprocessors
|
| 6 |
+
preprocess: vitePreprocess(),
|
| 7 |
+
}
|
front-end/tailwind.config.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** @type {import('tailwindcss').Config} */
|
| 2 |
+
export default {
|
| 3 |
+
content: [
|
| 4 |
+
"./index.html",
|
| 5 |
+
"./src/**/*.{svelte,js,ts,jsx,tsx}",
|
| 6 |
+
],
|
| 7 |
+
theme: {
|
| 8 |
+
extend: {},
|
| 9 |
+
},
|
| 10 |
+
plugins: [],
|
| 11 |
+
}
|
| 12 |
+
|
front-end/vite.config.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defineConfig } from 'vite'
|
| 2 |
+
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
| 3 |
+
|
| 4 |
+
// https://vitejs.dev/config/
|
| 5 |
+
export default defineConfig({
|
| 6 |
+
server: {
|
| 7 |
+
host: '0.0.0.0',
|
| 8 |
+
port: 8505,
|
| 9 |
+
},
|
| 10 |
+
plugins: [svelte()],
|
| 11 |
+
})
|
images/datamodel.png
ADDED
|
install_ollama.sh
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
# This script installs Ollama on Linux.
|
| 3 |
+
# It detects the current operating system architecture and installs the appropriate version of Ollama.
|
| 4 |
+
|
| 5 |
+
set -eu
|
| 6 |
+
|
| 7 |
+
status() { echo ">>> $*" >&2; }
|
| 8 |
+
error() { echo "ERROR $*"; exit 1; }
|
| 9 |
+
warning() { echo "WARNING: $*"; }
|
| 10 |
+
|
| 11 |
+
TEMP_DIR=$(mktemp -d)
|
| 12 |
+
cleanup() { rm -rf $TEMP_DIR; }
|
| 13 |
+
trap cleanup EXIT
|
| 14 |
+
|
| 15 |
+
available() { command -v $1 >/dev/null; }
|
| 16 |
+
require() {
|
| 17 |
+
local MISSING=''
|
| 18 |
+
for TOOL in $*; do
|
| 19 |
+
if ! available $TOOL; then
|
| 20 |
+
MISSING="$MISSING $TOOL"
|
| 21 |
+
fi
|
| 22 |
+
done
|
| 23 |
+
|
| 24 |
+
echo $MISSING
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
[ "$(uname -s)" = "Linux" ] || error 'This script is intended to run on Linux only.'
|
| 28 |
+
|
| 29 |
+
case "$(uname -m)" in
|
| 30 |
+
x86_64) ARCH="amd64" ;;
|
| 31 |
+
aarch64|arm64) ARCH="arm64" ;;
|
| 32 |
+
*) error "Unsupported architecture: $ARCH" ;;
|
| 33 |
+
esac
|
| 34 |
+
|
| 35 |
+
SUDO=
|
| 36 |
+
if [ "$(id -u)" -ne 0 ]; then
|
| 37 |
+
# Running as root, no need for sudo
|
| 38 |
+
if ! available sudo; then
|
| 39 |
+
error "This script requires superuser permissions. Please re-run as root."
|
| 40 |
+
fi
|
| 41 |
+
|
| 42 |
+
SUDO="sudo"
|
| 43 |
+
fi
|
| 44 |
+
|
| 45 |
+
NEEDS=$(require curl awk grep sed tee xargs)
|
| 46 |
+
if [ -n "$NEEDS" ]; then
|
| 47 |
+
status "ERROR: The following tools are required but missing:"
|
| 48 |
+
for NEED in $NEEDS; do
|
| 49 |
+
echo " - $NEED"
|
| 50 |
+
done
|
| 51 |
+
exit 1
|
| 52 |
+
fi
|
| 53 |
+
|
| 54 |
+
status "Downloading ollama..."
|
| 55 |
+
curl --fail --show-error --location --progress-bar -o $TEMP_DIR/ollama "https://ollama.ai/download/ollama-linux-$ARCH"
|
| 56 |
+
|
| 57 |
+
for BINDIR in /usr/local/bin /usr/bin /bin; do
|
| 58 |
+
echo $PATH | grep -q $BINDIR && break || continue
|
| 59 |
+
done
|
| 60 |
+
|
| 61 |
+
status "Installing ollama to $BINDIR..."
|
| 62 |
+
$SUDO install -o0 -g0 -m755 -d $BINDIR
|
| 63 |
+
$SUDO install -o0 -g0 -m755 $TEMP_DIR/ollama $BINDIR/ollama
|
| 64 |
+
|
| 65 |
+
install_success() { status 'Install complete. Run "ollama" from the command line.'; }
|
| 66 |
+
trap install_success EXIT
|
| 67 |
+
|
| 68 |
+
# Everything from this point onwards is optional.
|
| 69 |
+
|
| 70 |
+
configure_systemd() {
|
| 71 |
+
if ! id ollama >/dev/null 2>&1; then
|
| 72 |
+
status "Creating ollama user..."
|
| 73 |
+
$SUDO useradd -r -s /bin/false -m -d /usr/share/ollama ollama
|
| 74 |
+
fi
|
| 75 |
+
|
| 76 |
+
status "Creating ollama systemd service..."
|
| 77 |
+
cat <<EOF | $SUDO tee /etc/systemd/system/ollama.service >/dev/null
|
| 78 |
+
[Unit]
|
| 79 |
+
Description=Ollama Service
|
| 80 |
+
After=network-online.target
|
| 81 |
+
|
| 82 |
+
[Service]
|
| 83 |
+
ExecStart=$BINDIR/ollama serve
|
| 84 |
+
User=ollama
|
| 85 |
+
Group=ollama
|
| 86 |
+
Restart=always
|
| 87 |
+
RestartSec=3
|
| 88 |
+
Environment="HOME=/usr/share/ollama"
|
| 89 |
+
Environment="PATH=$PATH"
|
| 90 |
+
|
| 91 |
+
[Install]
|
| 92 |
+
WantedBy=default.target
|
| 93 |
+
EOF
|
| 94 |
+
SYSTEMCTL_RUNNING="$(systemctl is-system-running || true)"
|
| 95 |
+
case $SYSTEMCTL_RUNNING in
|
| 96 |
+
running|degraded)
|
| 97 |
+
status "Enabling and starting ollama service..."
|
| 98 |
+
$SUDO systemctl daemon-reload
|
| 99 |
+
$SUDO systemctl enable ollama
|
| 100 |
+
|
| 101 |
+
start_service() { $SUDO systemctl restart ollama; }
|
| 102 |
+
trap start_service EXIT
|
| 103 |
+
;;
|
| 104 |
+
esac
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
if available systemctl; then
|
| 108 |
+
configure_systemd
|
| 109 |
+
fi
|
| 110 |
+
|
| 111 |
+
if ! available lspci && ! available lshw; then
|
| 112 |
+
warning "Unable to detect NVIDIA GPU. Install lspci or lshw to automatically detect and install NVIDIA CUDA drivers."
|
| 113 |
+
exit 0
|
| 114 |
+
fi
|
| 115 |
+
|
| 116 |
+
check_gpu() {
|
| 117 |
+
case $1 in
|
| 118 |
+
lspci) available lspci && lspci -d '10de:' | grep -q 'NVIDIA' || return 1 ;;
|
| 119 |
+
lshw) available lshw && $SUDO lshw -c display -numeric | grep -q 'vendor: .* \[10DE\]' || return 1 ;;
|
| 120 |
+
nvidia-smi) available nvidia-smi || return 1 ;;
|
| 121 |
+
esac
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
if check_gpu nvidia-smi; then
|
| 125 |
+
status "NVIDIA GPU installed."
|
| 126 |
+
exit 0
|
| 127 |
+
fi
|
| 128 |
+
|
| 129 |
+
if ! check_gpu lspci && ! check_gpu lshw; then
|
| 130 |
+
warning "No NVIDIA GPU detected. Ollama will run in CPU-only mode."
|
| 131 |
+
exit 0
|
| 132 |
+
fi
|
| 133 |
+
|
| 134 |
+
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#rhel-7-centos-7
|
| 135 |
+
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#rhel-8-rocky-8
|
| 136 |
+
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#rhel-9-rocky-9
|
| 137 |
+
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#fedora
|
| 138 |
+
install_cuda_driver_yum() {
|
| 139 |
+
status 'Installing NVIDIA repository...'
|
| 140 |
+
case $PACKAGE_MANAGER in
|
| 141 |
+
yum)
|
| 142 |
+
$SUDO $PACKAGE_MANAGER -y install yum-utils
|
| 143 |
+
$SUDO $PACKAGE_MANAGER-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m)/cuda-$1$2.repo
|
| 144 |
+
;;
|
| 145 |
+
dnf)
|
| 146 |
+
$SUDO $PACKAGE_MANAGER config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m)/cuda-$1$2.repo
|
| 147 |
+
;;
|
| 148 |
+
esac
|
| 149 |
+
|
| 150 |
+
case $1 in
|
| 151 |
+
rhel)
|
| 152 |
+
status 'Installing EPEL repository...'
|
| 153 |
+
# EPEL is required for third-party dependencies such as dkms and libvdpau
|
| 154 |
+
$SUDO $PACKAGE_MANAGER -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-$2.noarch.rpm || true
|
| 155 |
+
;;
|
| 156 |
+
esac
|
| 157 |
+
|
| 158 |
+
status 'Installing CUDA driver...'
|
| 159 |
+
|
| 160 |
+
if [ "$1" = 'centos' ] || [ "$1$2" = 'rhel7' ]; then
|
| 161 |
+
$SUDO $PACKAGE_MANAGER -y install nvidia-driver-latest-dkms
|
| 162 |
+
fi
|
| 163 |
+
|
| 164 |
+
$SUDO $PACKAGE_MANAGER -y install cuda-drivers
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#ubuntu
|
| 168 |
+
# ref: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#debian
|
| 169 |
+
install_cuda_driver_apt() {
|
| 170 |
+
status 'Installing NVIDIA repository...'
|
| 171 |
+
curl -fsSL -o $TEMP_DIR/cuda-keyring.deb https://developer.download.nvidia.com/compute/cuda/repos/$1$2/$(uname -m)/cuda-keyring_1.1-1_all.deb
|
| 172 |
+
|
| 173 |
+
case $1 in
|
| 174 |
+
debian)
|
| 175 |
+
status 'Enabling contrib sources...'
|
| 176 |
+
$SUDO sed 's/main/contrib/' < /etc/apt/sources.list | sudo tee /etc/apt/sources.list.d/contrib.list > /dev/null
|
| 177 |
+
;;
|
| 178 |
+
esac
|
| 179 |
+
|
| 180 |
+
status 'Installing CUDA driver...'
|
| 181 |
+
$SUDO dpkg -i $TEMP_DIR/cuda-keyring.deb
|
| 182 |
+
$SUDO apt-get update
|
| 183 |
+
|
| 184 |
+
[ -n "$SUDO" ] && SUDO_E="$SUDO -E" || SUDO_E=
|
| 185 |
+
DEBIAN_FRONTEND=noninteractive $SUDO_E apt-get -y install cuda-drivers -q
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
if [ ! -f "/etc/os-release" ]; then
|
| 189 |
+
error "Unknown distribution. Skipping CUDA installation."
|
| 190 |
+
fi
|
| 191 |
+
|
| 192 |
+
. /etc/os-release
|
| 193 |
+
|
| 194 |
+
OS_NAME=$ID
|
| 195 |
+
OS_VERSION=$VERSION_ID
|
| 196 |
+
|
| 197 |
+
PACKAGE_MANAGER=
|
| 198 |
+
for PACKAGE_MANAGER in dnf yum apt-get; do
|
| 199 |
+
if available $PACKAGE_MANAGER; then
|
| 200 |
+
break
|
| 201 |
+
fi
|
| 202 |
+
done
|
| 203 |
+
|
| 204 |
+
if [ -z "$PACKAGE_MANAGER" ]; then
|
| 205 |
+
error "Unknown package manager. Skipping CUDA installation."
|
| 206 |
+
fi
|
| 207 |
+
|
| 208 |
+
if ! check_gpu nvidia-smi || [ -z "$(nvidia-smi | grep -o "CUDA Version: [0-9]*\.[0-9]*")" ]; then
|
| 209 |
+
case $OS_NAME in
|
| 210 |
+
centos|rhel) install_cuda_driver_yum 'rhel' $OS_VERSION ;;
|
| 211 |
+
rocky) install_cuda_driver_yum 'rhel' $(echo $OS_VERSION | cut -c1) ;;
|
| 212 |
+
fedora) install_cuda_driver_yum $OS_NAME $OS_VERSION ;;
|
| 213 |
+
amzn) install_cuda_driver_yum 'fedora' '35' ;;
|
| 214 |
+
debian) install_cuda_driver_apt $OS_NAME $OS_VERSION ;;
|
| 215 |
+
ubuntu) install_cuda_driver_apt $OS_NAME $(echo $OS_VERSION | sed 's/\.//') ;;
|
| 216 |
+
*) exit ;;
|
| 217 |
+
esac
|
| 218 |
+
fi
|
| 219 |
+
|
| 220 |
+
if ! lsmod | grep -q nvidia; then
|
| 221 |
+
KERNEL_RELEASE="$(uname -r)"
|
| 222 |
+
case $OS_NAME in
|
| 223 |
+
centos|rhel|rocky|amzn) $SUDO $PACKAGE_MANAGER -y install kernel-devel-$KERNEL_RELEASE kernel-headers-$KERNEL_RELEASE ;;
|
| 224 |
+
fedora) $SUDO $PACKAGE_MANAGER -y install kernel-devel-$KERNEL_RELEASE ;;
|
| 225 |
+
debian|ubuntu) $SUDO apt-get -y install linux-headers-$KERNEL_RELEASE ;;
|
| 226 |
+
*) exit ;;
|
| 227 |
+
esac
|
| 228 |
+
|
| 229 |
+
NVIDIA_CUDA_VERSION=$($SUDO dkms status | awk -F: '/added/ { print $1 }')
|
| 230 |
+
if [ -n "$NVIDIA_CUDA_VERSION" ]; then
|
| 231 |
+
$SUDO dkms install $NVIDIA_CUDA_VERSION
|
| 232 |
+
fi
|
| 233 |
+
|
| 234 |
+
if lsmod | grep -q nouveau; then
|
| 235 |
+
status 'Reboot to complete NVIDIA CUDA driver install.'
|
| 236 |
+
exit 0
|
| 237 |
+
fi
|
| 238 |
+
|
| 239 |
+
$SUDO modprobe nvidia
|
| 240 |
+
fi
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
status "NVIDIA CUDA drivers installed."
|
loader.Dockerfile
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM langchain/langchain
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
RUN apt-get update && apt-get install -y \
|
| 6 |
+
build-essential \
|
| 7 |
+
curl \
|
| 8 |
+
software-properties-common \
|
| 9 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
+
|
| 11 |
+
COPY requirements.txt .
|
| 12 |
+
|
| 13 |
+
RUN pip install --upgrade -r requirements.txt
|
| 14 |
+
|
| 15 |
+
COPY loader.py .
|
| 16 |
+
COPY utils.py .
|
| 17 |
+
COPY chains.py .
|
| 18 |
+
COPY images ./images
|
| 19 |
+
|
| 20 |
+
EXPOSE 8502
|
| 21 |
+
|
| 22 |
+
HEALTHCHECK CMD curl --fail http://localhost:8502/_stcore/health
|
| 23 |
+
|
| 24 |
+
ENTRYPOINT ["streamlit", "run", "loader.py", "--server.port=8502", "--server.address=0.0.0.0"]
|
loader.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import requests
|
| 3 |
+
from dotenv import load_dotenv
|
| 4 |
+
from langchain_community.graphs import Neo4jGraph
|
| 5 |
+
import streamlit as st
|
| 6 |
+
from streamlit.logger import get_logger
|
| 7 |
+
from chains import load_embedding_model
|
| 8 |
+
from utils import create_constraints, create_vector_index
|
| 9 |
+
from PIL import Image
|
| 10 |
+
|
| 11 |
+
load_dotenv(".env")
|
| 12 |
+
|
| 13 |
+
url = os.getenv("NEO4J_URI")
|
| 14 |
+
username = os.getenv("NEO4J_USERNAME")
|
| 15 |
+
password = os.getenv("NEO4J_PASSWORD")
|
| 16 |
+
ollama_base_url = os.getenv("OLLAMA_BASE_URL")
|
| 17 |
+
embedding_model_name = os.getenv("EMBEDDING_MODEL")
|
| 18 |
+
# Remapping for Langchain Neo4j integration
|
| 19 |
+
os.environ["NEO4J_URL"] = url
|
| 20 |
+
|
| 21 |
+
logger = get_logger(__name__)
|
| 22 |
+
|
| 23 |
+
so_api_base_url = "https://api.stackexchange.com/2.3/search/advanced"
|
| 24 |
+
|
| 25 |
+
embeddings, dimension = load_embedding_model(
|
| 26 |
+
embedding_model_name, config={"ollama_base_url": ollama_base_url}, logger=logger
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
# if Neo4j is local, you can go to http://localhost:7474/ to browse the database
|
| 30 |
+
neo4j_graph = Neo4jGraph(
|
| 31 |
+
url=url, username=username, password=password, refresh_schema=False
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
create_constraints(neo4j_graph)
|
| 35 |
+
create_vector_index(neo4j_graph)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def load_so_data(tag: str = "neo4j", page: int = 1) -> None:
|
| 39 |
+
parameters = (
|
| 40 |
+
f"?pagesize=100&page={page}&order=desc&sort=creation&answers=1&tagged={tag}"
|
| 41 |
+
"&site=stackoverflow&filter=!*236eb_eL9rai)MOSNZ-6D3Q6ZKb0buI*IVotWaTb"
|
| 42 |
+
)
|
| 43 |
+
data = requests.get(so_api_base_url + parameters).json()
|
| 44 |
+
insert_so_data(data)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def load_high_score_so_data() -> None:
|
| 48 |
+
parameters = (
|
| 49 |
+
f"?fromdate=1664150400&order=desc&sort=votes&site=stackoverflow&"
|
| 50 |
+
"filter=!.DK56VBPooplF.)bWW5iOX32Fh1lcCkw1b_Y6Zkb7YD8.ZMhrR5.FRRsR6Z1uK8*Z5wPaONvyII"
|
| 51 |
+
)
|
| 52 |
+
data = requests.get(so_api_base_url + parameters).json()
|
| 53 |
+
insert_so_data(data)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def insert_so_data(data: dict) -> None:
|
| 57 |
+
# Calculate embedding values for questions and answers
|
| 58 |
+
for q in data["items"]:
|
| 59 |
+
question_text = q["title"] + "\n" + q["body_markdown"]
|
| 60 |
+
q["embedding"] = embeddings.embed_query(question_text)
|
| 61 |
+
for a in q["answers"]:
|
| 62 |
+
a["embedding"] = embeddings.embed_query(
|
| 63 |
+
question_text + "\n" + a["body_markdown"]
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
# Cypher, the query language of Neo4j, is used to import the data
|
| 67 |
+
# https://neo4j.com/docs/getting-started/cypher-intro/
|
| 68 |
+
# https://neo4j.com/docs/cypher-cheat-sheet/5/auradb-enterprise/
|
| 69 |
+
import_query = """
|
| 70 |
+
UNWIND $data AS q
|
| 71 |
+
MERGE (question:Question {id:q.question_id})
|
| 72 |
+
ON CREATE SET question.title = q.title, question.link = q.link, question.score = q.score,
|
| 73 |
+
question.favorite_count = q.favorite_count, question.creation_date = datetime({epochSeconds: q.creation_date}),
|
| 74 |
+
question.body = q.body_markdown, question.embedding = q.embedding
|
| 75 |
+
FOREACH (tagName IN q.tags |
|
| 76 |
+
MERGE (tag:Tag {name:tagName})
|
| 77 |
+
MERGE (question)-[:TAGGED]->(tag)
|
| 78 |
+
)
|
| 79 |
+
FOREACH (a IN q.answers |
|
| 80 |
+
MERGE (question)<-[:ANSWERS]-(answer:Answer {id:a.answer_id})
|
| 81 |
+
SET answer.is_accepted = a.is_accepted,
|
| 82 |
+
answer.score = a.score,
|
| 83 |
+
answer.creation_date = datetime({epochSeconds:a.creation_date}),
|
| 84 |
+
answer.body = a.body_markdown,
|
| 85 |
+
answer.embedding = a.embedding
|
| 86 |
+
MERGE (answerer:User {id:coalesce(a.owner.user_id, "deleted")})
|
| 87 |
+
ON CREATE SET answerer.display_name = a.owner.display_name,
|
| 88 |
+
answerer.reputation= a.owner.reputation
|
| 89 |
+
MERGE (answer)<-[:PROVIDED]-(answerer)
|
| 90 |
+
)
|
| 91 |
+
WITH * WHERE NOT q.owner.user_id IS NULL
|
| 92 |
+
MERGE (owner:User {id:q.owner.user_id})
|
| 93 |
+
ON CREATE SET owner.display_name = q.owner.display_name,
|
| 94 |
+
owner.reputation = q.owner.reputation
|
| 95 |
+
MERGE (owner)-[:ASKED]->(question)
|
| 96 |
+
"""
|
| 97 |
+
neo4j_graph.query(import_query, {"data": data["items"]})
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
# Streamlit
|
| 101 |
+
def get_tag() -> str:
|
| 102 |
+
input_text = st.text_input(
|
| 103 |
+
"Which tag questions do you want to import?", value="neo4j"
|
| 104 |
+
)
|
| 105 |
+
return input_text
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def get_pages():
|
| 109 |
+
col1, col2 = st.columns(2)
|
| 110 |
+
with col1:
|
| 111 |
+
num_pages = st.number_input(
|
| 112 |
+
"Number of pages (100 questions per page)", step=1, min_value=1
|
| 113 |
+
)
|
| 114 |
+
with col2:
|
| 115 |
+
start_page = st.number_input("Start page", step=1, min_value=1)
|
| 116 |
+
st.caption("Only questions with answers will be imported.")
|
| 117 |
+
return (int(num_pages), int(start_page))
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def render_page():
|
| 121 |
+
datamodel_image = Image.open("./images/datamodel.png")
|
| 122 |
+
st.header("StackOverflow Loader")
|
| 123 |
+
st.subheader("Choose StackOverflow tags to load into Neo4j")
|
| 124 |
+
st.caption("Go to http://localhost:7474/ to explore the graph.")
|
| 125 |
+
|
| 126 |
+
user_input = get_tag()
|
| 127 |
+
num_pages, start_page = get_pages()
|
| 128 |
+
|
| 129 |
+
if st.button("Import", type="primary"):
|
| 130 |
+
with st.spinner("Loading... This might take a minute or two."):
|
| 131 |
+
try:
|
| 132 |
+
for page in range(1, num_pages + 1):
|
| 133 |
+
load_so_data(user_input, start_page + (page - 1))
|
| 134 |
+
st.success("Import successful", icon="✅")
|
| 135 |
+
st.caption("Data model")
|
| 136 |
+
st.image(datamodel_image)
|
| 137 |
+
st.caption("Go to http://localhost:7474/ to interact with the database")
|
| 138 |
+
except Exception as e:
|
| 139 |
+
st.error(f"Error: {e}", icon="🚨")
|
| 140 |
+
with st.expander("Highly ranked questions rather than tags?"):
|
| 141 |
+
if st.button("Import highly ranked questions"):
|
| 142 |
+
with st.spinner("Loading... This might take a minute or two."):
|
| 143 |
+
try:
|
| 144 |
+
load_high_score_so_data()
|
| 145 |
+
st.success("Import successful", icon="✅")
|
| 146 |
+
except Exception as e:
|
| 147 |
+
st.error(f"Error: {e}", icon="🚨")
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
render_page()
|
pdf_bot.Dockerfile
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM langchain/langchain
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
RUN apt-get update && apt-get install -y \
|
| 6 |
+
build-essential \
|
| 7 |
+
curl \
|
| 8 |
+
software-properties-common \
|
| 9 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
+
|
| 11 |
+
COPY requirements.txt .
|
| 12 |
+
|
| 13 |
+
RUN pip install --upgrade -r requirements.txt
|
| 14 |
+
|
| 15 |
+
COPY pdf_bot.py .
|
| 16 |
+
COPY utils.py .
|
| 17 |
+
COPY chains.py .
|
| 18 |
+
|
| 19 |
+
EXPOSE 8503
|
| 20 |
+
|
| 21 |
+
HEALTHCHECK CMD curl --fail http://localhost:8503/_stcore/health
|
| 22 |
+
|
| 23 |
+
ENTRYPOINT ["streamlit", "run", "pdf_bot.py", "--server.port=8503", "--server.address=0.0.0.0"]
|
pdf_bot.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
import streamlit as st
|
| 4 |
+
from langchain.chains import RetrievalQA
|
| 5 |
+
from PyPDF2 import PdfReader
|
| 6 |
+
from langchain.callbacks.base import BaseCallbackHandler
|
| 7 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
| 8 |
+
from langchain_community.vectorstores import Neo4jVector
|
| 9 |
+
from streamlit.logger import get_logger
|
| 10 |
+
from chains import (
|
| 11 |
+
load_embedding_model,
|
| 12 |
+
load_llm,
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
# load api key lib
|
| 16 |
+
from dotenv import load_dotenv
|
| 17 |
+
|
| 18 |
+
load_dotenv(".env")
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
url = os.getenv("NEO4J_URI")
|
| 22 |
+
username = os.getenv("NEO4J_USERNAME")
|
| 23 |
+
password = os.getenv("NEO4J_PASSWORD")
|
| 24 |
+
ollama_base_url = os.getenv("OLLAMA_BASE_URL")
|
| 25 |
+
embedding_model_name = os.getenv("EMBEDDING_MODEL")
|
| 26 |
+
llm_name = os.getenv("LLM")
|
| 27 |
+
# Remapping for Langchain Neo4j integration
|
| 28 |
+
os.environ["NEO4J_URL"] = url
|
| 29 |
+
|
| 30 |
+
logger = get_logger(__name__)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
embeddings, dimension = load_embedding_model(
|
| 34 |
+
embedding_model_name, config={"ollama_base_url": ollama_base_url}, logger=logger
|
| 35 |
+
)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
class StreamHandler(BaseCallbackHandler):
|
| 39 |
+
def __init__(self, container, initial_text=""):
|
| 40 |
+
self.container = container
|
| 41 |
+
self.text = initial_text
|
| 42 |
+
|
| 43 |
+
def on_llm_new_token(self, token: str, **kwargs) -> None:
|
| 44 |
+
self.text += token
|
| 45 |
+
self.container.markdown(self.text)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
llm = load_llm(llm_name, logger=logger, config={"ollama_base_url": ollama_base_url})
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def main():
|
| 52 |
+
st.header("📄Chat with your pdf file")
|
| 53 |
+
|
| 54 |
+
# upload a your pdf file
|
| 55 |
+
pdf = st.file_uploader("Upload your PDF", type="pdf")
|
| 56 |
+
|
| 57 |
+
if pdf is not None:
|
| 58 |
+
pdf_reader = PdfReader(pdf)
|
| 59 |
+
|
| 60 |
+
text = ""
|
| 61 |
+
for page in pdf_reader.pages:
|
| 62 |
+
text += page.extract_text()
|
| 63 |
+
|
| 64 |
+
# langchain_textspliter
|
| 65 |
+
text_splitter = RecursiveCharacterTextSplitter(
|
| 66 |
+
chunk_size=1000, chunk_overlap=200, length_function=len
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
chunks = text_splitter.split_text(text=text)
|
| 70 |
+
|
| 71 |
+
# Store the chunks part in db (vector)
|
| 72 |
+
vectorstore = Neo4jVector.from_texts(
|
| 73 |
+
chunks,
|
| 74 |
+
url=url,
|
| 75 |
+
username=username,
|
| 76 |
+
password=password,
|
| 77 |
+
embedding=embeddings,
|
| 78 |
+
index_name="pdf_bot",
|
| 79 |
+
node_label="PdfBotChunk",
|
| 80 |
+
pre_delete_collection=True, # Delete existing PDF data
|
| 81 |
+
)
|
| 82 |
+
qa = RetrievalQA.from_chain_type(
|
| 83 |
+
llm=llm, chain_type="stuff", retriever=vectorstore.as_retriever()
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
# Accept user questions/query
|
| 87 |
+
query = st.text_input("Ask questions about your PDF file")
|
| 88 |
+
|
| 89 |
+
if query:
|
| 90 |
+
stream_handler = StreamHandler(st.empty())
|
| 91 |
+
qa.run(query, callbacks=[stream_handler])
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
if __name__ == "__main__":
|
| 95 |
+
main()
|
pull_model.Dockerfile
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#syntax = docker/dockerfile:1.4
|
| 2 |
+
|
| 3 |
+
FROM ollama/ollama:latest AS ollama
|
| 4 |
+
FROM babashka/babashka:latest
|
| 5 |
+
|
| 6 |
+
# just using as a client - never as a server
|
| 7 |
+
COPY --from=ollama /bin/ollama ./bin/ollama
|
| 8 |
+
|
| 9 |
+
COPY <<EOF pull_model.clj
|
| 10 |
+
(ns pull-model
|
| 11 |
+
(:require [babashka.process :as process]
|
| 12 |
+
[clojure.core.async :as async]))
|
| 13 |
+
|
| 14 |
+
(try
|
| 15 |
+
(let [llm (get (System/getenv) "LLM")
|
| 16 |
+
url (get (System/getenv) "OLLAMA_BASE_URL")]
|
| 17 |
+
(println (format "pulling ollama model %s using %s" llm url))
|
| 18 |
+
(if (and llm
|
| 19 |
+
url
|
| 20 |
+
(not (#{"gpt-4" "gpt-3.5" "claudev2" "gpt-4o" "gpt-4-turbo"} llm))
|
| 21 |
+
(not (some #(.startsWith llm %) ["ai21.jamba-instruct-v1:0"
|
| 22 |
+
"amazon.titan"
|
| 23 |
+
"anthropic.claude"
|
| 24 |
+
"cohere.command"
|
| 25 |
+
"meta.llama"
|
| 26 |
+
"mistral.mi"])))
|
| 27 |
+
|
| 28 |
+
;; ----------------------------------------------------------------------
|
| 29 |
+
;; just call `ollama pull` here - create OLLAMA_HOST from OLLAMA_BASE_URL
|
| 30 |
+
;; ----------------------------------------------------------------------
|
| 31 |
+
;; TODO - this still doesn't show progress properly when run from docker compose
|
| 32 |
+
|
| 33 |
+
(let [done (async/chan)]
|
| 34 |
+
(async/go-loop [n 0]
|
| 35 |
+
(let [[v _] (async/alts! [done (async/timeout 5000)])]
|
| 36 |
+
(if (= :stop v) :stopped (do (println (format "... pulling model (%ss) - will take several minutes" (* n 10))) (recur (inc n))))))
|
| 37 |
+
(process/shell {:env {"OLLAMA_HOST" url "HOME" (System/getProperty "user.home")} :out :inherit :err :inherit} (format "bash -c './bin/ollama show %s --modelfile > /dev/null || ./bin/ollama pull %s'" llm llm))
|
| 38 |
+
(async/>!! done :stop))
|
| 39 |
+
|
| 40 |
+
(println "OLLAMA model only pulled if both LLM and OLLAMA_BASE_URL are set and the LLM model is not gpt")))
|
| 41 |
+
(catch Throwable _ (System/exit 1)))
|
| 42 |
+
EOF
|
| 43 |
+
|
| 44 |
+
ENTRYPOINT ["bb", "-f", "pull_model.clj"]
|
| 45 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
python-dotenv
|
| 2 |
+
wikipedia
|
| 3 |
+
tiktoken
|
| 4 |
+
neo4j
|
| 5 |
+
streamlit
|
| 6 |
+
Pillow
|
| 7 |
+
fastapi
|
| 8 |
+
PyPDF2
|
| 9 |
+
pydantic
|
| 10 |
+
uvicorn
|
| 11 |
+
sse-starlette
|
| 12 |
+
boto3
|
| 13 |
+
streamlit==1.32.1
|
| 14 |
+
# missing from the langchain base image?
|
| 15 |
+
langchain-openai==0.2.4
|
| 16 |
+
langchain-community==0.3.3
|
| 17 |
+
langchain-google-genai==2.0.3
|
| 18 |
+
langchain-ollama==0.2.0
|
| 19 |
+
langchain-huggingface==0.1.1
|
| 20 |
+
langchain-aws==0.2.4
|
running_on_wsl.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Run the stack on WSL
|
| 2 |
+
|
| 3 |
+
Note that for the stack to work on Windows, you should have running version on ollama installed somehow. Since Windows, is not yet supported, we can only use WSL.
|
| 4 |
+
|
| 5 |
+
I won't cover the activation of WSL procedure which you will find very easy on internet. Assuming that you have a version of WSL on your local windows machine and a running docker Desktop software installer and running as well, you can follow the following steps:
|
| 6 |
+
|
| 7 |
+
1. enable docker-desktop to use WSL using the following tutorial:
|
| 8 |
+
|
| 9 |
+
>To connect WSL to Docker Desktop, you need to follow the instructions below:
|
| 10 |
+
>
|
| 11 |
+
>1. First, ensure that you have installed Docker Desktop for Windows on your machine. If you haven't, you can download it from ¹.
|
| 12 |
+
>2. Next, open Docker Desktop and navigate to **Settings**.
|
| 13 |
+
>3. From the **Settings** menu, select **Resources** and then click on **WSL Integration**.
|
| 14 |
+
>4. On the **WSL Integration** page, you will see a list of available WSL distributions. Select the distribution that you want to connect to Docker Desktop.
|
| 15 |
+
>5. Once you have selected the distribution, click on **Apply & Restart**.
|
| 16 |
+
>
|
| 17 |
+
>After following these steps, your WSL distribution should be connected to Docker Desktop.
|
| 18 |
+
>
|
| 19 |
+
>
|
| 20 |
+
>1. Docker Desktop WSL 2 backend on Windows | Docker Docs. https://docs.docker.com/desktop/wsl/.
|
| 21 |
+
>2. Get started with Docker containers on WSL | Microsoft Learn. https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-containers.
|
| 22 |
+
>3. How to configure Docker Desktop to work with the WSL. https://tutorials.releaseworksacademy.com/learn/how-to-configure-docker-desktop-to-work-with-the-wsl.html.
|
| 23 |
+
>4. How can I access wsl2 which is used by Docker desktop?. https://stackoverflow.com/questions/70449927/how-can-i-access-wsl2-which-is-used-by-docker-desktop.
|
| 24 |
+
|
| 25 |
+
After the activation enter into the WSL with the command `wsl` and type `docker`.
|
| 26 |
+
|
| 27 |
+
2. Install ollama on WSL using https://github.com/jmorganca/ollama (avec la commande `curl https://ollama.ai/install.sh | sh`)
|
| 28 |
+
- The script have been downloaded in `./install_ollama.sh` and you do the smae thing with `sh ./install_ollama.sh`
|
| 29 |
+
- To list the downloaded model: `ollama list`. This command could lead to:
|
| 30 |
+
```sh
|
| 31 |
+
NAME ID SIZE MODIFIED
|
| 32 |
+
llama2:latest 7da22eda89ac 3.8 GB 22 minutes ago
|
| 33 |
+
```
|
| 34 |
+
- (OPTIONAL) To remove model: `ollama rm llama2`
|
| 35 |
+
- To run the ollama on WSL: `ollama run llama2`
|
| 36 |
+
|
| 37 |
+
3. clone the repo
|
| 38 |
+
4. cd into the repo and enter wsl
|
| 39 |
+
5. run `docker-compose up`
|
| 40 |
+
|
| 41 |
+
# Run the stack on MAC:
|
| 42 |
+
|
| 43 |
+
On MAC you can follow this tutorial: https://collabnix.com/getting-started-with-genai-stack-powered-with-docker-langchain-neo4j-and-ollama/
|
utils.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class BaseLogger:
|
| 2 |
+
def __init__(self) -> None:
|
| 3 |
+
self.info = print
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def extract_title_and_question(input_string):
|
| 7 |
+
lines = input_string.strip().split("\n")
|
| 8 |
+
|
| 9 |
+
title = ""
|
| 10 |
+
question = ""
|
| 11 |
+
is_question = False # flag to know if we are inside a "Question" block
|
| 12 |
+
|
| 13 |
+
for line in lines:
|
| 14 |
+
if line.startswith("Title:"):
|
| 15 |
+
title = line.split("Title: ", 1)[1].strip()
|
| 16 |
+
elif line.startswith("Question:"):
|
| 17 |
+
question = line.split("Question: ", 1)[1].strip()
|
| 18 |
+
is_question = (
|
| 19 |
+
True # set the flag to True once we encounter a "Question:" line
|
| 20 |
+
)
|
| 21 |
+
elif is_question:
|
| 22 |
+
# if the line does not start with "Question:" but we are inside a "Question" block,
|
| 23 |
+
# then it is a continuation of the question
|
| 24 |
+
question += "\n" + line.strip()
|
| 25 |
+
|
| 26 |
+
return title, question
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def create_vector_index(driver) -> None:
|
| 30 |
+
index_query = "CREATE VECTOR INDEX stackoverflow IF NOT EXISTS FOR (m:Question) ON m.embedding"
|
| 31 |
+
try:
|
| 32 |
+
driver.query(index_query)
|
| 33 |
+
except: # Already exists
|
| 34 |
+
pass
|
| 35 |
+
index_query = "CREATE VECTOR INDEX top_answers IF NOT EXISTS FOR (m:Answer) ON m.embedding"
|
| 36 |
+
try:
|
| 37 |
+
driver.query(index_query)
|
| 38 |
+
except: # Already exists
|
| 39 |
+
pass
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def create_constraints(driver):
|
| 43 |
+
driver.query(
|
| 44 |
+
"CREATE CONSTRAINT question_id IF NOT EXISTS FOR (q:Question) REQUIRE (q.id) IS UNIQUE"
|
| 45 |
+
)
|
| 46 |
+
driver.query(
|
| 47 |
+
"CREATE CONSTRAINT answer_id IF NOT EXISTS FOR (a:Answer) REQUIRE (a.id) IS UNIQUE"
|
| 48 |
+
)
|
| 49 |
+
driver.query(
|
| 50 |
+
"CREATE CONSTRAINT user_id IF NOT EXISTS FOR (u:User) REQUIRE (u.id) IS UNIQUE"
|
| 51 |
+
)
|
| 52 |
+
driver.query(
|
| 53 |
+
"CREATE CONSTRAINT tag_name IF NOT EXISTS FOR (t:Tag) REQUIRE (t.name) IS UNIQUE"
|
| 54 |
+
)
|