MetaList 0.1.6__tar.gz → 0.1.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of MetaList might be problematic. Click here for more details.
- MetaList-0.1.7/MetaList.egg-info/PKG-INFO +110 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/MetaList.egg-info/SOURCES.txt +4 -3
- MetaList-0.1.7/PKG-INFO +110 -0
- MetaList-0.1.7/README.md +92 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/app.py +107 -29
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/config.py +3 -1
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/components/chat-ui.css +25 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/components/items-list.css +5 -4
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/app-state.js +3 -1
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/components/chat-ui.js +77 -100
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/components/items-list.js +40 -3
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/components/search-bar.js +1 -1
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/components/suggestions-list.js +1 -1
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/misc/item-formatter.js +5 -6
- MetaList-0.1.6/metalist/static/js/misc/formats.js → MetaList-0.1.7/metalist/static/js/misc/parsing.js +113 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/misc/server-proxy.js +7 -0
- MetaList-0.1.7/metalist/utils/chat_prompts.py +220 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/decorate_single_item.py +6 -4
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/find.py +3 -3
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/initialize.py +4 -0
- MetaList-0.1.7/metalist/utils/search_index.py +62 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/search_suggestions.py +11 -1
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/server.py +42 -16
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/tags_suggestions.py +21 -7
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/update_multiple_items.py +10 -15
- {MetaList-0.1.6 → MetaList-0.1.7}/setup.py +2 -2
- {MetaList-0.1.6 → MetaList-0.1.7}/tests/test_utils.py +2 -2
- MetaList-0.1.6/MetaList.egg-info/PKG-INFO +0 -59
- MetaList-0.1.6/PKG-INFO +0 -59
- MetaList-0.1.6/README.md +0 -41
- MetaList-0.1.6/metalist/static/js/misc/LLMs.js +0 -252
- {MetaList-0.1.6 → MetaList-0.1.7}/LICENSE +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/MetaList.egg-info/dependency_links.txt +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/MetaList.egg-info/entry_points.txt +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/MetaList.egg-info/requires.txt +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/MetaList.egg-info/top_level.txt +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/__init__.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/app.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/components/search-bar.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/components/suggestions-list.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/components/tags-bar.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/dark-theme.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/reserved-tags.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/css/unreset.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/html/index.html +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/img/caret-down-filled.svg +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/img/caret-right-filled.svg +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/img/chat-left-svgrepo-com.svg +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/img/checkbox-checked.svg +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/img/checkbox-unchecked.svg +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/img/favicon.ico +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/img/search.svg +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/img/tag.svg +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/components/tags-bar.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/config.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/misc/logging.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/misc/scrolling.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/misc/vdom.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/js/pub-sub-events.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/PubSubJS/LICENSE.md +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/PubSubJS/pubsub.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/katex/LICENSE +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/katex/contrib/auto-render.min.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/katex/contrib/copy-tex.min.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/katex/contrib/copy-tex.min.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/katex/contrib/mathtex-script-type.min.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/katex/katex.min.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/katex/katex.min.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/lodash/LICENSE +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/lodash/lodash.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/markdown-it/LICENSE +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/markdown-it/markdown-it.min.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/micronitjs/LICENSE +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/micronitjs/micronit.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/the-new-css-reset/LICENSE +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/the-new-css-reset/reset.css +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/voca/LICENSE.md +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/libs/voca/voca.min.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/tests/unit-tests/run-tests.html +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/static/tests/unit-tests/test-search-bar.js +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/__init__.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/crud.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/generate.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/misc/__init__.py +0 -0
- /MetaList-0.1.6/metalist/utils/misc/crypto.py → /MetaList-0.1.7/metalist/utils/misc/crypto-test.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/ontology.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/reporting.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/search_filters.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/snapshots.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/metalist/utils/update_single_item.py +0 -0
- {MetaList-0.1.6 → MetaList-0.1.7}/setup.cfg +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: MetaList
|
|
3
|
+
Version: 0.1.7
|
|
4
|
+
Summary: A PKM web app integrated with LLMs
|
|
5
|
+
Home-page: https://github.com/evolvingstuff/MetaList
|
|
6
|
+
Author: Thomas Lahore
|
|
7
|
+
Author-email: tom.lahore@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: bottle==0.12.25
|
|
15
|
+
Requires-Dist: bottle-sqlite==0.2.0
|
|
16
|
+
Requires-Dist: beautifulsoup4~=4.12.2
|
|
17
|
+
Requires-Dist: tqdm==4.66.1
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# MetaList
|
|
21
|
+
|
|
22
|
+
<img src="docs/img/MetaList-Logo.png" width="130" />
|
|
23
|
+
|
|
24
|
+
[](https://pypi.org/project/metalist/)
|
|
25
|
+

|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## What is MetaList?
|
|
30
|
+
MetaList is a personal knowledge management web application,
|
|
31
|
+
tightly integrated with large language models.
|
|
32
|
+
|
|
33
|
+
> ⚠️ **MetaList is currently in Development**: Expect breaking changes and bugs
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- [x] Chat feature: LLM integration (currently only [OpenAI API](https://openai.com/blog/openai-api))
|
|
38
|
+
- [x] [Chart.js](https://www.chartjs.org/) integration for LLM-generated visualizations
|
|
39
|
+
- [x] Hierarchical, collapsable note structure
|
|
40
|
+
- [x] Reordering notes in one context survives to other search contexts; notes maintain a [total order](https://en.wikipedia.org/wiki/Total_order)
|
|
41
|
+
- [x] Quick, responsive searching (tags, full-text, or combo of both)
|
|
42
|
+
- [x] Search suggestions
|
|
43
|
+
- [x] Tagging
|
|
44
|
+
- [x] Tag suggestions (uses a [Jaccard index](https://en.wikipedia.org/wiki/Jaccard_index))
|
|
45
|
+
- [x] Tags can imply other tags
|
|
46
|
+
- [x] Tag implication rules are also notes; they can themselves be tagged and searched
|
|
47
|
+
- [x] Nested subitems in notes inherit tags from their parents
|
|
48
|
+
- [x] [Markdown](https://markdown-it.github.io/)/[LaTeX](https://katex.org/) support
|
|
49
|
+
- [x] Infinite undo/redo
|
|
50
|
+
- [x] Infinite scrolling
|
|
51
|
+
|
|
52
|
+
### Chat Feature Example
|
|
53
|
+
|
|
54
|
+
Search filters notes down to a relevant subset (a "search context"), which has the nice
|
|
55
|
+
effect of acting as a form of human-guided [retrieval augmented generation](https://www.promptingguide.ai/techniques/rag).
|
|
56
|
+
The chat feature is fully integrated with the underlying notes. Mousing over a reference in the chat will highlight
|
|
57
|
+
the referenced note, if it is within view, and clicking on the reference will navigate to and select the note,
|
|
58
|
+
even opening up collapsed items in the note hierarchy so that all the relevant info becomes visible.
|
|
59
|
+
|
|
60
|
+
Some examples of interactions with the chat feature (in this case, recommending new movies):
|
|
61
|
+
|
|
62
|
+
<img src="docs/img/demo-1.gif" width="800"/>
|
|
63
|
+
<img src="docs/img/chat-example-2.png" width="800"/>
|
|
64
|
+
<!--<img src="docs/img/chat-example-3.png" width="800"/>-->
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
It is recommended that you create a Python virtual environment before installing MetaList.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
python3 -m venv venv
|
|
72
|
+
source venv/bin/activate
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Then, install MetaList using pip:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install metalist
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
From the installation directory, run:
|
|
84
|
+
```
|
|
85
|
+
metalist
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Navigate to `http://127.0.0.0:8080/`
|
|
89
|
+
|
|
90
|
+
Read the [cheatsheet](docs/cheatsheet.md).
|
|
91
|
+
|
|
92
|
+
## Roadmap
|
|
93
|
+
|
|
94
|
+
- [ ] Chat integration with other models
|
|
95
|
+
- [ ] Menus / Settings
|
|
96
|
+
- [ ] Reminders
|
|
97
|
+
- [ ] Passwords / encryption at rest
|
|
98
|
+
- [ ] Import data from browser bookmarks
|
|
99
|
+
- [ ] Import data from other PKM apps
|
|
100
|
+
- [ ] Export notes to JSON, Markdown, HTML, PDF
|
|
101
|
+
- [ ] File handling
|
|
102
|
+
- [ ] Access to local file system
|
|
103
|
+
- [ ] Multi-user
|
|
104
|
+
- [ ] Mobile friendly
|
|
105
|
+
- [ ] More unit/integration testing
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MetaList is licensed under the MIT license. See [LICENSE](LICENSE) for more information.
|
|
110
|
+
|
|
@@ -36,10 +36,9 @@ metalist/static/js/components/items-list.js
|
|
|
36
36
|
metalist/static/js/components/search-bar.js
|
|
37
37
|
metalist/static/js/components/suggestions-list.js
|
|
38
38
|
metalist/static/js/components/tags-bar.js
|
|
39
|
-
metalist/static/js/misc/LLMs.js
|
|
40
|
-
metalist/static/js/misc/formats.js
|
|
41
39
|
metalist/static/js/misc/item-formatter.js
|
|
42
40
|
metalist/static/js/misc/logging.js
|
|
41
|
+
metalist/static/js/misc/parsing.js
|
|
43
42
|
metalist/static/js/misc/scrolling.js
|
|
44
43
|
metalist/static/js/misc/server-proxy.js
|
|
45
44
|
metalist/static/js/misc/vdom.js
|
|
@@ -65,6 +64,7 @@ metalist/static/libs/voca/voca.min.js
|
|
|
65
64
|
metalist/static/tests/unit-tests/run-tests.html
|
|
66
65
|
metalist/static/tests/unit-tests/test-search-bar.js
|
|
67
66
|
metalist/utils/__init__.py
|
|
67
|
+
metalist/utils/chat_prompts.py
|
|
68
68
|
metalist/utils/crud.py
|
|
69
69
|
metalist/utils/decorate_single_item.py
|
|
70
70
|
metalist/utils/find.py
|
|
@@ -73,6 +73,7 @@ metalist/utils/initialize.py
|
|
|
73
73
|
metalist/utils/ontology.py
|
|
74
74
|
metalist/utils/reporting.py
|
|
75
75
|
metalist/utils/search_filters.py
|
|
76
|
+
metalist/utils/search_index.py
|
|
76
77
|
metalist/utils/search_suggestions.py
|
|
77
78
|
metalist/utils/server.py
|
|
78
79
|
metalist/utils/snapshots.py
|
|
@@ -80,5 +81,5 @@ metalist/utils/tags_suggestions.py
|
|
|
80
81
|
metalist/utils/update_multiple_items.py
|
|
81
82
|
metalist/utils/update_single_item.py
|
|
82
83
|
metalist/utils/misc/__init__.py
|
|
83
|
-
metalist/utils/misc/crypto.py
|
|
84
|
+
metalist/utils/misc/crypto-test.py
|
|
84
85
|
tests/test_utils.py
|
MetaList-0.1.7/PKG-INFO
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: MetaList
|
|
3
|
+
Version: 0.1.7
|
|
4
|
+
Summary: A PKM web app integrated with LLMs
|
|
5
|
+
Home-page: https://github.com/evolvingstuff/MetaList
|
|
6
|
+
Author: Thomas Lahore
|
|
7
|
+
Author-email: tom.lahore@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: bottle==0.12.25
|
|
15
|
+
Requires-Dist: bottle-sqlite==0.2.0
|
|
16
|
+
Requires-Dist: beautifulsoup4~=4.12.2
|
|
17
|
+
Requires-Dist: tqdm==4.66.1
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# MetaList
|
|
21
|
+
|
|
22
|
+
<img src="docs/img/MetaList-Logo.png" width="130" />
|
|
23
|
+
|
|
24
|
+
[](https://pypi.org/project/metalist/)
|
|
25
|
+

|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## What is MetaList?
|
|
30
|
+
MetaList is a personal knowledge management web application,
|
|
31
|
+
tightly integrated with large language models.
|
|
32
|
+
|
|
33
|
+
> ⚠️ **MetaList is currently in Development**: Expect breaking changes and bugs
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- [x] Chat feature: LLM integration (currently only [OpenAI API](https://openai.com/blog/openai-api))
|
|
38
|
+
- [x] [Chart.js](https://www.chartjs.org/) integration for LLM-generated visualizations
|
|
39
|
+
- [x] Hierarchical, collapsable note structure
|
|
40
|
+
- [x] Reordering notes in one context survives to other search contexts; notes maintain a [total order](https://en.wikipedia.org/wiki/Total_order)
|
|
41
|
+
- [x] Quick, responsive searching (tags, full-text, or combo of both)
|
|
42
|
+
- [x] Search suggestions
|
|
43
|
+
- [x] Tagging
|
|
44
|
+
- [x] Tag suggestions (uses a [Jaccard index](https://en.wikipedia.org/wiki/Jaccard_index))
|
|
45
|
+
- [x] Tags can imply other tags
|
|
46
|
+
- [x] Tag implication rules are also notes; they can themselves be tagged and searched
|
|
47
|
+
- [x] Nested subitems in notes inherit tags from their parents
|
|
48
|
+
- [x] [Markdown](https://markdown-it.github.io/)/[LaTeX](https://katex.org/) support
|
|
49
|
+
- [x] Infinite undo/redo
|
|
50
|
+
- [x] Infinite scrolling
|
|
51
|
+
|
|
52
|
+
### Chat Feature Example
|
|
53
|
+
|
|
54
|
+
Search filters notes down to a relevant subset (a "search context"), which has the nice
|
|
55
|
+
effect of acting as a form of human-guided [retrieval augmented generation](https://www.promptingguide.ai/techniques/rag).
|
|
56
|
+
The chat feature is fully integrated with the underlying notes. Mousing over a reference in the chat will highlight
|
|
57
|
+
the referenced note, if it is within view, and clicking on the reference will navigate to and select the note,
|
|
58
|
+
even opening up collapsed items in the note hierarchy so that all the relevant info becomes visible.
|
|
59
|
+
|
|
60
|
+
Some examples of interactions with the chat feature (in this case, recommending new movies):
|
|
61
|
+
|
|
62
|
+
<img src="docs/img/demo-1.gif" width="800"/>
|
|
63
|
+
<img src="docs/img/chat-example-2.png" width="800"/>
|
|
64
|
+
<!--<img src="docs/img/chat-example-3.png" width="800"/>-->
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
It is recommended that you create a Python virtual environment before installing MetaList.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
python3 -m venv venv
|
|
72
|
+
source venv/bin/activate
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Then, install MetaList using pip:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install metalist
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
From the installation directory, run:
|
|
84
|
+
```
|
|
85
|
+
metalist
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Navigate to `http://127.0.0.0:8080/`
|
|
89
|
+
|
|
90
|
+
Read the [cheatsheet](docs/cheatsheet.md).
|
|
91
|
+
|
|
92
|
+
## Roadmap
|
|
93
|
+
|
|
94
|
+
- [ ] Chat integration with other models
|
|
95
|
+
- [ ] Menus / Settings
|
|
96
|
+
- [ ] Reminders
|
|
97
|
+
- [ ] Passwords / encryption at rest
|
|
98
|
+
- [ ] Import data from browser bookmarks
|
|
99
|
+
- [ ] Import data from other PKM apps
|
|
100
|
+
- [ ] Export notes to JSON, Markdown, HTML, PDF
|
|
101
|
+
- [ ] File handling
|
|
102
|
+
- [ ] Access to local file system
|
|
103
|
+
- [ ] Multi-user
|
|
104
|
+
- [ ] Mobile friendly
|
|
105
|
+
- [ ] More unit/integration testing
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MetaList is licensed under the MIT license. See [LICENSE](LICENSE) for more information.
|
|
110
|
+
|
MetaList-0.1.7/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
|
|
2
|
+
# MetaList
|
|
3
|
+
|
|
4
|
+
<img src="docs/img/MetaList-Logo.png" width="130" />
|
|
5
|
+
|
|
6
|
+
[](https://pypi.org/project/metalist/)
|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## What is MetaList?
|
|
12
|
+
MetaList is a personal knowledge management web application,
|
|
13
|
+
tightly integrated with large language models.
|
|
14
|
+
|
|
15
|
+
> ⚠️ **MetaList is currently in Development**: Expect breaking changes and bugs
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- [x] Chat feature: LLM integration (currently only [OpenAI API](https://openai.com/blog/openai-api))
|
|
20
|
+
- [x] [Chart.js](https://www.chartjs.org/) integration for LLM-generated visualizations
|
|
21
|
+
- [x] Hierarchical, collapsable note structure
|
|
22
|
+
- [x] Reordering notes in one context survives to other search contexts; notes maintain a [total order](https://en.wikipedia.org/wiki/Total_order)
|
|
23
|
+
- [x] Quick, responsive searching (tags, full-text, or combo of both)
|
|
24
|
+
- [x] Search suggestions
|
|
25
|
+
- [x] Tagging
|
|
26
|
+
- [x] Tag suggestions (uses a [Jaccard index](https://en.wikipedia.org/wiki/Jaccard_index))
|
|
27
|
+
- [x] Tags can imply other tags
|
|
28
|
+
- [x] Tag implication rules are also notes; they can themselves be tagged and searched
|
|
29
|
+
- [x] Nested subitems in notes inherit tags from their parents
|
|
30
|
+
- [x] [Markdown](https://markdown-it.github.io/)/[LaTeX](https://katex.org/) support
|
|
31
|
+
- [x] Infinite undo/redo
|
|
32
|
+
- [x] Infinite scrolling
|
|
33
|
+
|
|
34
|
+
### Chat Feature Example
|
|
35
|
+
|
|
36
|
+
Search filters notes down to a relevant subset (a "search context"), which has the nice
|
|
37
|
+
effect of acting as a form of human-guided [retrieval augmented generation](https://www.promptingguide.ai/techniques/rag).
|
|
38
|
+
The chat feature is fully integrated with the underlying notes. Mousing over a reference in the chat will highlight
|
|
39
|
+
the referenced note, if it is within view, and clicking on the reference will navigate to and select the note,
|
|
40
|
+
even opening up collapsed items in the note hierarchy so that all the relevant info becomes visible.
|
|
41
|
+
|
|
42
|
+
Some examples of interactions with the chat feature (in this case, recommending new movies):
|
|
43
|
+
|
|
44
|
+
<img src="docs/img/demo-1.gif" width="800"/>
|
|
45
|
+
<img src="docs/img/chat-example-2.png" width="800"/>
|
|
46
|
+
<!--<img src="docs/img/chat-example-3.png" width="800"/>-->
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
It is recommended that you create a Python virtual environment before installing MetaList.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
python3 -m venv venv
|
|
54
|
+
source venv/bin/activate
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Then, install MetaList using pip:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install metalist
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
From the installation directory, run:
|
|
66
|
+
```
|
|
67
|
+
metalist
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Navigate to `http://127.0.0.0:8080/`
|
|
71
|
+
|
|
72
|
+
Read the [cheatsheet](docs/cheatsheet.md).
|
|
73
|
+
|
|
74
|
+
## Roadmap
|
|
75
|
+
|
|
76
|
+
- [ ] Chat integration with other models
|
|
77
|
+
- [ ] Menus / Settings
|
|
78
|
+
- [ ] Reminders
|
|
79
|
+
- [ ] Passwords / encryption at rest
|
|
80
|
+
- [ ] Import data from browser bookmarks
|
|
81
|
+
- [ ] Import data from other PKM apps
|
|
82
|
+
- [ ] Export notes to JSON, Markdown, HTML, PDF
|
|
83
|
+
- [ ] File handling
|
|
84
|
+
- [ ] Access to local file system
|
|
85
|
+
- [ ] Multi-user
|
|
86
|
+
- [ ] Mobile friendly
|
|
87
|
+
- [ ] More unit/integration testing
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MetaList is licensed under the MIT license. See [LICENSE](LICENSE) for more information.
|
|
92
|
+
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from
|
|
2
|
+
from typing import List
|
|
3
|
+
from bottle import Bottle, run, static_file, request, response
|
|
3
4
|
import bottle_sqlite
|
|
4
|
-
|
|
5
|
-
from metalist.config import reset_undo_stack_on_search, port
|
|
5
|
+
import requests
|
|
6
|
+
from metalist.config import reset_undo_stack_on_search, port, open_ai_url, open_ai_model, development_mode
|
|
7
|
+
from metalist.utils.chat_prompts import build_initial_prompts, build_selection_prompt
|
|
6
8
|
from metalist.utils.crud import get_database_path
|
|
7
9
|
from metalist.utils.search_suggestions import calculate_search_suggestions
|
|
8
10
|
from metalist.utils.server import get_request_context, \
|
|
9
|
-
generic_response, noop_response, error_response,
|
|
11
|
+
generic_response, noop_response, error_response, filter_and_sort_items, Context, chat_response
|
|
12
|
+
from metalist.utils.search_index import SearchIndex
|
|
10
13
|
from metalist.utils.tags_suggestions import calculate_tags_suggestions
|
|
11
14
|
from metalist.utils.initialize import initialize_cache
|
|
12
15
|
from metalist.utils.snapshots import Snapshots, SnapshotFragment, Snapshot, compress_snapshots
|
|
@@ -16,6 +19,7 @@ from metalist.utils import update_single_item, update_multiple_items
|
|
|
16
19
|
|
|
17
20
|
cache = {}
|
|
18
21
|
snapshots = Snapshots()
|
|
22
|
+
chat_history: List[dict] = list()
|
|
19
23
|
|
|
20
24
|
app = Bottle()
|
|
21
25
|
plugin = bottle_sqlite.Plugin(dbfile=get_database_path())
|
|
@@ -23,6 +27,8 @@ app.install(plugin)
|
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
def run_app():
|
|
30
|
+
if development_mode:
|
|
31
|
+
print('DEV MODE = True')
|
|
26
32
|
initialize_cache(cache)
|
|
27
33
|
run(app, port=port, debug=False)
|
|
28
34
|
|
|
@@ -91,7 +97,7 @@ def todo(db):
|
|
|
91
97
|
context = get_request_context(request, cache)
|
|
92
98
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
93
99
|
update_single_item.todo(db, context, cache)
|
|
94
|
-
filtered_items, reached_scroll_end =
|
|
100
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
95
101
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
96
102
|
snapshot = Snapshot('/todo', snap_pre, snap_post, context.item_subitem_id)
|
|
97
103
|
snapshots.push(snapshot)
|
|
@@ -111,7 +117,7 @@ def done(db):
|
|
|
111
117
|
context = get_request_context(request, cache)
|
|
112
118
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
113
119
|
update_single_item.done(db, context, cache)
|
|
114
|
-
filtered_items, reached_scroll_end =
|
|
120
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
115
121
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
116
122
|
snapshot = Snapshot('/done', snap_pre, snap_post, context.item_subitem_id)
|
|
117
123
|
snapshots.push(snapshot)
|
|
@@ -131,7 +137,7 @@ def expand(db):
|
|
|
131
137
|
context = get_request_context(request, cache)
|
|
132
138
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
133
139
|
update_single_item.expand(db, context, cache)
|
|
134
|
-
filtered_items, reached_scroll_end =
|
|
140
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
135
141
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
136
142
|
snapshot = Snapshot('/expand', snap_pre, snap_post, context.item_subitem_id)
|
|
137
143
|
snapshots.push(snapshot)
|
|
@@ -151,7 +157,7 @@ def collapse(db):
|
|
|
151
157
|
context = get_request_context(request, cache)
|
|
152
158
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
153
159
|
update_single_item.collapse(db, context, cache)
|
|
154
|
-
filtered_items, reached_scroll_end =
|
|
160
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
155
161
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
156
162
|
snapshot = Snapshot('/collapse', snap_pre, snap_post, context.item_subitem_id)
|
|
157
163
|
snapshots.push(snapshot)
|
|
@@ -175,7 +181,7 @@ def delete_subitem(db):
|
|
|
175
181
|
must_recalculate_ontology = update_multiple_items.remove_item(db, cache, context)
|
|
176
182
|
if must_recalculate_ontology:
|
|
177
183
|
update_multiple_items.recalculate_ontology(db, cache, context)
|
|
178
|
-
filtered_items, reached_scroll_end =
|
|
184
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
179
185
|
snap_post = SnapshotFragment(cache, None)
|
|
180
186
|
snapshot = Snapshot('/delete-subitem (item)', snap_pre, snap_post, context.item_subitem_id)
|
|
181
187
|
snapshots.push(snapshot)
|
|
@@ -186,7 +192,7 @@ def delete_subitem(db):
|
|
|
186
192
|
must_recalculate_ontology = update_single_item.delete_subitem(db, context, cache)
|
|
187
193
|
if must_recalculate_ontology:
|
|
188
194
|
update_multiple_items.recalculate_ontology(db, cache, context)
|
|
189
|
-
filtered_items, reached_scroll_end =
|
|
195
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
190
196
|
snap_post = SnapshotFragment(cache, None)
|
|
191
197
|
snapshot = Snapshot('/delete-subitem', snap_pre, snap_post, context.item_subitem_id)
|
|
192
198
|
snapshots.push(snapshot)
|
|
@@ -227,7 +233,7 @@ def move_item_up(db):
|
|
|
227
233
|
context = get_request_context(request, cache)
|
|
228
234
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
229
235
|
update_multiple_items.move_item_up(db, cache, context)
|
|
230
|
-
filtered_items, reached_scroll_end =
|
|
236
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
231
237
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
232
238
|
snapshot = Snapshot('/move-item-up', snap_pre, snap_post, context.item_subitem_id)
|
|
233
239
|
snapshots.push(snapshot)
|
|
@@ -247,7 +253,7 @@ def move_item_down(db):
|
|
|
247
253
|
context = get_request_context(request, cache)
|
|
248
254
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
249
255
|
update_multiple_items.move_item_down(db, cache, context)
|
|
250
|
-
filtered_items, reached_scroll_end =
|
|
256
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
251
257
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
252
258
|
snapshot = Snapshot('/move-item-down', snap_pre, snap_post, context.item_subitem_id)
|
|
253
259
|
snapshots.push(snapshot)
|
|
@@ -267,7 +273,7 @@ def move_subitem_up(db):
|
|
|
267
273
|
context = get_request_context(request, cache)
|
|
268
274
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
269
275
|
new_item_subitem_id = update_single_item.move_subitem_up(db, context, cache)
|
|
270
|
-
filtered_items, reached_scroll_end =
|
|
276
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
271
277
|
snap_post = SnapshotFragment(cache, new_item_subitem_id)
|
|
272
278
|
snapshot = Snapshot('/move-subitem-up', snap_pre, snap_post, context.item_subitem_id)
|
|
273
279
|
snapshots.push(snapshot)
|
|
@@ -287,7 +293,7 @@ def move_subitem_down(db):
|
|
|
287
293
|
context = get_request_context(request, cache)
|
|
288
294
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
289
295
|
new_item_subitem_id = update_single_item.move_subitem_down(db, context, cache)
|
|
290
|
-
filtered_items, reached_scroll_end =
|
|
296
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
291
297
|
snap_post = SnapshotFragment(cache, new_item_subitem_id)
|
|
292
298
|
snapshot = Snapshot('/move-subitem-down', snap_pre, snap_post, context.item_subitem_id)
|
|
293
299
|
snapshots.push(snapshot)
|
|
@@ -307,7 +313,7 @@ def indent(db):
|
|
|
307
313
|
context = get_request_context(request, cache)
|
|
308
314
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
309
315
|
update_single_item.indent(db, context, cache)
|
|
310
|
-
filtered_items, reached_scroll_end =
|
|
316
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
311
317
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
312
318
|
snapshot = Snapshot('/indent', snap_pre, snap_post, context.item_subitem_id)
|
|
313
319
|
snapshots.push(snapshot)
|
|
@@ -327,7 +333,7 @@ def outdent(db):
|
|
|
327
333
|
context = get_request_context(request, cache)
|
|
328
334
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
329
335
|
update_single_item.outdent(db, context, cache)
|
|
330
|
-
filtered_items, reached_scroll_end =
|
|
336
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
331
337
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
332
338
|
snapshot = Snapshot('/outdent', snap_pre, snap_post, context.item_subitem_id)
|
|
333
339
|
snapshots.push(snapshot)
|
|
@@ -345,8 +351,7 @@ def search(db):
|
|
|
345
351
|
context = get_request_context(request, cache)
|
|
346
352
|
# TODO why recreate context?
|
|
347
353
|
context = Context(context.app_state, search_text=context.search_text, search_filter=context.search_filter)
|
|
348
|
-
filtered_items, reached_scroll_end =
|
|
349
|
-
print(f'debug: reached_scroll_end = {reached_scroll_end}')
|
|
354
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, updated_search=True, dirty_ranking=True)
|
|
350
355
|
if reset_undo_stack_on_search:
|
|
351
356
|
snapshots.reset()
|
|
352
357
|
else:
|
|
@@ -385,7 +390,7 @@ def add_item_sibling(db):
|
|
|
385
390
|
context = get_request_context(request, cache)
|
|
386
391
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
387
392
|
new_item_subitem_id = update_multiple_items.add_item_sibling(db, cache, context)
|
|
388
|
-
filtered_items, reached_scroll_end =
|
|
393
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
389
394
|
snap_post = SnapshotFragment(cache, new_item_subitem_id)
|
|
390
395
|
snapshot = Snapshot('/add-item-sibling', snap_pre, snap_post, context.item_subitem_id)
|
|
391
396
|
snapshots.push(snapshot)
|
|
@@ -401,7 +406,7 @@ def add_subitem_sibling(db):
|
|
|
401
406
|
context = get_request_context(request, cache)
|
|
402
407
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
403
408
|
new_item_subitem_id = update_single_item.add_subitem_sibling(db, context, cache)
|
|
404
|
-
filtered_items, reached_scroll_end =
|
|
409
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
405
410
|
snap_post = SnapshotFragment(cache, new_item_subitem_id)
|
|
406
411
|
snapshot = Snapshot('/add-subitem-sibling', snap_pre, snap_post, context.item_subitem_id)
|
|
407
412
|
snapshots.push(snapshot)
|
|
@@ -417,7 +422,7 @@ def add_subitem_child(db):
|
|
|
417
422
|
context = get_request_context(request, cache)
|
|
418
423
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
419
424
|
new_item_subitem_id = update_single_item.add_subitem_child(db, context, cache)
|
|
420
|
-
filtered_items, reached_scroll_end =
|
|
425
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
421
426
|
snap_post = SnapshotFragment(cache, new_item_subitem_id)
|
|
422
427
|
snapshot = Snapshot('/add-subitem-child', snap_pre, snap_post, context.item_subitem_id)
|
|
423
428
|
snapshots.push(snapshot)
|
|
@@ -436,7 +441,7 @@ def add_item_top(db):
|
|
|
436
441
|
if len(context.search_filter['texts']) > 0 or context.search_filter['partial_text'] is not None:
|
|
437
442
|
return error_response('Cannot add new items when using a text based search filter.')
|
|
438
443
|
new_item_subitem_id = update_multiple_items.add_item_top(db, cache, context)
|
|
439
|
-
filtered_items, reached_scroll_end =
|
|
444
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
440
445
|
snap_post = SnapshotFragment(cache, new_item_subitem_id)
|
|
441
446
|
snapshot = Snapshot('/add-item-top', snap_pre, snap_post, context.item_subitem_id)
|
|
442
447
|
snapshots.push(snapshot)
|
|
@@ -453,7 +458,7 @@ def paste_sibling(db):
|
|
|
453
458
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
454
459
|
assert context.clipboard is not None, 'missing clipboard from request'
|
|
455
460
|
new_item_subitem_id = update_multiple_items.paste_sibling(db, cache, context)
|
|
456
|
-
filtered_items, reached_scroll_end =
|
|
461
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
457
462
|
snap_post = SnapshotFragment(cache, new_item_subitem_id)
|
|
458
463
|
snapshot = Snapshot('/paste-sibling', snap_pre, snap_post, context.item_subitem_id)
|
|
459
464
|
snapshots.push(snapshot)
|
|
@@ -470,7 +475,7 @@ def paste_child(db):
|
|
|
470
475
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
471
476
|
assert context.clipboard is not None, 'missing clipboard from request'
|
|
472
477
|
new_item_subitem_id = update_single_item.paste_child(db, context, cache)
|
|
473
|
-
filtered_items, reached_scroll_end =
|
|
478
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
474
479
|
snap_post = SnapshotFragment(cache, new_item_subitem_id)
|
|
475
480
|
snapshot = Snapshot('/paste-child', snap_pre, snap_post, context.item_subitem_id)
|
|
476
481
|
snapshots.push(snapshot)
|
|
@@ -484,7 +489,7 @@ def pagination_update(db):
|
|
|
484
489
|
global cache, snapshots
|
|
485
490
|
context = get_request_context(request, cache)
|
|
486
491
|
# no snapshot
|
|
487
|
-
filtered_items, reached_scroll_end =
|
|
492
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
488
493
|
return generic_response(filtered_items, reached_scroll_end, new_item_subitem_id=context.item_subitem_id)
|
|
489
494
|
|
|
490
495
|
|
|
@@ -497,7 +502,7 @@ def update_tags(db):
|
|
|
497
502
|
must_recalculate_ontology = update_single_item.update_tags(db, context, cache)
|
|
498
503
|
if must_recalculate_ontology:
|
|
499
504
|
update_multiple_items.recalculate_ontology(db, cache, context)
|
|
500
|
-
filtered_items, reached_scroll_end =
|
|
505
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
501
506
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
502
507
|
snapshot = Snapshot('/update-tags', snap_pre, snap_post, context.item_subitem_id)
|
|
503
508
|
snapshots.push(snapshot)
|
|
@@ -513,7 +518,7 @@ def open_to(db):
|
|
|
513
518
|
context = get_request_context(request, cache)
|
|
514
519
|
snap_pre = SnapshotFragment(cache, context.item_subitem_id)
|
|
515
520
|
update_single_item.open_to(db, context, cache)
|
|
516
|
-
filtered_items, reached_scroll_end =
|
|
521
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context)
|
|
517
522
|
snap_post = SnapshotFragment(cache, context.item_subitem_id)
|
|
518
523
|
snapshot = Snapshot('/open-to', snap_pre, snap_post, context.item_subitem_id)
|
|
519
524
|
snapshots.push(snapshot)
|
|
@@ -530,7 +535,7 @@ def undo(db):
|
|
|
530
535
|
# no snapshot
|
|
531
536
|
try:
|
|
532
537
|
new_item_subitem_id = update_multiple_items.undo(db, snapshots, cache)
|
|
533
|
-
filtered_items, reached_scroll_end =
|
|
538
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
534
539
|
crud.commit(db)
|
|
535
540
|
return generic_response(filtered_items, reached_scroll_end, new_item_subitem_id=new_item_subitem_id)
|
|
536
541
|
except Exception as e:
|
|
@@ -546,7 +551,7 @@ def redo(db):
|
|
|
546
551
|
# no snapshot
|
|
547
552
|
try:
|
|
548
553
|
new_item_subitem_id = update_multiple_items.redo(db, snapshots, cache)
|
|
549
|
-
filtered_items, reached_scroll_end =
|
|
554
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
550
555
|
crud.commit(db)
|
|
551
556
|
return generic_response(filtered_items, reached_scroll_end, new_item_subitem_id=new_item_subitem_id)
|
|
552
557
|
except Exception as e:
|
|
@@ -554,5 +559,78 @@ def redo(db):
|
|
|
554
559
|
return noop_response('nothing to redo')
|
|
555
560
|
|
|
556
561
|
|
|
562
|
+
@app.post('/chat-open')
|
|
563
|
+
def chat_open(db):
|
|
564
|
+
global chat_history
|
|
565
|
+
chat_history = [] # reset history
|
|
566
|
+
return noop_response('chat-open')
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
@app.post('/chat-close')
|
|
570
|
+
def chat_close(db):
|
|
571
|
+
global chat_history
|
|
572
|
+
chat_history = [] # reset history
|
|
573
|
+
return noop_response('chat-close')
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
@app.post('/chat-select-reference')
|
|
577
|
+
def chat_select_reference(db):
|
|
578
|
+
global chat_history, cache
|
|
579
|
+
context = get_request_context(request, cache)
|
|
580
|
+
system_message = build_selection_prompt(context)
|
|
581
|
+
chat_history.append(system_message)
|
|
582
|
+
return noop_response('chat-select-reference')
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
@app.post('/chat-send-message')
|
|
586
|
+
def chat_send_message(db):
|
|
587
|
+
global chat_history, cache
|
|
588
|
+
context = get_request_context(request, cache)
|
|
589
|
+
assert context.open_ai_api_key is not None, "OpenAI key is None"
|
|
590
|
+
if len(chat_history) == 0:
|
|
591
|
+
# get relevant items based on search filter
|
|
592
|
+
filtered_items, reached_scroll_end = filter_and_sort_items(cache, context, dirty_ranking=True)
|
|
593
|
+
prompts = build_initial_prompts(context, filtered_items)
|
|
594
|
+
for prompt in prompts:
|
|
595
|
+
chat_history.append(prompt)
|
|
596
|
+
else:
|
|
597
|
+
assert chat_history[0]['role'] == 'system'
|
|
598
|
+
user_message = {'role': 'user', 'content': context.chat_user_message}
|
|
599
|
+
chat_history.append(user_message)
|
|
600
|
+
|
|
601
|
+
# web_crawl_system_messages = process_user_message_for_urls(context.chat_user_message)
|
|
602
|
+
# chat_history.extend(web_crawl_system_messages)
|
|
603
|
+
|
|
604
|
+
########################################################
|
|
605
|
+
|
|
606
|
+
# Prepare the payload for the OpenAI API
|
|
607
|
+
data = {
|
|
608
|
+
"model": open_ai_model,
|
|
609
|
+
"messages": chat_history
|
|
610
|
+
}
|
|
611
|
+
headers = {
|
|
612
|
+
"Authorization": f"Bearer {context.open_ai_api_key}",
|
|
613
|
+
"Content-Type": "application/json"
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
# Make a synchronous POST request to the OpenAI Chat API # TODO FastAPI
|
|
617
|
+
openai_response = requests.post(open_ai_url, json=data, headers=headers)
|
|
618
|
+
|
|
619
|
+
# Check if the request was successful and process the response
|
|
620
|
+
if openai_response.status_code == 200:
|
|
621
|
+
openai_data = openai_response.json()
|
|
622
|
+
assistant_message = openai_data['choices'][0]['message']
|
|
623
|
+
msg = {
|
|
624
|
+
'role': assistant_message['role'],
|
|
625
|
+
'content': assistant_message['content']
|
|
626
|
+
}
|
|
627
|
+
chat_history.append(msg)
|
|
628
|
+
return chat_response(chat_history)
|
|
629
|
+
else:
|
|
630
|
+
return error_response('bad response from open ai')
|
|
631
|
+
|
|
632
|
+
|
|
557
633
|
if __name__ == '__main__':
|
|
634
|
+
global development_mode
|
|
635
|
+
development_mode = True
|
|
558
636
|
run_app()
|