Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- .github/workflows/update_space.yml +28 -0
- .gitignore +170 -0
- .gradio/certificate.pem +31 -0
- .pre-commit-config.yaml +20 -0
- .streamlit/config.toml +2 -0
- LICENSE +21 -0
- README.md +98 -7
- __init__.py +0 -0
- data/Fab2Esp_transparent.png +0 -0
- data/Fab2Esp_transparent.png:Zone.Identifier +4 -0
- gradio_app_query_only.py +114 -0
- lib - Shortcut.lnk +0 -0
- logs/fabric_to_espanso.log.1 +0 -0
- main.py +120 -0
- parameters.py +64 -0
- pdm.lock +0 -0
- pyproject.toml +36 -0
- requirements.txt +548 -0
- setup.py +7 -0
- src/__init__.py +0 -0
- src/fabrics_processor/__init__.py +1 -0
- src/fabrics_processor/config.py +129 -0
- src/fabrics_processor/database.py +218 -0
- src/fabrics_processor/database_updater.py +147 -0
- src/fabrics_processor/exceptions.py +37 -0
- src/fabrics_processor/file_change_detector.py +132 -0
- src/fabrics_processor/file_processor.py +141 -0
- src/fabrics_processor/logger.py +60 -0
- src/fabrics_processor/markdown_parser.py +83 -0
- src/fabrics_processor/obsidian2fabric.py +90 -0
- src/fabrics_processor/output_files_generator.py +157 -0
- src/fabrics_processor/output_files_generator_temp.py +113 -0
- src/search_qdrant/__init__.py +0 -0
- src/search_qdrant/database_query.py +57 -0
- src/search_qdrant/logs/fabric_to_espanso.log.1 +135 -0
- src/search_qdrant/logs/fabric_to_espanso.log.2 +136 -0
- src/search_qdrant/logs/fabric_to_espanso.log.3 +136 -0
- src/search_qdrant/logs/fabric_to_espanso.log.4 +0 -0
- src/search_qdrant/run_query.sh +7 -0
- src/search_qdrant/run_streamlit.bup2 +23 -0
- src/search_qdrant/run_streamlit.sh +49 -0
- src/search_qdrant/run_streamlit_query_only_terminal_visible.sh +13 -0
- src/search_qdrant/run_streamlit_terminal_visible.sh +13 -0
- src/search_qdrant/streamlit_app.py +257 -0
- streamlit_app_query_only.py +143 -0
- tests/__init__.py +0 -0
.github/workflows/update_space.yml
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Run Python script
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches:
|
6 |
+
- main
|
7 |
+
|
8 |
+
jobs:
|
9 |
+
build:
|
10 |
+
runs-on: ubuntu-latest
|
11 |
+
|
12 |
+
steps:
|
13 |
+
- name: Checkout
|
14 |
+
uses: actions/checkout@v2
|
15 |
+
|
16 |
+
- name: Set up Python
|
17 |
+
uses: actions/setup-python@v2
|
18 |
+
with:
|
19 |
+
python-version: '3.9'
|
20 |
+
|
21 |
+
- name: Install Gradio
|
22 |
+
run: python -m pip install gradio
|
23 |
+
|
24 |
+
- name: Log in to Hugging Face
|
25 |
+
run: python -c 'import huggingface_hub; huggingface_hub.login(token="${{ secrets.hf_token }}")'
|
26 |
+
|
27 |
+
- name: Deploy to Spaces
|
28 |
+
run: gradio deploy
|
.gitignore
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Own additions
|
2 |
+
nohup.out
|
3 |
+
.streamlit/secrets.toml
|
4 |
+
secret*
|
5 |
+
*.ipynb
|
6 |
+
|
7 |
+
# Byte-compiled / optimized / DLL files
|
8 |
+
__pycache__/
|
9 |
+
*.py[cod]
|
10 |
+
*$py.class
|
11 |
+
|
12 |
+
# C extensions
|
13 |
+
*.so
|
14 |
+
|
15 |
+
# Distribution / packaging
|
16 |
+
.Python
|
17 |
+
build/
|
18 |
+
develop-eggs/
|
19 |
+
dist/
|
20 |
+
downloads/
|
21 |
+
eggs/
|
22 |
+
.eggs/
|
23 |
+
lib/
|
24 |
+
lib64/
|
25 |
+
parts/
|
26 |
+
sdist/
|
27 |
+
var/
|
28 |
+
wheels/
|
29 |
+
share/python-wheels/
|
30 |
+
*.egg-info/
|
31 |
+
.installed.cfg
|
32 |
+
*.egg
|
33 |
+
MANIFEST
|
34 |
+
|
35 |
+
# PyInstaller
|
36 |
+
# Usually these files are written by a python script from a template
|
37 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
38 |
+
*.manifest
|
39 |
+
*.spec
|
40 |
+
|
41 |
+
# Installer logs
|
42 |
+
pip-log.txt
|
43 |
+
pip-delete-this-directory.txt
|
44 |
+
|
45 |
+
# Unit test / coverage reports
|
46 |
+
htmlcov/
|
47 |
+
.tox/
|
48 |
+
.nox/
|
49 |
+
.coverage
|
50 |
+
.coverage.*
|
51 |
+
.cache
|
52 |
+
nosetests.xml
|
53 |
+
coverage.xml
|
54 |
+
*.cover
|
55 |
+
*.py,cover
|
56 |
+
.hypothesis/
|
57 |
+
.pytest_cache/
|
58 |
+
cover/
|
59 |
+
|
60 |
+
# Translations
|
61 |
+
*.mo
|
62 |
+
*.pot
|
63 |
+
|
64 |
+
# Django stuff:
|
65 |
+
*.log
|
66 |
+
local_settings.py
|
67 |
+
db.sqlite3
|
68 |
+
db.sqlite3-journal
|
69 |
+
|
70 |
+
# Flask stuff:
|
71 |
+
instance/
|
72 |
+
.webassets-cache
|
73 |
+
|
74 |
+
# Scrapy stuff:
|
75 |
+
.scrapy
|
76 |
+
|
77 |
+
# Sphinx documentation
|
78 |
+
docs/_build/
|
79 |
+
|
80 |
+
# PyBuilder
|
81 |
+
.pybuilder/
|
82 |
+
target/
|
83 |
+
|
84 |
+
# Jupyter Notebook
|
85 |
+
.ipynb_checkpoints
|
86 |
+
|
87 |
+
# IPython
|
88 |
+
profile_default/
|
89 |
+
ipython_config.py
|
90 |
+
|
91 |
+
# pyenv
|
92 |
+
# For a library or package, you might want to ignore these files since the code is
|
93 |
+
# intended to run in multiple environments; otherwise, check them in:
|
94 |
+
# .python-version
|
95 |
+
|
96 |
+
# pipenv
|
97 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
98 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
99 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
100 |
+
# install all needed dependencies.
|
101 |
+
#Pipfile.lock
|
102 |
+
|
103 |
+
# poetry
|
104 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
105 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
106 |
+
# commonly ignored for libraries.
|
107 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
108 |
+
#poetry.lock
|
109 |
+
|
110 |
+
# pdm
|
111 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
112 |
+
#pdm.lock
|
113 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
114 |
+
# in version control.
|
115 |
+
# https://pdm-project.org/#use-with-ide
|
116 |
+
.pdm.toml
|
117 |
+
.pdm-python
|
118 |
+
.pdm-build/
|
119 |
+
|
120 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
121 |
+
__pypackages__/
|
122 |
+
|
123 |
+
# Celery stuff
|
124 |
+
celerybeat-schedule
|
125 |
+
celerybeat.pid
|
126 |
+
|
127 |
+
# SageMath parsed files
|
128 |
+
*.sage.py
|
129 |
+
|
130 |
+
# Environments
|
131 |
+
.env
|
132 |
+
.venv
|
133 |
+
env/
|
134 |
+
venv/
|
135 |
+
ENV/
|
136 |
+
env.bak/
|
137 |
+
venv.bak/
|
138 |
+
|
139 |
+
# Spyder project settings
|
140 |
+
.spyderproject
|
141 |
+
.spyproject
|
142 |
+
|
143 |
+
# Rope project settings
|
144 |
+
.ropeproject
|
145 |
+
|
146 |
+
# mkdocs documentation
|
147 |
+
/site
|
148 |
+
|
149 |
+
# mypy
|
150 |
+
.mypy_cache/
|
151 |
+
.dmypy.json
|
152 |
+
dmypy.json
|
153 |
+
|
154 |
+
# Pyre type checker
|
155 |
+
.pyre/
|
156 |
+
|
157 |
+
# pytype static type analyzer
|
158 |
+
.pytype/
|
159 |
+
|
160 |
+
# Cython debug symbols
|
161 |
+
cython_debug/
|
162 |
+
|
163 |
+
# PyCharm
|
164 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
165 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
166 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
167 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
168 |
+
#.idea/
|
169 |
+
.streamlit/secrets.toml
|
170 |
+
scratch.ipynb
|
.gradio/certificate.pem
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
-----BEGIN CERTIFICATE-----
|
2 |
+
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
3 |
+
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
4 |
+
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
5 |
+
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
6 |
+
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
7 |
+
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
8 |
+
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
9 |
+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
10 |
+
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
11 |
+
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
12 |
+
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
13 |
+
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
14 |
+
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
15 |
+
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
16 |
+
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
17 |
+
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
18 |
+
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
19 |
+
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
20 |
+
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
21 |
+
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
22 |
+
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
23 |
+
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
24 |
+
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
25 |
+
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
26 |
+
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
27 |
+
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
28 |
+
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
29 |
+
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
30 |
+
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
31 |
+
-----END CERTIFICATE-----
|
.pre-commit-config.yaml
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# .pre-commit-config.yaml
|
2 |
+
repos:
|
3 |
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
4 |
+
rev: v4.4.0
|
5 |
+
hooks:
|
6 |
+
- id: trailing-whitespace
|
7 |
+
- id: end-of-file-fixer
|
8 |
+
- id: check-yaml
|
9 |
+
- id: check-added-large-files
|
10 |
+
|
11 |
+
- repo: https://github.com/psf/black
|
12 |
+
rev: 23.7.0
|
13 |
+
hooks:
|
14 |
+
- id: black
|
15 |
+
|
16 |
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
17 |
+
rev: v1.4.1
|
18 |
+
hooks:
|
19 |
+
- id: mypy
|
20 |
+
additional_dependencies: [types-all]
|
.streamlit/config.toml
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
[server]
|
2 |
+
# Add any Streamlit-specific configurations here
|
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2025 Jelle de Jong
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
README.md
CHANGED
@@ -1,12 +1,103 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
|
4 |
-
colorFrom: purple
|
5 |
-
colorTo: pink
|
6 |
sdk: gradio
|
7 |
sdk_version: 5.12.0
|
8 |
-
app_file: app.py
|
9 |
-
pinned: false
|
10 |
---
|
|
|
11 |
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
title: fabric_to_espanso
|
3 |
+
app_file: gradio_app_query_only.py
|
|
|
|
|
4 |
sdk: gradio
|
5 |
sdk_version: 5.12.0
|
|
|
|
|
6 |
---
|
7 |
+
# Fabric to Espanso Converter
|
8 |
|
9 |
+
A Python application that bridges Fabric prompts with Espanso by managing and converting prompts through a vector database.
|
10 |
+
|
11 |
+
## Features
|
12 |
+
|
13 |
+
- Store and manage Fabric prompts in a Qdrant vector database
|
14 |
+
- Convert stored prompts into Espanso YAML format for system-wide usage
|
15 |
+
- Semantic search functionality to find relevant prompts based on their meaning
|
16 |
+
- Web interface for easy interaction with the prompt database
|
17 |
+
|
18 |
+
## Prerequisites
|
19 |
+
|
20 |
+
- Python 3.11
|
21 |
+
- Qdrant vector database server (local or cloud)
|
22 |
+
- Obsidian with MeshAI plugin installed
|
23 |
+
- Windows (for PowerShell script) or Linux/WSL for direct execution
|
24 |
+
|
25 |
+
## Installation
|
26 |
+
|
27 |
+
1. Install Obsidian and the MeshAI plugin
|
28 |
+
2. In Obsidian, create the following folder structure:
|
29 |
+
```
|
30 |
+
Extra/
|
31 |
+
└── FabricPatterns/
|
32 |
+
├── Official/ # For downloaded Fabric patterns
|
33 |
+
└── Own/ # For your custom additions
|
34 |
+
```
|
35 |
+
3. Clone this repository
|
36 |
+
4. Install dependencies using PDM:
|
37 |
+
```bash
|
38 |
+
pdm install
|
39 |
+
```
|
40 |
+
5. Configure your Qdrant server connection in the application settings
|
41 |
+
|
42 |
+
## Usage
|
43 |
+
|
44 |
+
### Linux/WSL
|
45 |
+
|
46 |
+
Run the Streamlit application directly:
|
47 |
+
```bash
|
48 |
+
./src/search_qdrant/run_streamlit.sh
|
49 |
+
```
|
50 |
+
|
51 |
+
### Windows
|
52 |
+
|
53 |
+
Create a PowerShell script with the following content to start the application:
|
54 |
+
|
55 |
+
```powershell
|
56 |
+
# Start WSL process without showing window
|
57 |
+
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
|
58 |
+
$startInfo.Filename = "wsl.exe"
|
59 |
+
# Use -c flag to let the command use the WSL2 Ubuntu folder system and not the Windows
|
60 |
+
$startInfo.Arguments = "bash -c ~/Tools/pythagora-core/workspace/fabrics_processor/src/search_qdrant/run_streamlit.sh"
|
61 |
+
$startInfo.UseShellExecute = $false
|
62 |
+
$startInfo.RedirectStandardOutput = $true
|
63 |
+
$startInfo.RedirectStandardError = $true
|
64 |
+
$startInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
65 |
+
$startInfo.CreateNoWindow = $true
|
66 |
+
|
67 |
+
# Start the process
|
68 |
+
try {
|
69 |
+
$process = [System.Diagnostics.Process]::Start($startInfo)
|
70 |
+
Start-Sleep -Seconds 5
|
71 |
+
|
72 |
+
# Check if Streamlit is actually running
|
73 |
+
$streamlitRunning = Test-NetConnection -ComputerName localhost -Port 8501 -WarningAction SilentlyContinue
|
74 |
+
|
75 |
+
if ($streamlitRunning.TcpTestSucceeded) {
|
76 |
+
Start-Process "msedge.exe" "--app=http://localhost:8501"
|
77 |
+
} else {
|
78 |
+
Write-Error "Failed to start Streamlit application"
|
79 |
+
}
|
80 |
+
} catch {
|
81 |
+
Write-Error "Error starting Streamlit: $_"
|
82 |
+
}
|
83 |
+
```
|
84 |
+
|
85 |
+
This script will:
|
86 |
+
1. Start the Streamlit server if it's not already running
|
87 |
+
2. Open the application in Microsoft Edge in app mode
|
88 |
+
3. Automatically handle server startup and connection
|
89 |
+
|
90 |
+
## Dependencies
|
91 |
+
|
92 |
+
- ipykernel >= 6.29.5
|
93 |
+
- markdown >= 3.7
|
94 |
+
- pyyaml >= 6.0.2
|
95 |
+
- qdrant-client >= 1.12.1
|
96 |
+
- fastembed >= 0.4.2
|
97 |
+
- streamlit >= 1.41.1
|
98 |
+
- pyperclip >= 1.9.0
|
99 |
+
- regex >= 2024.11.6
|
100 |
+
|
101 |
+
## License
|
102 |
+
|
103 |
+
This project is licensed under the MIT License.
|
__init__.py
ADDED
File without changes
|
data/Fab2Esp_transparent.png
ADDED
![]() |
data/Fab2Esp_transparent.png:Zone.Identifier
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[ZoneTransfer]
|
2 |
+
ZoneId=3
|
3 |
+
ReferrerUrl=https://www7.lunapic.com/editor/?action=save
|
4 |
+
HostUrl=https://www7.lunapic.com/editor/saveas.php
|
gradio_app_query_only.py
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pyperclip
|
3 |
+
from src.fabrics_processor.database import initialize_qdrant_database
|
4 |
+
from src.search_qdrant.database_query import query_qdrant_database
|
5 |
+
from src.fabrics_processor.logger import setup_logger
|
6 |
+
import logging
|
7 |
+
import atexit
|
8 |
+
from src.fabrics_processor.config import config
|
9 |
+
import time
|
10 |
+
import os
|
11 |
+
from dotenv import load_dotenv
|
12 |
+
|
13 |
+
# Load environment variables from .env file
|
14 |
+
load_dotenv()
|
15 |
+
|
16 |
+
# Configure logging
|
17 |
+
logger = setup_logger()
|
18 |
+
|
19 |
+
# Initialize the database client
|
20 |
+
client = None
|
21 |
+
def init_client():
|
22 |
+
global client
|
23 |
+
if client is None:
|
24 |
+
client = initialize_qdrant_database(api_key=os.environ.get("QDRANT_API_KEY"))
|
25 |
+
# Register cleanup function
|
26 |
+
atexit.register(lambda: client.close() if hasattr(client, '_transport') else None)
|
27 |
+
return client
|
28 |
+
|
29 |
+
def search_prompts(query):
|
30 |
+
"""Search for prompts based on the query."""
|
31 |
+
try:
|
32 |
+
client = init_client()
|
33 |
+
results = query_qdrant_database(
|
34 |
+
query=query,
|
35 |
+
client=client,
|
36 |
+
num_results=5,
|
37 |
+
collection_name=config.embedding.collection_name
|
38 |
+
)
|
39 |
+
|
40 |
+
if not results:
|
41 |
+
return gr.Radio(choices=[]), None
|
42 |
+
|
43 |
+
# Format results for radio buttons - just filenames
|
44 |
+
filenames = [r.metadata['filename'] for r in results]
|
45 |
+
# Store the full results for later use
|
46 |
+
global current_results
|
47 |
+
current_results = results
|
48 |
+
return gr.Radio(choices=filenames), None
|
49 |
+
|
50 |
+
except Exception as e:
|
51 |
+
logger.error(f"Error during search: {str(e)}")
|
52 |
+
return gr.Radio(choices=[]), None
|
53 |
+
|
54 |
+
def show_selected_prompt(selected_filename):
|
55 |
+
"""Display the content of the selected prompt."""
|
56 |
+
if not selected_filename or not current_results:
|
57 |
+
return ""
|
58 |
+
|
59 |
+
# Find the selected result
|
60 |
+
selected_prompt = next(
|
61 |
+
(r for r in current_results if r.metadata['filename'] == selected_filename),
|
62 |
+
None
|
63 |
+
)
|
64 |
+
|
65 |
+
if selected_prompt:
|
66 |
+
return selected_prompt.metadata['content']
|
67 |
+
return ""
|
68 |
+
|
69 |
+
# Store current results globally
|
70 |
+
global current_results
|
71 |
+
current_results = []
|
72 |
+
|
73 |
+
with gr.Blocks() as demo:
|
74 |
+
gr.Markdown("# Prompt finding and comparing")
|
75 |
+
|
76 |
+
with gr.Column():
|
77 |
+
query_input = gr.Textbox(
|
78 |
+
label="What are you trying to accomplish? I will then search for good prompts to give you a good start.",
|
79 |
+
lines=3,
|
80 |
+
autofocus=True, # This will focus the textbox when the page loads
|
81 |
+
interactive=True # This enables keyboard events
|
82 |
+
)
|
83 |
+
search_button = gr.Button("Search")
|
84 |
+
|
85 |
+
# Radio buttons for selecting prompts
|
86 |
+
results_radio = gr.Radio(
|
87 |
+
choices=[],
|
88 |
+
label="Select a prompt",
|
89 |
+
interactive=True
|
90 |
+
)
|
91 |
+
|
92 |
+
# Display area for selected prompt using Markdown
|
93 |
+
selected_prompt_display = gr.Markdown(label="Selected Prompt", show_copy_button=True)
|
94 |
+
|
95 |
+
# Set up event handlers
|
96 |
+
query_input.submit(
|
97 |
+
fn=search_prompts,
|
98 |
+
inputs=[query_input],
|
99 |
+
outputs=[results_radio, selected_prompt_display]
|
100 |
+
)
|
101 |
+
search_button.click(
|
102 |
+
fn=search_prompts,
|
103 |
+
inputs=[query_input],
|
104 |
+
outputs=[results_radio, selected_prompt_display]
|
105 |
+
)
|
106 |
+
|
107 |
+
results_radio.change(
|
108 |
+
fn=show_selected_prompt,
|
109 |
+
inputs=[results_radio],
|
110 |
+
outputs=[selected_prompt_display]
|
111 |
+
)
|
112 |
+
|
113 |
+
if __name__ == "__main__":
|
114 |
+
demo.launch(share=True)
|
lib - Shortcut.lnk
ADDED
Binary file (2.72 kB). View file
|
|
logs/fabric_to_espanso.log.1
ADDED
The diff for this file is too large to render.
See raw diff
|
|
main.py
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Main entry point for the Fabric to Espanso conversion process."""
|
2 |
+
from typing import Optional
|
3 |
+
import sys
|
4 |
+
import signal
|
5 |
+
import logging
|
6 |
+
from contextlib import contextmanager
|
7 |
+
|
8 |
+
from src.fabrics_processor.database import initialize_qdrant_database
|
9 |
+
from src.fabrics_processor.file_change_detector import detect_file_changes
|
10 |
+
from src.fabrics_processor.database_updater import update_qdrant_database
|
11 |
+
from src.fabrics_processor.yaml_file_generator import generate_yaml_file
|
12 |
+
from src.fabrics_processor.logger import setup_logger
|
13 |
+
from src.fabrics_processor.config import config
|
14 |
+
from src.fabrics_processor.exceptions import (
|
15 |
+
DatabaseConnectionError,
|
16 |
+
DatabaseInitializationError
|
17 |
+
)
|
18 |
+
|
19 |
+
# Setup logger
|
20 |
+
logger = setup_logger()
|
21 |
+
|
22 |
+
class GracefulExit(SystemExit):
|
23 |
+
"""Custom exception for graceful shutdown."""
|
24 |
+
pass
|
25 |
+
|
26 |
+
def signal_handler(signum, frame):
|
27 |
+
"""Handle shutdown signals gracefully."""
|
28 |
+
logger.info(f"Received signal {signum}. Initiating graceful shutdown...")
|
29 |
+
raise GracefulExit()
|
30 |
+
|
31 |
+
@contextmanager
|
32 |
+
def managed_qdrant_client():
|
33 |
+
"""Context manager for handling Qdrant client lifecycle."""
|
34 |
+
client = None
|
35 |
+
try:
|
36 |
+
client = initialize_qdrant_database()
|
37 |
+
yield client
|
38 |
+
finally:
|
39 |
+
if client:
|
40 |
+
logger.info("Closing Qdrant client connection...")
|
41 |
+
client.close()
|
42 |
+
logger.info("Qdrant client connection closed")
|
43 |
+
|
44 |
+
def process_changes(client) -> bool:
|
45 |
+
"""Process file changes and update database and YAML files.
|
46 |
+
|
47 |
+
Args:
|
48 |
+
client: Initialized Qdrant client
|
49 |
+
|
50 |
+
Returns:
|
51 |
+
bool: True if processing was successful, False otherwise
|
52 |
+
"""
|
53 |
+
try:
|
54 |
+
# Detect file changes
|
55 |
+
new_files, modified_files, deleted_files = detect_file_changes(client, config.fabric_patterns_folder)
|
56 |
+
|
57 |
+
# Log the results
|
58 |
+
if new_files:
|
59 |
+
logger.info(f"New files: {[file['filename'] for file in new_files]}")
|
60 |
+
if modified_files:
|
61 |
+
logger.info(f"Modified files: {[file['filename'] for file in modified_files]}")
|
62 |
+
if deleted_files:
|
63 |
+
logger.info(f"Deleted files: {deleted_files}")
|
64 |
+
|
65 |
+
# Update database if there are changes
|
66 |
+
if any([new_files, modified_files, deleted_files]):
|
67 |
+
logger.info("Changes detected. Updating database...")
|
68 |
+
update_qdrant_database(client, new_files, modified_files, deleted_files)
|
69 |
+
|
70 |
+
# Always generate output files to ensure consistency
|
71 |
+
generate_yaml_file(client, config.yaml_output_folder)
|
72 |
+
|
73 |
+
return True
|
74 |
+
|
75 |
+
except Exception as e:
|
76 |
+
logger.error(f"Error processing changes: {str(e)}", exc_info=True)
|
77 |
+
return False
|
78 |
+
|
79 |
+
def main() -> Optional[int]:
|
80 |
+
"""Main application entry point.
|
81 |
+
|
82 |
+
Returns:
|
83 |
+
Optional[int]: Exit code, None if successful, 1 if error
|
84 |
+
"""
|
85 |
+
# Setup signal handlers
|
86 |
+
signal.signal(signal.SIGINT, signal_handler)
|
87 |
+
signal.signal(signal.SIGTERM, signal_handler)
|
88 |
+
|
89 |
+
try:
|
90 |
+
logger.info("Fabric to Espanso conversion process started")
|
91 |
+
|
92 |
+
# Log configuration
|
93 |
+
logger.info(f"Using configuration:")
|
94 |
+
logger.info(f" Database URL: {config.database.url}")
|
95 |
+
logger.info(f" Fabric patterns folder: {config.fabric_patterns_folder}")
|
96 |
+
logger.info(f" YAML output folder: {config.yaml_output_folder}")
|
97 |
+
logger.info(f" Obsidian textgenerator markdown output folder: {config.markdown_output_folder}")
|
98 |
+
logger.info(f" Obsidian personal prompts input folder: {config.obsidian_input_folder}")
|
99 |
+
|
100 |
+
# Process changes with managed client
|
101 |
+
with managed_qdrant_client() as client:
|
102 |
+
if process_changes(client):
|
103 |
+
logger.info("Fabric to Espanso conversion completed successfully")
|
104 |
+
return None
|
105 |
+
else:
|
106 |
+
logger.error("Fabric to Espanso conversion completed with errors")
|
107 |
+
return 1
|
108 |
+
|
109 |
+
except GracefulExit:
|
110 |
+
logger.info("Gracefully shutting down...")
|
111 |
+
return None
|
112 |
+
except (DatabaseConnectionError, DatabaseInitializationError) as e:
|
113 |
+
logger.error(f"Database error: {str(e)}")
|
114 |
+
return 1
|
115 |
+
except Exception as e:
|
116 |
+
logger.error(f"Unexpected error: {str(e)}", exc_info=True)
|
117 |
+
return 1
|
118 |
+
|
119 |
+
if __name__ == "__main__":
|
120 |
+
sys.exit(main() or 0)
|
parameters.py
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Checks on input data are done in config.py
|
2 |
+
These parameters must be loaded in the script using config.py"""
|
3 |
+
import os
|
4 |
+
|
5 |
+
#
|
6 |
+
# Initialize some automated variables
|
7 |
+
# only needed for updating the database and writing the YAML espanso file
|
8 |
+
# and the markdown Obsidian files
|
9 |
+
# So not necessary for running the streamlit app with query only
|
10 |
+
# These automated variables don't work in the cloud obviously
|
11 |
+
# because the cloud doesn't have a local filesystem
|
12 |
+
# Therefore we first check if we are running in a local WSL environment
|
13 |
+
#
|
14 |
+
# Project root directory
|
15 |
+
is_wsl = os.environ.get('WSL_DISTRO_NAME') is not None
|
16 |
+
|
17 |
+
if is_wsl:
|
18 |
+
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
|
19 |
+
|
20 |
+
# Get Windows user profile path
|
21 |
+
import subprocess
|
22 |
+
windows_user = subprocess.check_output(['cmd.exe', '/c', 'echo %USERNAME%'], text=True).strip()
|
23 |
+
#
|
24 |
+
# User parameters
|
25 |
+
#
|
26 |
+
# Location of input and output files
|
27 |
+
# TODO: make us of ~ possible in setting of path
|
28 |
+
FABRIC_PATTERNS_FOLDER="/home/jelle/.config/fabric/patterns"
|
29 |
+
OBSIDIAN_OUTPUT_FOLDER="/mnt/c/Obsidian/BrainCave/Extra/textgenerator/templates/fabric"
|
30 |
+
OBSIDIAN_INPUT_FOLDER="/mnt/c/Obsidian/BrainCave/d5 WDODelta/50-59 Programmeren en development/56 Generative AI en LLM/56.15 PromptsLibrary"
|
31 |
+
YAML_OUTPUT_FOLDER=f"/mnt/c/Users/{windows_user}/AppData/Roaming/espanso/match"
|
32 |
+
else:
|
33 |
+
windows_user = "cloud_dummy"
|
34 |
+
FABRIC_PATTERNS_FOLDER="cloud_dummy"
|
35 |
+
OBSIDIAN_OUTPUT_FOLDER="cloud_dummy"
|
36 |
+
OBSIDIAN_INPUT_FOLDER="cloud_dummy"
|
37 |
+
YAML_OUTPUT_FOLDER="cloud_dummy"
|
38 |
+
|
39 |
+
# Headings to extract from markdown files
|
40 |
+
BASE_WORDS = ['Identity', 'Purpose', 'Task', 'Goal']
|
41 |
+
|
42 |
+
|
43 |
+
# Qdrant database parameters
|
44 |
+
# TODO: deze paramater wordt nu niet in het script gebruikt, is nu hard coded, dit moet wel gebruikt worden
|
45 |
+
# Local:
|
46 |
+
# QDRANT_URL = "http://localhost:6333"
|
47 |
+
# COLLECTION_NAME = "fabric_patterns"
|
48 |
+
# Cloud:
|
49 |
+
QDRANT_URL = "https://91ed3a93-6135-4951-a624-1c8c2878240d.europe-west3-0.gcp.cloud.qdrant.io:6333"
|
50 |
+
COLLECTION_NAME = "fabric_patterns"
|
51 |
+
|
52 |
+
# Required fields for database points
|
53 |
+
# TODO: default trigger wordt nu twee keer gedefinieerd, oplossen
|
54 |
+
DEFAULT_TRIGGER = ";;fab"
|
55 |
+
REQUIRED_FIELDS = ['filename', 'content', 'purpose', 'filesize', 'trigger']
|
56 |
+
REQUIRED_FIELDS_DEFAULTS = {
|
57 |
+
'trigger': ';;fab',
|
58 |
+
'filesize': 0,
|
59 |
+
'purpose': None # Will be set to content if missing
|
60 |
+
}
|
61 |
+
|
62 |
+
# Embedding Model parameters voor Qdrant
|
63 |
+
USE_FASTEMBED = True
|
64 |
+
EMBED_MODEL = "fast-bge-small-en"
|
pdm.lock
ADDED
The diff for this file is too large to render.
See raw diff
|
|
pyproject.toml
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[project]
|
2 |
+
name = "fabric-to-espanso"
|
3 |
+
version = "0.1.0"
|
4 |
+
description = "Default template for PDM package"
|
5 |
+
authors = [
|
6 |
+
{name = "Hopsakee", email = "[email protected]"},
|
7 |
+
]
|
8 |
+
packages = [
|
9 |
+
{include = "src"},
|
10 |
+
]
|
11 |
+
dependencies = [
|
12 |
+
"ipykernel>=6.29.5",
|
13 |
+
"markdown>=3.7",
|
14 |
+
"pyyaml>=6.0.2",
|
15 |
+
"qdrant-client>=1.12.1",
|
16 |
+
"fastembed>=0.4.2",
|
17 |
+
"streamlit>=1.41.1",
|
18 |
+
"pyperclip>=1.9.0",
|
19 |
+
"regex>=2024.11.6",
|
20 |
+
"fastcore>=1.7.28",
|
21 |
+
"setuptools>=75.8.0",
|
22 |
+
"gradio>=5.12.0",
|
23 |
+
"python-dotenv>=1.0.1",
|
24 |
+
]
|
25 |
+
requires-python = "==3.11.*"
|
26 |
+
readme = "README.md"
|
27 |
+
license = {text = "MIT"}
|
28 |
+
|
29 |
+
|
30 |
+
[tool.pdm]
|
31 |
+
package-dir = "src"
|
32 |
+
distribution = false
|
33 |
+
|
34 |
+
[build-system]
|
35 |
+
requires = ["pdm-backend"]
|
36 |
+
build-backend = "pdm.backend"
|
requirements.txt
ADDED
@@ -0,0 +1,548 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This file is @generated by PDM.
|
2 |
+
# Please do not edit it manually.
|
3 |
+
|
4 |
+
altair==5.5.0 \
|
5 |
+
--hash=sha256:91a310b926508d560fe0148d02a194f38b824122641ef528113d029fcd129f8c \
|
6 |
+
--hash=sha256:d960ebe6178c56de3855a68c47b516be38640b73fb3b5111c2a9ca90546dd73d
|
7 |
+
annotated-types==0.7.0 \
|
8 |
+
--hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
|
9 |
+
--hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
|
10 |
+
anyio==4.7.0 \
|
11 |
+
--hash=sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48 \
|
12 |
+
--hash=sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352
|
13 |
+
appnope==0.1.4; platform_system == "Darwin" \
|
14 |
+
--hash=sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee \
|
15 |
+
--hash=sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c
|
16 |
+
asttokens==2.4.1 \
|
17 |
+
--hash=sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24 \
|
18 |
+
--hash=sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0
|
19 |
+
attrs==24.3.0 \
|
20 |
+
--hash=sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff \
|
21 |
+
--hash=sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308
|
22 |
+
blinker==1.9.0 \
|
23 |
+
--hash=sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf \
|
24 |
+
--hash=sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc
|
25 |
+
cachetools==5.5.0 \
|
26 |
+
--hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \
|
27 |
+
--hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a
|
28 |
+
certifi==2024.8.30 \
|
29 |
+
--hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \
|
30 |
+
--hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9
|
31 |
+
cffi==1.17.1; implementation_name == "pypy" \
|
32 |
+
--hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \
|
33 |
+
--hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \
|
34 |
+
--hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \
|
35 |
+
--hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \
|
36 |
+
--hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \
|
37 |
+
--hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \
|
38 |
+
--hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \
|
39 |
+
--hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \
|
40 |
+
--hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \
|
41 |
+
--hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \
|
42 |
+
--hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \
|
43 |
+
--hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \
|
44 |
+
--hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b
|
45 |
+
charset-normalizer==3.4.0 \
|
46 |
+
--hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \
|
47 |
+
--hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \
|
48 |
+
--hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \
|
49 |
+
--hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \
|
50 |
+
--hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \
|
51 |
+
--hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \
|
52 |
+
--hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \
|
53 |
+
--hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \
|
54 |
+
--hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \
|
55 |
+
--hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \
|
56 |
+
--hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \
|
57 |
+
--hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \
|
58 |
+
--hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \
|
59 |
+
--hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \
|
60 |
+
--hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \
|
61 |
+
--hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \
|
62 |
+
--hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079
|
63 |
+
click==8.1.7 \
|
64 |
+
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
|
65 |
+
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
|
66 |
+
colorama==0.4.6; platform_system == "Windows" or sys_platform == "win32" \
|
67 |
+
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
|
68 |
+
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
|
69 |
+
coloredlogs==15.0.1; python_version >= "3.10" and python_version < "3.13" \
|
70 |
+
--hash=sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934 \
|
71 |
+
--hash=sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0
|
72 |
+
comm==0.2.2 \
|
73 |
+
--hash=sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e \
|
74 |
+
--hash=sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3
|
75 |
+
debugpy==1.8.9 \
|
76 |
+
--hash=sha256:1339e14c7d980407248f09824d1b25ff5c5616651689f1e0f0e51bdead3ea13e \
|
77 |
+
--hash=sha256:62d22dacdb0e296966d7d74a7141aaab4bec123fa43d1a35ddcb39bf9fd29d70 \
|
78 |
+
--hash=sha256:8138efff315cd09b8dcd14226a21afda4ca582284bf4215126d87342bba1cc66 \
|
79 |
+
--hash=sha256:b74a49753e21e33e7cf030883a92fa607bddc4ede1aa4145172debc637780040 \
|
80 |
+
--hash=sha256:cc37a6c9987ad743d9c3a14fa1b1a14b7e4e6041f9dd0c8abf8895fe7a97b899 \
|
81 |
+
--hash=sha256:ff54ef77ad9f5c425398efb150239f6fe8e20c53ae2f68367eba7ece1e96226d
|
82 |
+
decorator==5.1.1 \
|
83 |
+
--hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \
|
84 |
+
--hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186
|
85 |
+
executing==2.1.0 \
|
86 |
+
--hash=sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf \
|
87 |
+
--hash=sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab
|
88 |
+
fastcore==1.7.28 \
|
89 |
+
--hash=sha256:606e4507eb4b8892e4c83ddf5462fbcf32f4bde4fa6caf56ca67ee5e2dbe2b1e \
|
90 |
+
--hash=sha256:ffa1ab1b34518795a4342b85ebb9cd2b30588210c21df028a11e420678a59e20
|
91 |
+
fastembed==0.5.0 \
|
92 |
+
--hash=sha256:420e42ced462e44878065ce13f812485f9788f9f4f1cfd73e075add728d17a70 \
|
93 |
+
--hash=sha256:a1a242ca9ffec866cd0336a435e3169ffb7dd60d67b3f61dbb6683f74e3856cf
|
94 |
+
filelock==3.16.1 \
|
95 |
+
--hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \
|
96 |
+
--hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435
|
97 |
+
flatbuffers==24.3.25; python_version >= "3.10" and python_version < "3.13" \
|
98 |
+
--hash=sha256:8dbdec58f935f3765e4f7f3cf635ac3a77f83568138d6a2311f524ec96364812 \
|
99 |
+
--hash=sha256:de2ec5b203f21441716617f38443e0a8ebf3d25bf0d9c0bb0ce68fa00ad546a4
|
100 |
+
fsspec==2024.10.0 \
|
101 |
+
--hash=sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871 \
|
102 |
+
--hash=sha256:eda2d8a4116d4f2429db8550f2457da57279247dd930bb12f821b58391359493
|
103 |
+
gitdb==4.0.11 \
|
104 |
+
--hash=sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4 \
|
105 |
+
--hash=sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b
|
106 |
+
gitpython==3.1.43 \
|
107 |
+
--hash=sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c \
|
108 |
+
--hash=sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff
|
109 |
+
grpcio==1.68.1 \
|
110 |
+
--hash=sha256:298ee7f80e26f9483f0b6f94cc0a046caf54400a11b644713bb5b3d8eb387600 \
|
111 |
+
--hash=sha256:3522c77d7e6606d6665ec8d50e867f13f946a4e00c7df46768f1c85089eae515 \
|
112 |
+
--hash=sha256:44a8502dd5de653ae6a73e2de50a401d84184f0331d0ac3daeb044e66d5c5054 \
|
113 |
+
--hash=sha256:4b177f5547f1b995826ef529d2eef89cca2f830dd8b2c99ffd5fde4da734ba73 \
|
114 |
+
--hash=sha256:55857c71641064f01ff0541a1776bfe04a59db5558e82897d35a7793e525774c \
|
115 |
+
--hash=sha256:7f20ebec257af55694d8f993e162ddf0d36bd82d4e57f74b31c67b3c6d63d8b2 \
|
116 |
+
--hash=sha256:9d1fae6bbf0816415b81db1e82fb3bf56f7857273c84dcbe68cbe046e58e1ccd \
|
117 |
+
--hash=sha256:b33bd114fa5a83f03ec6b7b262ef9f5cac549d4126f1dc702078767b10c46ed9 \
|
118 |
+
--hash=sha256:cbb5780e2e740b6b4f2d208e90453591036ff80c02cc605fea1af8e6fc6b1bbe \
|
119 |
+
--hash=sha256:ddda1aa22495d8acd9dfbafff2866438d12faec4d024ebc2e656784d96328ad0
|
120 |
+
grpcio-tools==1.68.1 \
|
121 |
+
--hash=sha256:02f04de42834129eb54bb12469160ab631a0395d6a2b77975381c02b994086c3 \
|
122 |
+
--hash=sha256:12239cf5ca6b7b4937103953cf35c49683d935e32e98596fe52dd35168aa86e6 \
|
123 |
+
--hash=sha256:1f0ac6ac5e1e33b998511981b3ef36489501833413354f3597b97a3452d7d7ba \
|
124 |
+
--hash=sha256:2114528723d9f12d3e24af3d433ec6f140deea1dd64d3bb1b4ebced217f1867c \
|
125 |
+
--hash=sha256:21815d54a83effbd2600d16382a7897298cfeffe578557fc9a47b642cc8ddafe \
|
126 |
+
--hash=sha256:2413a17ad16c9c821b36e4a67fc64c37b9e4636ab1c3a07778018801378739ba \
|
127 |
+
--hash=sha256:28e0bca3a262af86557f30e30ddf2fadc2324ee05cd7352716924cc7f83541f1 \
|
128 |
+
--hash=sha256:8e48d8884fcf6b182c73d0560a183404458e30a0f479918b88ca8fbd48b8b05f \
|
129 |
+
--hash=sha256:92b6aab37095879ef9ee428dd171740ff794f4c7a66bc1cc7280cd0051f8cd96 \
|
130 |
+
--hash=sha256:e4e8059469847441855322da16fa2c0f9787b996c237a98778210e31188a8652
|
131 |
+
h11==0.14.0 \
|
132 |
+
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
|
133 |
+
--hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761
|
134 |
+
h2==4.1.0 \
|
135 |
+
--hash=sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d \
|
136 |
+
--hash=sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb
|
137 |
+
hpack==4.0.0 \
|
138 |
+
--hash=sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c \
|
139 |
+
--hash=sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095
|
140 |
+
httpcore==1.0.7 \
|
141 |
+
--hash=sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c \
|
142 |
+
--hash=sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd
|
143 |
+
httpx[http2]==0.28.1 \
|
144 |
+
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
|
145 |
+
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
|
146 |
+
huggingface-hub==0.26.5 \
|
147 |
+
--hash=sha256:1008bd18f60bfb65e8dbc0a97249beeeaa8c99d3c2fa649354df9fa5a13ed83b \
|
148 |
+
--hash=sha256:fb7386090bbe892072e64b85f7c4479fd2d65eea5f2543327c970d5169e83924
|
149 |
+
humanfriendly==10.0; python_version >= "3.10" and python_version < "3.13" \
|
150 |
+
--hash=sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477 \
|
151 |
+
--hash=sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc
|
152 |
+
hyperframe==6.0.1 \
|
153 |
+
--hash=sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15 \
|
154 |
+
--hash=sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914
|
155 |
+
idna==3.10 \
|
156 |
+
--hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
|
157 |
+
--hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
|
158 |
+
ipykernel==6.29.5 \
|
159 |
+
--hash=sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5 \
|
160 |
+
--hash=sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215
|
161 |
+
ipython==8.29.0 \
|
162 |
+
--hash=sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8 \
|
163 |
+
--hash=sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb
|
164 |
+
jedi==0.19.2 \
|
165 |
+
--hash=sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0 \
|
166 |
+
--hash=sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9
|
167 |
+
jinja2==3.1.4 \
|
168 |
+
--hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
|
169 |
+
--hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
|
170 |
+
jsonschema==4.23.0 \
|
171 |
+
--hash=sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4 \
|
172 |
+
--hash=sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566
|
173 |
+
jsonschema-specifications==2024.10.1 \
|
174 |
+
--hash=sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272 \
|
175 |
+
--hash=sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf
|
176 |
+
jupyter-client==8.6.3 \
|
177 |
+
--hash=sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419 \
|
178 |
+
--hash=sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f
|
179 |
+
jupyter-core==5.7.2 \
|
180 |
+
--hash=sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409 \
|
181 |
+
--hash=sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9
|
182 |
+
loguru==0.7.3 \
|
183 |
+
--hash=sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6 \
|
184 |
+
--hash=sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c
|
185 |
+
markdown==3.7 \
|
186 |
+
--hash=sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2 \
|
187 |
+
--hash=sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803
|
188 |
+
markdown-it-py==3.0.0 \
|
189 |
+
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
|
190 |
+
--hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
|
191 |
+
markupsafe==3.0.2 \
|
192 |
+
--hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \
|
193 |
+
--hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \
|
194 |
+
--hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \
|
195 |
+
--hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \
|
196 |
+
--hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \
|
197 |
+
--hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \
|
198 |
+
--hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \
|
199 |
+
--hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \
|
200 |
+
--hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \
|
201 |
+
--hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \
|
202 |
+
--hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0
|
203 |
+
matplotlib-inline==0.1.7 \
|
204 |
+
--hash=sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90 \
|
205 |
+
--hash=sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca
|
206 |
+
mdurl==0.1.2 \
|
207 |
+
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
|
208 |
+
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
|
209 |
+
mmh3==4.1.0 \
|
210 |
+
--hash=sha256:073d57425a23721730d3ff5485e2da489dd3c90b04e86243dd7211f889898106 \
|
211 |
+
--hash=sha256:0dc6dc32eb03727467da8e17deffe004fbb65e8b5ee2b502d36250d7a3f4e2ec \
|
212 |
+
--hash=sha256:1d3b1cdad7c71b7b88966301789a478af142bddcb3a2bee563f7a7d40519a00f \
|
213 |
+
--hash=sha256:3280a463855b0eae64b681cd5b9ddd9464b73f81151e87bb7c91a811d25619e6 \
|
214 |
+
--hash=sha256:4a013979fc9390abadc445ea2527426a0e7a4495c19b74589204f9b71bcaafeb \
|
215 |
+
--hash=sha256:5135358a7e00991f73b88cdc8eda5203bf9de22120d10a834c5761dbeb07dd13 \
|
216 |
+
--hash=sha256:52ba2da04671a9621580ddabf72f06f0e72c1c9c3b7b608849b58b11080d8f14 \
|
217 |
+
--hash=sha256:5a5fef4c4ecc782e6e43fbeab09cff1bac82c998a1773d3a5ee6a3605cde343e \
|
218 |
+
--hash=sha256:71e32ddec7f573a1a0feb8d2cf2af474c50ec21e7a8263026e8d3b4b629805db \
|
219 |
+
--hash=sha256:7cbb20b29d57e76a58b40fd8b13a9130db495a12d678d651b459bf61c0714cea \
|
220 |
+
--hash=sha256:97ac57c6c3301769e757d444fa7c973ceb002cb66534b39cbab5e38de61cd896 \
|
221 |
+
--hash=sha256:9ae3a5c1b32dda121c7dc26f9597ef7b01b4c56a98319a7fe86c35b8bc459ae6 \
|
222 |
+
--hash=sha256:a1cf25348b9acd229dda464a094d6170f47d2850a1fcb762a3b6172d2ce6ca4a \
|
223 |
+
--hash=sha256:a42ad267e131d7847076bb7e31050f6c4378cd38e8f1bf7a0edd32f30224d5c9 \
|
224 |
+
--hash=sha256:a7b6502cdb4dbd880244818ab363c8770a48cdccecf6d729ade0241b736b5ec0 \
|
225 |
+
--hash=sha256:cff9ae76a54f7c6fe0167c9c4028c12c1f6de52d68a31d11b6790bb2ae685560 \
|
226 |
+
--hash=sha256:f6f02576a4d106d7830ca90278868bf0983554dd69183b7bbe09f2fcd51cf54f
|
227 |
+
mpmath==1.3.0; python_version >= "3.10" and python_version < "3.13" \
|
228 |
+
--hash=sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f \
|
229 |
+
--hash=sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c
|
230 |
+
narwhals==1.18.4 \
|
231 |
+
--hash=sha256:b1da4e2e4ab185824781760319ac1ec8ee2944a929795064c3a64ffff16b00c4 \
|
232 |
+
--hash=sha256:c6bb6b6fba59caeab28a7d6ec1e79ab0040c75baef2e4152199ad1a9c266ef96
|
233 |
+
nest-asyncio==1.6.0 \
|
234 |
+
--hash=sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe \
|
235 |
+
--hash=sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c
|
236 |
+
numpy==2.2.0 \
|
237 |
+
--hash=sha256:0557eebc699c1c34cccdd8c3778c9294e8196df27d713706895edc6f57d29608 \
|
238 |
+
--hash=sha256:0da8495970f6b101ddd0c38ace92edea30e7e12b9a926b57f5fabb1ecc25bb90 \
|
239 |
+
--hash=sha256:140dd80ff8981a583a60980be1a655068f8adebf7a45a06a6858c873fcdcd4a0 \
|
240 |
+
--hash=sha256:16757cf28621e43e252c560d25b15f18a2f11da94fea344bf26c599b9cf54b73 \
|
241 |
+
--hash=sha256:3579eaeb5e07f3ded59298ce22b65f877a86ba8e9fe701f5576c99bb17c283da \
|
242 |
+
--hash=sha256:40deb10198bbaa531509aad0cd2f9fadb26c8b94070831e2208e7df543562b74 \
|
243 |
+
--hash=sha256:4723a50e1523e1de4fccd1b9a6dcea750c2102461e9a02b2ac55ffeae09a4410 \
|
244 |
+
--hash=sha256:4e58666988605e251d42c2818c7d3d8991555381be26399303053b58a5bbf30d \
|
245 |
+
--hash=sha256:9874bc2ff574c40ab7a5cbb7464bf9b045d617e36754a7bc93f933d52bd9ffc6 \
|
246 |
+
--hash=sha256:a222d764352c773aa5ebde02dd84dba3279c81c6db2e482d62a3fa54e5ece69b \
|
247 |
+
--hash=sha256:c2aed8fcf8abc3020d6a9ccb31dbc9e7d7819c56a348cc88fd44be269b37427e
|
248 |
+
onnx==1.17.0 \
|
249 |
+
--hash=sha256:081ec43a8b950171767d99075b6b92553901fa429d4bc5eb3ad66b36ef5dbe3a \
|
250 |
+
--hash=sha256:48ca1a91ff73c1d5e3ea2eef20ae5d0e709bb8a2355ed798ffc2169753013fd3 \
|
251 |
+
--hash=sha256:4a183c6178be001bf398260e5ac2c927dc43e7746e8638d6c05c20e321f8c949 \
|
252 |
+
--hash=sha256:95c03e38671785036bb704c30cd2e150825f6ab4763df3a4f1d249da48525957 \
|
253 |
+
--hash=sha256:d6fc3a03fc0129b8b6ac03f03bc894431ffd77c7d79ec023d0afd667b4d35869 \
|
254 |
+
--hash=sha256:f01a4b63d4e1d8ec3e2f069e7b798b2955810aa434f7361f01bc8ca08d69cce4
|
255 |
+
onnxruntime==1.19.2; python_version >= "3.10" and python_version < "3.13" \
|
256 |
+
--hash=sha256:1c3e5d415b78337fa0b1b75291e9ea9fb2a4c1f148eb5811e7212fed02cfffa8 \
|
257 |
+
--hash=sha256:50cbb8dc69d6befad4746a69760e5b00cc3ff0a59c6c3fb27f8afa20e2cab7e7 \
|
258 |
+
--hash=sha256:a36511dc07c5c964b916697e42e366fa43c48cdb3d3503578d78cef30417cb84 \
|
259 |
+
--hash=sha256:c1dfe4f660a71b31caa81fc298a25f9612815215a47b286236e61d540350d7b6 \
|
260 |
+
--hash=sha256:d863e8acdc7232d705d49e41087e10b274c42f09e259016a46f32c34e06dc4fd
|
261 |
+
packaging==24.2 \
|
262 |
+
--hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \
|
263 |
+
--hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f
|
264 |
+
pandas==2.2.3 \
|
265 |
+
--hash=sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32 \
|
266 |
+
--hash=sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5 \
|
267 |
+
--hash=sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667 \
|
268 |
+
--hash=sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3 \
|
269 |
+
--hash=sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039 \
|
270 |
+
--hash=sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd \
|
271 |
+
--hash=sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc \
|
272 |
+
--hash=sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698
|
273 |
+
parso==0.8.4 \
|
274 |
+
--hash=sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18 \
|
275 |
+
--hash=sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d
|
276 |
+
pexpect==4.9.0; sys_platform != "win32" and sys_platform != "emscripten" \
|
277 |
+
--hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 \
|
278 |
+
--hash=sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f
|
279 |
+
pillow==10.4.0 \
|
280 |
+
--hash=sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c \
|
281 |
+
--hash=sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06 \
|
282 |
+
--hash=sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696 \
|
283 |
+
--hash=sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d \
|
284 |
+
--hash=sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3 \
|
285 |
+
--hash=sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6 \
|
286 |
+
--hash=sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496 \
|
287 |
+
--hash=sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319 \
|
288 |
+
--hash=sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe \
|
289 |
+
--hash=sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91 \
|
290 |
+
--hash=sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be \
|
291 |
+
--hash=sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22
|
292 |
+
platformdirs==4.3.6 \
|
293 |
+
--hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \
|
294 |
+
--hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb
|
295 |
+
portalocker==2.10.1 \
|
296 |
+
--hash=sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf \
|
297 |
+
--hash=sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f
|
298 |
+
prompt-toolkit==3.0.48 \
|
299 |
+
--hash=sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90 \
|
300 |
+
--hash=sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e
|
301 |
+
protobuf==5.29.1 \
|
302 |
+
--hash=sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34 \
|
303 |
+
--hash=sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110 \
|
304 |
+
--hash=sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0 \
|
305 |
+
--hash=sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb \
|
306 |
+
--hash=sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d \
|
307 |
+
--hash=sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155 \
|
308 |
+
--hash=sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18
|
309 |
+
psutil==6.1.0 \
|
310 |
+
--hash=sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e \
|
311 |
+
--hash=sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e \
|
312 |
+
--hash=sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a \
|
313 |
+
--hash=sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b \
|
314 |
+
--hash=sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688 \
|
315 |
+
--hash=sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38 \
|
316 |
+
--hash=sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be \
|
317 |
+
--hash=sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a
|
318 |
+
ptyprocess==0.7.0; sys_platform != "win32" and sys_platform != "emscripten" \
|
319 |
+
--hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \
|
320 |
+
--hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220
|
321 |
+
pure-eval==0.2.3 \
|
322 |
+
--hash=sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0 \
|
323 |
+
--hash=sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42
|
324 |
+
py-rust-stemmers==0.1.3 \
|
325 |
+
--hash=sha256:02b347ab8fe686a88aef0432060471d501b37a6b9a868e7c50bffcd382269cf2 \
|
326 |
+
--hash=sha256:2d8b8e6b6d5839a168dae510a00ff4662c7d0a22d12f24fe81caa0ac59265711 \
|
327 |
+
--hash=sha256:47211ac6252eb484f5067d30b1812667936deffcef89b4b0acd2efe881a99aed \
|
328 |
+
--hash=sha256:658784c0072f7aae67c726be9acac40dd27b29416356c63a3a760a9499a93513 \
|
329 |
+
--hash=sha256:72a7b810d8d376c03f0ccebe146f04cbf4c6c97bd74e489b0ddf1342eb40970c \
|
330 |
+
--hash=sha256:9fbbb37e0df579859b42b3f850aa08fe829d190d32c6338349eccb0e762b74c6 \
|
331 |
+
--hash=sha256:ad796d47874181a25addb505a04245e34620bd7a0c5055671f52d9ce993253e2 \
|
332 |
+
--hash=sha256:d4a65b429eb1282934a1cc3c1b2698ae32a6dc00d6be00dd747e688c642eb110 \
|
333 |
+
--hash=sha256:d6f9790fe1e9962787817b1894486df7e0b5fc59e4adad423e189530530fae11 \
|
334 |
+
--hash=sha256:e6afcd19da56d4182eecb43bdb6c5b9686370063f2538df877fc23f1d16f909e \
|
335 |
+
--hash=sha256:fd5d7388f807f584b4c55bfbe608ef40cff0024c1dc54de95d28265395065d02
|
336 |
+
pyarrow==18.1.0 \
|
337 |
+
--hash=sha256:01c034b576ce0eef554f7c3d8c341714954be9b3f5d5bc7117006b85fcf302fe \
|
338 |
+
--hash=sha256:3b2e2239339c538f3464308fd345113f886ad031ef8266c6f004d49769bb074c \
|
339 |
+
--hash=sha256:9386d3ca9c145b5539a1cfc75df07757dff870168c959b473a0bccbc3abc8c73 \
|
340 |
+
--hash=sha256:d4f13eee18433f99adefaeb7e01d83b59f73360c231d4782d9ddfaf1c3fbde0a \
|
341 |
+
--hash=sha256:e31e9417ba9c42627574bdbfeada7217ad8a4cbbe45b9d6bdd4b62abbca4c6f6 \
|
342 |
+
--hash=sha256:eaeabf638408de2772ce3d7793b2668d4bb93807deed1725413b70e3156a7854 \
|
343 |
+
--hash=sha256:f266a2c0fc31995a06ebd30bcfdb7f615d7278035ec5b1cd71c48d56daaf30b0 \
|
344 |
+
--hash=sha256:f39a2e0ed32a0970e4e46c262753417a60c43a3246972cfc2d3eb85aedd01b21
|
345 |
+
pycparser==2.22; implementation_name == "pypy" \
|
346 |
+
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
|
347 |
+
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
|
348 |
+
pydantic==2.10.3 \
|
349 |
+
--hash=sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d \
|
350 |
+
--hash=sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9
|
351 |
+
pydantic-core==2.27.1 \
|
352 |
+
--hash=sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919 \
|
353 |
+
--hash=sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9 \
|
354 |
+
--hash=sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c \
|
355 |
+
--hash=sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5 \
|
356 |
+
--hash=sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e \
|
357 |
+
--hash=sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235 \
|
358 |
+
--hash=sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52 \
|
359 |
+
--hash=sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89 \
|
360 |
+
--hash=sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de \
|
361 |
+
--hash=sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c \
|
362 |
+
--hash=sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330 \
|
363 |
+
--hash=sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8 \
|
364 |
+
--hash=sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025 \
|
365 |
+
--hash=sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4 \
|
366 |
+
--hash=sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc
|
367 |
+
pydeck==0.9.1 \
|
368 |
+
--hash=sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038 \
|
369 |
+
--hash=sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605
|
370 |
+
pygments==2.18.0 \
|
371 |
+
--hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \
|
372 |
+
--hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
|
373 |
+
pyperclip==1.9.0 \
|
374 |
+
--hash=sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310
|
375 |
+
pyreadline3==3.5.4; sys_platform == "win32" and python_version >= "3.10" and python_version < "3.13" \
|
376 |
+
--hash=sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7 \
|
377 |
+
--hash=sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6
|
378 |
+
python-dateutil==2.9.0.post0 \
|
379 |
+
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
|
380 |
+
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
|
381 |
+
pytz==2024.2 \
|
382 |
+
--hash=sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a \
|
383 |
+
--hash=sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725
|
384 |
+
pywin32==308; sys_platform == "win32" and platform_python_implementation != "PyPy" or platform_system == "Windows" \
|
385 |
+
--hash=sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6 \
|
386 |
+
--hash=sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b \
|
387 |
+
--hash=sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a
|
388 |
+
pyyaml==6.0.2 \
|
389 |
+
--hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \
|
390 |
+
--hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \
|
391 |
+
--hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \
|
392 |
+
--hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \
|
393 |
+
--hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \
|
394 |
+
--hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \
|
395 |
+
--hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \
|
396 |
+
--hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \
|
397 |
+
--hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \
|
398 |
+
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
|
399 |
+
pyzmq==26.2.0 \
|
400 |
+
--hash=sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f \
|
401 |
+
--hash=sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37 \
|
402 |
+
--hash=sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3 \
|
403 |
+
--hash=sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4 \
|
404 |
+
--hash=sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5 \
|
405 |
+
--hash=sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6 \
|
406 |
+
--hash=sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e \
|
407 |
+
--hash=sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317 \
|
408 |
+
--hash=sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef \
|
409 |
+
--hash=sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218 \
|
410 |
+
--hash=sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf \
|
411 |
+
--hash=sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003 \
|
412 |
+
--hash=sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4
|
413 |
+
qdrant-client==1.12.2 \
|
414 |
+
--hash=sha256:2777e09b3e89bb22bb490384d8b1fa8140f3915287884f18984f7031a346aba5 \
|
415 |
+
--hash=sha256:a0ae500a46a679ff3521ba3f1f1cf3d72b57090a768cec65fc317066bcbac1e6
|
416 |
+
referencing==0.35.1 \
|
417 |
+
--hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \
|
418 |
+
--hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de
|
419 |
+
regex==2024.11.6 \
|
420 |
+
--hash=sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60 \
|
421 |
+
--hash=sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d \
|
422 |
+
--hash=sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114 \
|
423 |
+
--hash=sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3 \
|
424 |
+
--hash=sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d \
|
425 |
+
--hash=sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7 \
|
426 |
+
--hash=sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f \
|
427 |
+
--hash=sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34 \
|
428 |
+
--hash=sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638 \
|
429 |
+
--hash=sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519 \
|
430 |
+
--hash=sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20 \
|
431 |
+
--hash=sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89 \
|
432 |
+
--hash=sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45 \
|
433 |
+
--hash=sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55 \
|
434 |
+
--hash=sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9 \
|
435 |
+
--hash=sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0
|
436 |
+
requests==2.32.3 \
|
437 |
+
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
438 |
+
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
439 |
+
rich==13.9.4 \
|
440 |
+
--hash=sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098 \
|
441 |
+
--hash=sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90
|
442 |
+
rpds-py==0.22.3 \
|
443 |
+
--hash=sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2 \
|
444 |
+
--hash=sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a \
|
445 |
+
--hash=sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d \
|
446 |
+
--hash=sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1 \
|
447 |
+
--hash=sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a \
|
448 |
+
--hash=sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0 \
|
449 |
+
--hash=sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c \
|
450 |
+
--hash=sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64 \
|
451 |
+
--hash=sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb \
|
452 |
+
--hash=sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f \
|
453 |
+
--hash=sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d \
|
454 |
+
--hash=sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74 \
|
455 |
+
--hash=sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648 \
|
456 |
+
--hash=sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5
|
457 |
+
setuptools==75.8.0 \
|
458 |
+
--hash=sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6 \
|
459 |
+
--hash=sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3
|
460 |
+
six==1.16.0 \
|
461 |
+
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
|
462 |
+
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
|
463 |
+
smmap==5.0.1 \
|
464 |
+
--hash=sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62 \
|
465 |
+
--hash=sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da
|
466 |
+
sniffio==1.3.1 \
|
467 |
+
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
|
468 |
+
--hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
|
469 |
+
stack-data==0.6.3 \
|
470 |
+
--hash=sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9 \
|
471 |
+
--hash=sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695
|
472 |
+
streamlit==1.41.1 \
|
473 |
+
--hash=sha256:0def00822480071d642e6df36cd63c089f991da3a69fd9eb4ab8f65ce27de4e0 \
|
474 |
+
--hash=sha256:6626d32b098ba1458b71eebdd634c62af2dd876380e59c4b6a1e828a39d62d69
|
475 |
+
sympy==1.13.3; python_version >= "3.10" and python_version < "3.13" \
|
476 |
+
--hash=sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73 \
|
477 |
+
--hash=sha256:b27fd2c6530e0ab39e275fc9b683895367e51d5da91baa8d3d64db2565fec4d9
|
478 |
+
tenacity==9.0.0 \
|
479 |
+
--hash=sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b \
|
480 |
+
--hash=sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539
|
481 |
+
tokenizers==0.21.0 \
|
482 |
+
--hash=sha256:089d56db6782a73a27fd8abf3ba21779f5b85d4a9f35e3b493c7bbcbbf0d539b \
|
483 |
+
--hash=sha256:3c4c93eae637e7d2aaae3d376f06085164e1660f89304c0ab2b1d08a406636b2 \
|
484 |
+
--hash=sha256:400832c0904f77ce87c40f1a8a27493071282f785724ae62144324f171377273 \
|
485 |
+
--hash=sha256:4145505a973116f91bc3ac45988a92e618a6f83eb458f49ea0790df94ee243ff \
|
486 |
+
--hash=sha256:6b177fb54c4702ef611de0c069d9169f0004233890e0c4c5bd5508ae05abf193 \
|
487 |
+
--hash=sha256:6b43779a269f4629bebb114e19c3fca0223296ae9fea8bb9a7a6c6fb0657ff8e \
|
488 |
+
--hash=sha256:87841da5a25a3a5f70c102de371db120f41873b854ba65e52bccd57df5a3780c \
|
489 |
+
--hash=sha256:9aeb255802be90acfd363626753fda0064a8df06031012fe7d52fd9a905eb00e \
|
490 |
+
--hash=sha256:c87ca3dc48b9b1222d984b6b7490355a6fdb411a2d810f6f05977258400ddb74 \
|
491 |
+
--hash=sha256:d8b09dbeb7a8d73ee204a70f94fc06ea0f17dcf0844f16102b9f414f0b7463ba \
|
492 |
+
--hash=sha256:e84ca973b3a96894d1707e189c14a774b701596d579ffc7e69debfc036a61a04 \
|
493 |
+
--hash=sha256:eb1702c2f27d25d9dd5b389cc1f2f51813e99f8ca30d9e25348db6585a97e24a \
|
494 |
+
--hash=sha256:eb7202d231b273c34ec67767378cd04c767e967fda12d4a9e36208a34e2f137e \
|
495 |
+
--hash=sha256:ee0894bf311b75b0c03079f33859ae4b2334d675d4e93f5a4132e1eae2834fe4 \
|
496 |
+
--hash=sha256:f53ea537c925422a2e0e92a24cce96f6bc5046bbef24a1652a5edc8ba975f62e
|
497 |
+
toml==0.10.2 \
|
498 |
+
--hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \
|
499 |
+
--hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f
|
500 |
+
tornado==6.4.2 \
|
501 |
+
--hash=sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803 \
|
502 |
+
--hash=sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec \
|
503 |
+
--hash=sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482 \
|
504 |
+
--hash=sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634 \
|
505 |
+
--hash=sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38 \
|
506 |
+
--hash=sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b \
|
507 |
+
--hash=sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c \
|
508 |
+
--hash=sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf \
|
509 |
+
--hash=sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946 \
|
510 |
+
--hash=sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73 \
|
511 |
+
--hash=sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1
|
512 |
+
tqdm==4.67.1 \
|
513 |
+
--hash=sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2 \
|
514 |
+
--hash=sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2
|
515 |
+
traitlets==5.14.3 \
|
516 |
+
--hash=sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7 \
|
517 |
+
--hash=sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f
|
518 |
+
typing-extensions==4.12.2 \
|
519 |
+
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
|
520 |
+
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
|
521 |
+
tzdata==2024.2 \
|
522 |
+
--hash=sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc \
|
523 |
+
--hash=sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd
|
524 |
+
urllib3==2.2.3 \
|
525 |
+
--hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \
|
526 |
+
--hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9
|
527 |
+
watchdog==6.0.0; platform_system != "Darwin" \
|
528 |
+
--hash=sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a \
|
529 |
+
--hash=sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2 \
|
530 |
+
--hash=sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f \
|
531 |
+
--hash=sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c \
|
532 |
+
--hash=sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c \
|
533 |
+
--hash=sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13 \
|
534 |
+
--hash=sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e \
|
535 |
+
--hash=sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379 \
|
536 |
+
--hash=sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282 \
|
537 |
+
--hash=sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f \
|
538 |
+
--hash=sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c \
|
539 |
+
--hash=sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680 \
|
540 |
+
--hash=sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26 \
|
541 |
+
--hash=sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2
|
542 |
+
wcwidth==0.2.13 \
|
543 |
+
--hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \
|
544 |
+
--hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5
|
545 |
+
win32-setctime==1.2.0; sys_platform == "win32" \
|
546 |
+
--hash=sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390 \
|
547 |
+
--hash=sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0
|
548 |
+
|
setup.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from setuptools import setup, find_packages
|
2 |
+
|
3 |
+
setup(
|
4 |
+
name="fabric-to-espanso",
|
5 |
+
packages=find_packages(),
|
6 |
+
include_package_data=True,
|
7 |
+
)
|
src/__init__.py
ADDED
File without changes
|
src/fabrics_processor/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
from .database import initialize_qdrant_database
|
src/fabrics_processor/config.py
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Configuration management for fabric-to-espanso."""
|
2 |
+
# TODO: check if config.validate wel gebruikt wordt
|
3 |
+
|
4 |
+
from typing import Dict, Any, Optional
|
5 |
+
from dataclasses import dataclass, field
|
6 |
+
from urllib.parse import urlparse
|
7 |
+
from pathlib import Path
|
8 |
+
import logging
|
9 |
+
|
10 |
+
from parameters import (
|
11 |
+
FABRIC_PATTERNS_FOLDER,
|
12 |
+
YAML_OUTPUT_FOLDER,
|
13 |
+
DEFAULT_TRIGGER,
|
14 |
+
OBSIDIAN_OUTPUT_FOLDER,
|
15 |
+
OBSIDIAN_INPUT_FOLDER,
|
16 |
+
BASE_WORDS,
|
17 |
+
QDRANT_URL,
|
18 |
+
USE_FASTEMBED,
|
19 |
+
EMBED_MODEL,
|
20 |
+
COLLECTION_NAME,
|
21 |
+
REQUIRED_FIELDS,
|
22 |
+
REQUIRED_FIELDS_DEFAULTS
|
23 |
+
)
|
24 |
+
|
25 |
+
logger = logging.getLogger('fabric_to_espanso')
|
26 |
+
|
27 |
+
@dataclass
|
28 |
+
class DatabaseConfig:
|
29 |
+
"""Database configuration settings."""
|
30 |
+
url: str = QDRANT_URL
|
31 |
+
max_retries: int = 3
|
32 |
+
retry_delay: float = 1.0
|
33 |
+
timeout: float = 10.0
|
34 |
+
api_key: Optional[str] = None
|
35 |
+
required_fields: list = field(default_factory=lambda: REQUIRED_FIELDS)
|
36 |
+
required_fields_defaults: dict = field(default_factory=lambda: REQUIRED_FIELDS_DEFAULTS)
|
37 |
+
|
38 |
+
|
39 |
+
def validate(self) -> None:
|
40 |
+
"""Validate the database configuration.
|
41 |
+
|
42 |
+
Raises:
|
43 |
+
ConfigurationError: If any configuration values are invalid.
|
44 |
+
"""
|
45 |
+
try:
|
46 |
+
result = urlparse(self.url)
|
47 |
+
if not all([result.scheme, result.netloc]):
|
48 |
+
raise ValueError(f"Invalid database URL: {self.url}")
|
49 |
+
|
50 |
+
if self.max_retries < 0:
|
51 |
+
raise ValueError(f"max_retries must be >= 0, got {self.max_retries}")
|
52 |
+
|
53 |
+
if self.retry_delay <= 0:
|
54 |
+
raise ValueError(f"retry_delay must be > 0, got {self.retry_delay}")
|
55 |
+
|
56 |
+
if self.timeout <= 0:
|
57 |
+
raise ValueError(f"timeout must be > 0, got {self.timeout}")
|
58 |
+
|
59 |
+
except ValueError as e:
|
60 |
+
from .exceptions import ConfigurationError
|
61 |
+
raise ConfigurationError(str(e))
|
62 |
+
|
63 |
+
@dataclass
|
64 |
+
class EmbeddingConfig:
|
65 |
+
"""Embedding model configuration."""
|
66 |
+
use_fastembed: bool = USE_FASTEMBED
|
67 |
+
model_name: str = EMBED_MODEL
|
68 |
+
collection_name: str = COLLECTION_NAME
|
69 |
+
vector_size: int = 384
|
70 |
+
|
71 |
+
def validate(self) -> None:
|
72 |
+
"""Validate the embedding configuration."""
|
73 |
+
if not self.model_name:
|
74 |
+
from .exceptions import ConfigurationError
|
75 |
+
raise ConfigurationError("Embedding model name cannot be empty")
|
76 |
+
|
77 |
+
if self.vector_size <= 0:
|
78 |
+
from .exceptions import ConfigurationError
|
79 |
+
raise ConfigurationError(f"Vector size must be > 0, got {self.vector_size}")
|
80 |
+
|
81 |
+
class Config:
|
82 |
+
"""Global configuration singleton."""
|
83 |
+
_instance: Optional['Config'] = None
|
84 |
+
|
85 |
+
def __new__(cls) -> 'Config':
|
86 |
+
if cls._instance is None:
|
87 |
+
cls._instance = super().__new__(cls)
|
88 |
+
cls._instance.database = DatabaseConfig()
|
89 |
+
cls._instance.embedding = EmbeddingConfig()
|
90 |
+
cls._instance.espanso_trigger = DEFAULT_TRIGGER
|
91 |
+
cls._instance.fabric_patterns_folder = FABRIC_PATTERNS_FOLDER
|
92 |
+
cls._instance.yaml_output_folder = YAML_OUTPUT_FOLDER
|
93 |
+
cls._instance.obsidian_output_folder = OBSIDIAN_OUTPUT_FOLDER
|
94 |
+
cls._instance.obsidian_input_folder = OBSIDIAN_INPUT_FOLDER
|
95 |
+
cls._instance.base_words = BASE_WORDS
|
96 |
+
return cls._instance
|
97 |
+
|
98 |
+
def validate(self) -> None:
|
99 |
+
"""Validate all configuration settings."""
|
100 |
+
self.database.validate()
|
101 |
+
self.embedding.validate()
|
102 |
+
|
103 |
+
# Validate paths
|
104 |
+
if not self.espanso_trigger:
|
105 |
+
from .exceptions import ConfigurationError
|
106 |
+
raise ConfigurationError("The default trigger for espanso patterns cannot be empty")
|
107 |
+
|
108 |
+
if not self.fabric_patterns_folder:
|
109 |
+
from .exceptions import ConfigurationError
|
110 |
+
raise ConfigurationError("The fabric patterns folder path cannot be empty")
|
111 |
+
|
112 |
+
if not self.yaml_output_folder:
|
113 |
+
from .exceptions import ConfigurationError
|
114 |
+
raise ConfigurationError("YAML output folder path for espanso cannot be empty")
|
115 |
+
|
116 |
+
if not self.obsidian_output_folder:
|
117 |
+
from .exceptions import ConfigurationError
|
118 |
+
raise ConfigurationError("Obsidian output folder path to write the files for Obsidian Textgenerator cannot be empty")
|
119 |
+
|
120 |
+
if not self.obsidian_input_folder:
|
121 |
+
from .exceptions import ConfigurationError
|
122 |
+
raise ConfigurationError("Obsidian input folder path to find the personal prompts stored in Obsidian cannot be empty")
|
123 |
+
|
124 |
+
for path in [self.fabric_patterns_folder, self.yaml_output_folder, self.obsidian_output_folder, self.obsidian_input_folder]:
|
125 |
+
if not path == "cloud_dummy" and not Path(path).is_dir():
|
126 |
+
from .exceptions import ConfigurationError
|
127 |
+
raise ConfigurationError(f"{path} is not a valid directory")
|
128 |
+
# Global configuration instance
|
129 |
+
config = Config()
|
src/fabrics_processor/database.py
ADDED
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Database management for fabric-to-espanso."""
|
2 |
+
from typing import Optional, List, Dict
|
3 |
+
import logging
|
4 |
+
import time
|
5 |
+
|
6 |
+
from qdrant_client import QdrantClient
|
7 |
+
from qdrant_client.http import models, exceptions
|
8 |
+
from qdrant_client.http.models import Distance, VectorParams, PointStruct
|
9 |
+
|
10 |
+
from .config import config
|
11 |
+
from .exceptions import DatabaseConnectionError, CollectionError, DatabaseInitializationError, ConfigurationError
|
12 |
+
|
13 |
+
logger = logging.getLogger('fabric_to_espanso')
|
14 |
+
|
15 |
+
def create_database_connection(url: Optional[str] = None, api_key: Optional[str] = None) -> QdrantClient:
|
16 |
+
"""Create a database connection.
|
17 |
+
|
18 |
+
Args:
|
19 |
+
url: Optional database URL. If not provided, uses configuration.
|
20 |
+
|
21 |
+
Returns:
|
22 |
+
QdrantClient: Connected database client
|
23 |
+
|
24 |
+
Raises:
|
25 |
+
DatabaseConnectionError: If connection fails after retries
|
26 |
+
"""
|
27 |
+
url = url or config.database.url
|
28 |
+
for attempt in range(config.database.max_retries + 1):
|
29 |
+
try:
|
30 |
+
client = QdrantClient(
|
31 |
+
url=url,
|
32 |
+
timeout=config.database.timeout,
|
33 |
+
api_key=api_key
|
34 |
+
)
|
35 |
+
# Test connection
|
36 |
+
client.get_collections()
|
37 |
+
return client
|
38 |
+
except Exception as e:
|
39 |
+
if attempt == config.database.max_retries:
|
40 |
+
raise DatabaseConnectionError(
|
41 |
+
f"Failed to connect to database at {url} after "
|
42 |
+
f"{config.database.max_retries} attempts: {str(e)}"
|
43 |
+
) from e
|
44 |
+
logger.warning(
|
45 |
+
f"Connection attempt {attempt + 1} failed, retrying in "
|
46 |
+
f"{config.database.retry_delay} seconds..."
|
47 |
+
)
|
48 |
+
time.sleep(config.database.retry_delay)
|
49 |
+
|
50 |
+
def initialize_qdrant_database(
|
51 |
+
url: str = config.database.url,
|
52 |
+
api_key: Optional[str] = "",
|
53 |
+
collection_name: str = config.embedding.collection_name,
|
54 |
+
use_fastembed: bool = config.embedding.use_fastembed,
|
55 |
+
embed_model: str = config.embedding.model_name
|
56 |
+
) -> QdrantClient:
|
57 |
+
"""Initialize the Qdrant database for storing markdown file information.
|
58 |
+
|
59 |
+
Args:
|
60 |
+
collection_name: Name of the collection to initialize
|
61 |
+
use_fastembed: Whether to use FastEmbed for embeddings
|
62 |
+
embed_model: Name of the embedding model to use
|
63 |
+
|
64 |
+
Returns:
|
65 |
+
QdrantClient: Initialized database client
|
66 |
+
|
67 |
+
Raises:
|
68 |
+
DatabaseInitializationError: If initialization fails
|
69 |
+
CollectionError: If collection creation fails
|
70 |
+
ConfigurationError: If configuration is invalid
|
71 |
+
"""
|
72 |
+
try:
|
73 |
+
# Validate configuration
|
74 |
+
config.validate()
|
75 |
+
|
76 |
+
# Create database connection
|
77 |
+
client = create_database_connection(url=url, api_key=api_key)
|
78 |
+
|
79 |
+
# Check if collection exists
|
80 |
+
collections = client.get_collections()
|
81 |
+
collection_names = [c.name for c in collections.collections]
|
82 |
+
|
83 |
+
if collection_name not in collection_names:
|
84 |
+
logger.info(f"Creating new collection: {collection_name}")
|
85 |
+
|
86 |
+
# Create collection with appropriate vector configuration
|
87 |
+
if use_fastembed:
|
88 |
+
vector_config = client.get_fastembed_vector_params()
|
89 |
+
else:
|
90 |
+
vector_config = {
|
91 |
+
embed_model: VectorParams(
|
92 |
+
size=config.embedding.vector_size,
|
93 |
+
distance=Distance.COSINE
|
94 |
+
)
|
95 |
+
}
|
96 |
+
|
97 |
+
try:
|
98 |
+
client.create_collection(
|
99 |
+
collection_name=collection_name,
|
100 |
+
vectors_config=vector_config,
|
101 |
+
on_disk_payload=True
|
102 |
+
)
|
103 |
+
except exceptions.UnexpectedResponse as e:
|
104 |
+
raise CollectionError(
|
105 |
+
f"Failed to create collection {collection_name}: {str(e)}"
|
106 |
+
) from e
|
107 |
+
|
108 |
+
# Create indexes for efficient searching
|
109 |
+
for field_name, field_type in [
|
110 |
+
("filename", models.PayloadSchemaType.KEYWORD),
|
111 |
+
("date", models.PayloadSchemaType.DATETIME)
|
112 |
+
]:
|
113 |
+
client.create_payload_index(
|
114 |
+
collection_name=collection_name,
|
115 |
+
field_name=field_name,
|
116 |
+
field_schema=field_type
|
117 |
+
)
|
118 |
+
logger.info(f"Created indexes for collection {collection_name}")
|
119 |
+
|
120 |
+
# Log collection status
|
121 |
+
collection_info = client.get_collection(collection_name)
|
122 |
+
logger.info(
|
123 |
+
f"Collection {collection_name} ready with "
|
124 |
+
f"{collection_info.points_count} points"
|
125 |
+
)
|
126 |
+
|
127 |
+
return client
|
128 |
+
|
129 |
+
except Exception as e:
|
130 |
+
logger.error(f"Database initialization failed: {str(e)}", exc_info=True)
|
131 |
+
if isinstance(e, (DatabaseConnectionError, CollectionError)):
|
132 |
+
raise
|
133 |
+
raise DatabaseInitializationError(str(e)) from e
|
134 |
+
|
135 |
+
def validate_database_payload(
|
136 |
+
client: QdrantClient,
|
137 |
+
collection_name: str,
|
138 |
+
) -> Dict:
|
139 |
+
"""Validate the payload of all points in the Qdrant database.
|
140 |
+
|
141 |
+
Args:
|
142 |
+
client: Initialized Qdrant client
|
143 |
+
collection_name: Name of the collection to validate
|
144 |
+
"""
|
145 |
+
|
146 |
+
# First validate existing points in database
|
147 |
+
logger.info("Validating existing database points...")
|
148 |
+
offset = None
|
149 |
+
|
150 |
+
while True:
|
151 |
+
scroll_result = client.scroll(
|
152 |
+
collection_name=collection_name,
|
153 |
+
limit=5, # Process in batches of 5
|
154 |
+
offset=offset
|
155 |
+
)
|
156 |
+
|
157 |
+
points, offset = scroll_result
|
158 |
+
|
159 |
+
for point in points:
|
160 |
+
try:
|
161 |
+
fixed_payload = validate_point_payload(point.payload, point.id)
|
162 |
+
if fixed_payload != point.payload:
|
163 |
+
# Update point with fixed payload
|
164 |
+
point_struct = PointStruct(
|
165 |
+
id=point.id,
|
166 |
+
vector=point.vector,
|
167 |
+
payload=fixed_payload
|
168 |
+
)
|
169 |
+
client.upsert(collection_name=collection_name, points=[point_struct])
|
170 |
+
logger.info(f"Fixed and updated point {point.id} in database")
|
171 |
+
except ConfigurationError as e:
|
172 |
+
logger.error(str(e))
|
173 |
+
|
174 |
+
if not offset: # No more points to process
|
175 |
+
break
|
176 |
+
|
177 |
+
logger.info("Database validation completed")
|
178 |
+
|
179 |
+
def validate_point_payload(payload: dict, point_id: Optional[str] = None) -> dict:
|
180 |
+
"""Validate and fix point payload fields.
|
181 |
+
Only use if somehow many points have become corrupted.
|
182 |
+
|
183 |
+
Args:
|
184 |
+
payload (dict): Point payload to validate
|
185 |
+
point_id (str, optional): ID of the point for logging purposes
|
186 |
+
|
187 |
+
Returns:
|
188 |
+
dict: Validated and potentially fixed payload
|
189 |
+
|
190 |
+
Raises:
|
191 |
+
ConfigurationError: If required fields are missing and cannot be fixed
|
192 |
+
"""
|
193 |
+
print(f"Validating point {point_id if point_id else ''}")
|
194 |
+
from .exceptions import ConfigurationError
|
195 |
+
|
196 |
+
# Check for critical fields
|
197 |
+
if 'filename' not in payload or 'content' not in payload:
|
198 |
+
error_msg = f"Point {point_id if point_id else ''} is missing critical fields: "
|
199 |
+
error_msg += "'filename' and/or 'content' are required and cannot be defaulted"
|
200 |
+
raise ConfigurationError(error_msg)
|
201 |
+
|
202 |
+
# Copy payload to avoid modifying the original
|
203 |
+
fixed_payload = payload.copy()
|
204 |
+
|
205 |
+
# Apply defaults and fixes for non-critical fields
|
206 |
+
if 'purpose' not in fixed_payload or not fixed_payload['purpose']:
|
207 |
+
fixed_payload['purpose'] = fixed_payload['content']
|
208 |
+
logger.warning(f"Point {point_id if point_id else ''}: 'purpose' was missing, set to content value")
|
209 |
+
|
210 |
+
if 'filesize' not in fixed_payload:
|
211 |
+
fixed_payload['filesize'] = self.required_fields_defaults['filesize']
|
212 |
+
logger.warning(f"Point {point_id if point_id else ''}: 'filesize' was missing, set to {self.required_fields_defaults['filesize']}")
|
213 |
+
|
214 |
+
if 'trigger' not in fixed_payload:
|
215 |
+
fixed_payload['trigger'] = self.required_fields_defaults['trigger']
|
216 |
+
logger.warning(f"Point {point_id if point_id else ''}: 'trigger' was missing, set to {self.required_fields_defaults['trigger']}")
|
217 |
+
|
218 |
+
return fixed_payload
|
src/fabrics_processor/database_updater.py
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Optional
|
2 |
+
from qdrant_client import QdrantClient
|
3 |
+
from qdrant_client.http.models import PointStruct, Filter, FieldCondition, MatchValue, PointIdsList
|
4 |
+
from fastembed import TextEmbedding
|
5 |
+
import logging
|
6 |
+
import uuid
|
7 |
+
from .output_files_generator import generate_yaml_file, generate_markdown_files
|
8 |
+
from .config import config
|
9 |
+
from .exceptions import ConfigurationError
|
10 |
+
from .database import validate_point_payload
|
11 |
+
|
12 |
+
logger = logging.getLogger('fabric_to_espanso')
|
13 |
+
|
14 |
+
def get_embedding(text: str, embedding_model: TextEmbedding) -> list:
|
15 |
+
"""
|
16 |
+
Generate embedding vector for the given text using FastEmbed.
|
17 |
+
|
18 |
+
Args:
|
19 |
+
text (str): Text to generate embedding for
|
20 |
+
|
21 |
+
Returns:
|
22 |
+
list: Embedding vector
|
23 |
+
"""
|
24 |
+
embeddings = list(embedding_model.embed([text]))
|
25 |
+
return embeddings[0].tolist()
|
26 |
+
|
27 |
+
def update_qdrant_database(client: QdrantClient, collection_name: str, new_files: list, modified_files: list, deleted_files: list):
|
28 |
+
"""
|
29 |
+
Update the Qdrant database based on detected file changes.
|
30 |
+
|
31 |
+
Args:
|
32 |
+
client (QdrantClient): An initialized Qdrant client.
|
33 |
+
new_files (list): List of new files to be added to the database.
|
34 |
+
modified_files (list): List of modified files to be updated in the database.
|
35 |
+
deleted_files (list): List of deleted files to be removed from the database.
|
36 |
+
"""
|
37 |
+
|
38 |
+
# Initialize the FastEmbed model (done once)
|
39 |
+
if config.embedding.use_fastembed:
|
40 |
+
# TODO: I think it is possible to choose another model here. Make that an option
|
41 |
+
logger.info(f"Initializing FastEmbed model.")
|
42 |
+
embedding_model = TextEmbedding()
|
43 |
+
else:
|
44 |
+
logger.info(f"Initializing embbeding model: {config.model_name}")
|
45 |
+
# TODO: testen. Weet niet of dit werkt.
|
46 |
+
embedding_model = TextEmbedding(model_name=config.model_name)
|
47 |
+
|
48 |
+
try:
|
49 |
+
# Add new files
|
50 |
+
for file in new_files:
|
51 |
+
try:
|
52 |
+
payload_new = validate_point_payload(file)
|
53 |
+
point = PointStruct(
|
54 |
+
id=str(uuid.uuid4()), # Generate a new UUID for each point
|
55 |
+
# TODO: 'fast-bge-small-en' is de naam van de vector. Je kunt de naam vinden door: client.get_vector_field_name()
|
56 |
+
vector={'fast-bge-small-en':
|
57 |
+
get_embedding(payload_new['purpose'], embedding_model)}, # Generate vector from purpose field
|
58 |
+
payload={
|
59 |
+
"filename": payload_new['filename'],
|
60 |
+
"content": payload_new['content'],
|
61 |
+
"purpose": payload_new['purpose'],
|
62 |
+
"date": payload_new['last_modified'],
|
63 |
+
"filesize": payload_new['filesize'],
|
64 |
+
"trigger": payload_new['trigger'],
|
65 |
+
}
|
66 |
+
)
|
67 |
+
client.upsert(collection_name=collection_name, points=[point]) # Update the database with the new file
|
68 |
+
logger.info(f"Added new file to database: {file['filename']}")
|
69 |
+
except ConfigurationError as e:
|
70 |
+
logger.error(f"Skipping new file: {str(e)}")
|
71 |
+
|
72 |
+
# Update modified files
|
73 |
+
for file in modified_files:
|
74 |
+
try:
|
75 |
+
# Query the database to find the point with the matching filename
|
76 |
+
scroll_result = client.scroll(
|
77 |
+
collection_name=collection_name,
|
78 |
+
scroll_filter=Filter(
|
79 |
+
must=[FieldCondition(key="filename", match=MatchValue(value=file['filename']))]
|
80 |
+
),
|
81 |
+
limit=1
|
82 |
+
)[0]
|
83 |
+
# TODO: Add handling of cases of multiple entries with the same filename
|
84 |
+
if scroll_result:
|
85 |
+
point_id = scroll_result[0].id
|
86 |
+
payload_current = validate_point_payload(file, point_id)
|
87 |
+
# Update the existing point with the new file data
|
88 |
+
point = PointStruct(
|
89 |
+
id=point_id,
|
90 |
+
# LET OP: als je 'fastembed' gebruikt, moet je de naam van de vector gebruiken.
|
91 |
+
# In dit geval is de naam 'fast-bge-small-en'.
|
92 |
+
# Gebruik je fastembed niet, maar rechtstreeks de QDRANT api, dan kun je ook gebruik maken
|
93 |
+
# van unnamed vectors en kun je dus schrrijven vector = get_embedding(file['purpose'], embedding_model)
|
94 |
+
# Zie https://github.com/qdrant/qdrant-client/discussions/598
|
95 |
+
# De naam die fastembed gebruikt is afhankelijk van het model dat je gebruikt.
|
96 |
+
# Je kunt de naam vinden door: client.get_vector_field_name()
|
97 |
+
vector={'fast-bge-small-en':
|
98 |
+
get_embedding(file['purpose'], embedding_model)}, # Generate vector from purpose field
|
99 |
+
payload={
|
100 |
+
"filename": payload_current['filename'],
|
101 |
+
"content": file['content'],
|
102 |
+
"purpose": file['purpose'],
|
103 |
+
"date": file['last_modified'],
|
104 |
+
"filesize": file['filesize'],
|
105 |
+
"trigger": payload_current['trigger'],
|
106 |
+
}
|
107 |
+
)
|
108 |
+
client.upsert(collection_name=collection_name, points=[point])
|
109 |
+
logger.info(f"Updated modified file in database: {payload_current['filename']}")
|
110 |
+
else:
|
111 |
+
logger.warning(f"File not found in database for update: {file['filename']}")
|
112 |
+
except ConfigurationError as e:
|
113 |
+
logger.error(f"Skipping modified file: {str(e)}")
|
114 |
+
|
115 |
+
# Delete removed files
|
116 |
+
for filename in deleted_files:
|
117 |
+
# Query the database to find the point with the matching filename
|
118 |
+
scroll_result = client.scroll(
|
119 |
+
collection_name=collection_name,
|
120 |
+
scroll_filter=Filter(
|
121 |
+
must=[FieldCondition(key="filename", match=MatchValue(value=filename))]
|
122 |
+
),
|
123 |
+
limit=1
|
124 |
+
)[0]
|
125 |
+
# TODO: Add handling of cases of multiple entries with the same filename
|
126 |
+
if scroll_result:
|
127 |
+
point_id = scroll_result[0].id
|
128 |
+
client.delete(
|
129 |
+
collection_name=collection_name,
|
130 |
+
points_selector=PointIdsList(points=[point_id])
|
131 |
+
)
|
132 |
+
logger.info(f"Deleted file from database: {filename}")
|
133 |
+
else:
|
134 |
+
logger.warning(f"File not found in database for deletion: {filename}")
|
135 |
+
|
136 |
+
logger.info("Database update completed successfully")
|
137 |
+
|
138 |
+
# Generate new YAML file for use with espanso after database update
|
139 |
+
print("Generating YAML file...")
|
140 |
+
generate_yaml_file(client, config.embedding.collection_name, config.yaml_output_folder)
|
141 |
+
# Generate markdown files for use with obsidian after database update
|
142 |
+
print("Generating markdown files...")
|
143 |
+
generate_markdown_files(client, config.embedding.collection_name, config.obsidian_output_folder)
|
144 |
+
|
145 |
+
except Exception as e:
|
146 |
+
logger.error(f"Error updating Qdrant database: {str(e)}", exc_info=True)
|
147 |
+
raise
|
src/fabrics_processor/exceptions.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Custom exceptions for the fabric-to-espanso application."""
|
2 |
+
|
3 |
+
class FabricToEspansoError(Exception):
|
4 |
+
"""Base exception for all fabric-to-espanso errors."""
|
5 |
+
pass
|
6 |
+
|
7 |
+
class DatabaseError(FabricToEspansoError):
|
8 |
+
"""Base exception for database-related errors."""
|
9 |
+
pass
|
10 |
+
|
11 |
+
class DatabaseConnectionError(DatabaseError):
|
12 |
+
"""Raised when unable to connect to the database."""
|
13 |
+
pass
|
14 |
+
|
15 |
+
class DatabaseInitializationError(DatabaseError):
|
16 |
+
"""Raised when database initialization fails."""
|
17 |
+
pass
|
18 |
+
|
19 |
+
class CollectionError(DatabaseError):
|
20 |
+
"""Raised when there's an error with collection operations."""
|
21 |
+
pass
|
22 |
+
|
23 |
+
class ConfigurationError(FabricToEspansoError):
|
24 |
+
"""Raised when there's an error in the configuration."""
|
25 |
+
pass
|
26 |
+
|
27 |
+
class NotImplementedError(FabricToEspansoError):
|
28 |
+
"""Raised when a feature is not implemented."""
|
29 |
+
pass
|
30 |
+
|
31 |
+
class ParsingError(FabricToEspansoError):
|
32 |
+
"""Raised when there's an error parsing markdown files."""
|
33 |
+
pass
|
34 |
+
|
35 |
+
class ProcessingError(FabricToEspansoError):
|
36 |
+
"""Raised when there's an error processing the input files."""
|
37 |
+
pass
|
src/fabrics_processor/file_change_detector.py
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""File change detection for fabric-to-espanso."""
|
2 |
+
from typing import List, Tuple, Dict, Any
|
3 |
+
from datetime import datetime
|
4 |
+
import logging
|
5 |
+
|
6 |
+
from qdrant_client import QdrantClient
|
7 |
+
from qdrant_client.http.models import Filter, FieldCondition, MatchValue
|
8 |
+
from qdrant_client.http.exceptions import UnexpectedResponse
|
9 |
+
|
10 |
+
from .file_processor import process_markdown_files
|
11 |
+
from .config import config
|
12 |
+
from .exceptions import DatabaseError
|
13 |
+
|
14 |
+
logger = logging.getLogger('fabric_to_espanso')
|
15 |
+
|
16 |
+
def get_stored_files(client: QdrantClient, collection_name: str = config.embedding.collection_name) -> Dict[str, Dict[str, Any]]:
|
17 |
+
"""Get all files stored in the database.
|
18 |
+
|
19 |
+
Args:
|
20 |
+
client: Initialized Qdrant client
|
21 |
+
collection_name: Name of the collection to query
|
22 |
+
|
23 |
+
Returns:
|
24 |
+
Dict mapping filenames to their database records
|
25 |
+
|
26 |
+
Raises:
|
27 |
+
DatabaseError: If query fails
|
28 |
+
"""
|
29 |
+
try:
|
30 |
+
stored_files = client.scroll(
|
31 |
+
collection_name=collection_name,
|
32 |
+
limit=10000 # Adjust based on expected file count
|
33 |
+
)[0]
|
34 |
+
return {
|
35 |
+
file.payload['filename']: {
|
36 |
+
'payload': file.payload,
|
37 |
+
'id': file.id,
|
38 |
+
'vector': file.vector
|
39 |
+
}
|
40 |
+
for file in stored_files
|
41 |
+
}
|
42 |
+
except UnexpectedResponse as e:
|
43 |
+
raise DatabaseError(f"Failed to query stored files: {str(e)}") from e
|
44 |
+
|
45 |
+
def compare_file_dates(
|
46 |
+
current_date: datetime,
|
47 |
+
stored_date_str: str
|
48 |
+
) -> bool:
|
49 |
+
"""Compare file modification dates.
|
50 |
+
note: This function isn't used anymore. Replaced by compare_file_sizes.
|
51 |
+
|
52 |
+
Args:
|
53 |
+
current_date: Current file's modification date
|
54 |
+
stored_date_str: Stored file's modification date string
|
55 |
+
|
56 |
+
Returns:
|
57 |
+
True if file is modified, False otherwise
|
58 |
+
"""
|
59 |
+
stored_date = datetime.strptime(stored_date_str, '%Y-%m-%dT%H:%M:%S.%f')
|
60 |
+
return current_date > stored_date
|
61 |
+
|
62 |
+
def detect_file_changes(
|
63 |
+
client: QdrantClient,
|
64 |
+
fabric_patterns_folder: str
|
65 |
+
) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]], List[str]]:
|
66 |
+
"""Detect changes in markdown files by comparing with database.
|
67 |
+
|
68 |
+
Args:
|
69 |
+
client: Initialized Qdrant client
|
70 |
+
markdown_folder: Folder containing markdown files
|
71 |
+
|
72 |
+
Returns:
|
73 |
+
Tuple containing:
|
74 |
+
- List of new files
|
75 |
+
- List of modified files
|
76 |
+
- List of deleted files
|
77 |
+
|
78 |
+
Raises:
|
79 |
+
DatabaseError: If database query fails
|
80 |
+
OSError: If file system operations fail
|
81 |
+
"""
|
82 |
+
try:
|
83 |
+
# Get current files
|
84 |
+
current_files = process_markdown_files(fabric_patterns_folder)
|
85 |
+
logger.debug(f"Found {len(current_files)} files in {fabric_patterns_folder}")
|
86 |
+
|
87 |
+
# Get stored files from database
|
88 |
+
stored_files = get_stored_files(client)
|
89 |
+
logger.debug(f"Found {len(stored_files)} files in database")
|
90 |
+
|
91 |
+
# Initialize change lists
|
92 |
+
new_files: List[Dict[str, Any]] = []
|
93 |
+
modified_files: List[Dict[str, Any]] = []
|
94 |
+
deleted_files: List[str] = []
|
95 |
+
|
96 |
+
# Check for new and modified files
|
97 |
+
for file in current_files:
|
98 |
+
filename = file['filename']
|
99 |
+
if filename not in stored_files:
|
100 |
+
logger.debug(f"New file detected: {filename}")
|
101 |
+
new_files.append(file)
|
102 |
+
# compare on file size, not on modified date, because fabric -U will change the modified date of the file
|
103 |
+
# even if the content hasn't changed
|
104 |
+
elif file['filesize'] != stored_files[filename]['payload']['filesize']:
|
105 |
+
logger.debug(f"Modified file detected: {filename}")
|
106 |
+
modified_files.append(file)
|
107 |
+
|
108 |
+
# Check for deleted files
|
109 |
+
current_filenames = {file['filename'] for file in current_files}
|
110 |
+
deleted_files = [
|
111 |
+
filename for filename in stored_files
|
112 |
+
if filename not in current_filenames
|
113 |
+
]
|
114 |
+
|
115 |
+
if deleted_files:
|
116 |
+
logger.debug(f"Deleted files detected: {deleted_files}")
|
117 |
+
|
118 |
+
# Log summary
|
119 |
+
logger.info(
|
120 |
+
f"Changes detected:"
|
121 |
+
f" {len(new_files)} new,"
|
122 |
+
f" {len(modified_files)} modified,"
|
123 |
+
f" {len(deleted_files)} deleted"
|
124 |
+
)
|
125 |
+
|
126 |
+
return new_files, modified_files, deleted_files
|
127 |
+
|
128 |
+
except Exception as e:
|
129 |
+
logger.error(f"Error detecting file changes: {str(e)}", exc_info=True)
|
130 |
+
if isinstance(e, (DatabaseError, OSError)):
|
131 |
+
raise
|
132 |
+
raise RuntimeError(f"Unexpected error detecting changes: {str(e)}") from e
|
src/fabrics_processor/file_processor.py
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""File processing module for fabric-to-espanso."""
|
2 |
+
from pathlib import Path
|
3 |
+
from typing import List, Dict, Any, Optional
|
4 |
+
from datetime import datetime
|
5 |
+
import logging
|
6 |
+
|
7 |
+
from .markdown_parser import parse_markdown_file
|
8 |
+
from .exceptions import ProcessingError
|
9 |
+
|
10 |
+
logger = logging.getLogger('fabric_to_espanso')
|
11 |
+
|
12 |
+
def find_markdown_files(
|
13 |
+
root_dir: Path,
|
14 |
+
max_depth: int = 2,
|
15 |
+
pattern: str = "*.md"
|
16 |
+
) -> List[Path]:
|
17 |
+
"""Find markdown files in directory up to specified depth.
|
18 |
+
|
19 |
+
Args:
|
20 |
+
root_dir: Root directory to search in
|
21 |
+
max_depth: Maximum directory depth to search
|
22 |
+
pattern: Glob pattern for files to find
|
23 |
+
|
24 |
+
Returns:
|
25 |
+
List of paths to markdown files
|
26 |
+
|
27 |
+
Raises:
|
28 |
+
ValueError: If root_dir doesn't exist or isn't a directory
|
29 |
+
"""
|
30 |
+
if not root_dir.exists():
|
31 |
+
raise ValueError(f"Directory does not exist: {root_dir}")
|
32 |
+
if not root_dir.is_dir():
|
33 |
+
raise ValueError(f"Path is not a directory: {root_dir}")
|
34 |
+
|
35 |
+
files: List[Path] = []
|
36 |
+
|
37 |
+
try:
|
38 |
+
# Convert depth to parts for comparison
|
39 |
+
root_parts = len(root_dir.parts)
|
40 |
+
|
41 |
+
# Use rglob to find all markdown files
|
42 |
+
for file_path in root_dir.rglob(pattern):
|
43 |
+
# Skip if too deep
|
44 |
+
if len(file_path.parts) - root_parts > max_depth:
|
45 |
+
continue
|
46 |
+
# Skip README.md files
|
47 |
+
if file_path.name.lower() == "readme.md":
|
48 |
+
continue
|
49 |
+
if file_path.name.lower() == "user.md":
|
50 |
+
continue
|
51 |
+
if file_path.is_file():
|
52 |
+
files.append(file_path)
|
53 |
+
|
54 |
+
logger.debug(f"Found {len(files)} markdown files in {root_dir}")
|
55 |
+
return files
|
56 |
+
|
57 |
+
except Exception as e:
|
58 |
+
logger.error(f"Error finding markdown files: {str(e)}", exc_info=True)
|
59 |
+
raise ProcessingError(f"Failed to find markdown files: {str(e)}") from e
|
60 |
+
|
61 |
+
def process_markdown_file(
|
62 |
+
file_path: Path,
|
63 |
+
trigger_prefix: str
|
64 |
+
) -> Optional[Dict[str, Any]]:
|
65 |
+
"""Process a single markdown file.
|
66 |
+
|
67 |
+
Args:
|
68 |
+
file_path: Path to markdown file
|
69 |
+
trigger_prefix: Prefix for espanso triggers
|
70 |
+
|
71 |
+
Returns:
|
72 |
+
Dictionary with file information or None if processing fails
|
73 |
+
|
74 |
+
Raises:
|
75 |
+
ProcessingError: If file processing fails
|
76 |
+
"""
|
77 |
+
try:
|
78 |
+
content, extracted_sections = parse_markdown_file(str(file_path))
|
79 |
+
if extracted_sections is None:
|
80 |
+
logger.warning(f"No sections extracted from {file_path}")
|
81 |
+
extracted_sections = content
|
82 |
+
|
83 |
+
return {
|
84 |
+
'filename': file_path.parent.name,
|
85 |
+
'content': content,
|
86 |
+
'purpose': extracted_sections,
|
87 |
+
'last_modified': datetime.fromtimestamp(file_path.stat().st_mtime),
|
88 |
+
'filesize': file_path.stat().st_size,
|
89 |
+
'trigger': trigger_prefix,
|
90 |
+
'label': file_path.stem # filename without extension
|
91 |
+
}
|
92 |
+
|
93 |
+
except Exception as e:
|
94 |
+
logger.error(f"Error processing {file_path}: {str(e)}", exc_info=True)
|
95 |
+
raise ProcessingError(f"Failed to process {file_path}: {str(e)}") from e
|
96 |
+
|
97 |
+
def process_markdown_files(
|
98 |
+
markdown_folder: Path | str,
|
99 |
+
# TODO: make 'max_depth' a parameter
|
100 |
+
max_depth: int = 2,
|
101 |
+
trigger_prefix: str = ";;fab"
|
102 |
+
) -> List[Dict[str, Any]]:
|
103 |
+
"""Process all markdown files in directory.
|
104 |
+
|
105 |
+
Args:
|
106 |
+
markdown_folder: Directory containing markdown files
|
107 |
+
max_depth: Maximum directory depth to search
|
108 |
+
trigger_prefix: Prefix for espanso triggers
|
109 |
+
|
110 |
+
Returns:
|
111 |
+
List of processed file information
|
112 |
+
|
113 |
+
Raises:
|
114 |
+
ProcessingError: If processing fails
|
115 |
+
ValueError: If markdown_folder is invalid
|
116 |
+
"""
|
117 |
+
root_dir = Path(markdown_folder)
|
118 |
+
processed_files: List[Dict[str, Any]] = []
|
119 |
+
|
120 |
+
try:
|
121 |
+
# Find all markdown files
|
122 |
+
markdown_files = find_markdown_files(root_dir, max_depth)
|
123 |
+
|
124 |
+
# Process each file
|
125 |
+
for file_path in markdown_files:
|
126 |
+
try:
|
127 |
+
if result := process_markdown_file(file_path, trigger_prefix):
|
128 |
+
processed_files.append(result)
|
129 |
+
logger.info(f"Processed: {file_path.parent.name}")
|
130 |
+
except ProcessingError as e:
|
131 |
+
logger.error(str(e))
|
132 |
+
continue
|
133 |
+
|
134 |
+
logger.info(f"Successfully processed {len(processed_files)} files in fabric patterns folder")
|
135 |
+
return processed_files
|
136 |
+
|
137 |
+
except Exception as e:
|
138 |
+
logger.error(f"Error processing markdown files: {str(e)}", exc_info=True)
|
139 |
+
if isinstance(e, (ProcessingError, ValueError)):
|
140 |
+
raise
|
141 |
+
raise ProcessingError(f"Unexpected error processing files: {str(e)}") from e
|
src/fabrics_processor/logger.py
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
import os
|
3 |
+
from pathlib import Path
|
4 |
+
from logging.handlers import RotatingFileHandler
|
5 |
+
|
6 |
+
# Module level logger instance
|
7 |
+
_logger = None
|
8 |
+
|
9 |
+
def setup_logger(log_file='fabric_to_espanso.log'):
|
10 |
+
"""
|
11 |
+
Set up and configure the logger for the application.
|
12 |
+
|
13 |
+
Args:
|
14 |
+
log_file (str): Name of the log file. Defaults to 'fabric_to_espanso.log'.
|
15 |
+
|
16 |
+
Returns:
|
17 |
+
logging.Logger: Configured logger object.
|
18 |
+
"""
|
19 |
+
global _logger
|
20 |
+
if _logger is not None:
|
21 |
+
return _logger
|
22 |
+
|
23 |
+
logger = logging.getLogger('fabric_to_espanso')
|
24 |
+
|
25 |
+
# Clean up any existing handlers
|
26 |
+
logger.handlers.clear()
|
27 |
+
|
28 |
+
# Set log level and prevent propagation
|
29 |
+
logger.setLevel(logging.INFO)
|
30 |
+
logger.propagate = False
|
31 |
+
|
32 |
+
# Get the project root directory (2 levels up from logger.py)
|
33 |
+
project_root = Path(__file__).parent.parent.parent
|
34 |
+
|
35 |
+
# Create logs directory if it doesn't exist - use absolute path
|
36 |
+
log_dir = project_root / "logs"
|
37 |
+
log_dir.mkdir(exist_ok=True)
|
38 |
+
|
39 |
+
# Create file handlers with absolute path
|
40 |
+
log_file_path = log_dir / f"{log_file}"
|
41 |
+
file_handler = RotatingFileHandler(log_file_path, maxBytes=1024*1024, backupCount=5)
|
42 |
+
console_handler = logging.StreamHandler()
|
43 |
+
|
44 |
+
# Set log levels
|
45 |
+
file_handler.setLevel(logging.INFO)
|
46 |
+
console_handler.setLevel(logging.INFO)
|
47 |
+
|
48 |
+
# Create formatters and add it to handlers
|
49 |
+
file_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
50 |
+
console_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
|
51 |
+
|
52 |
+
file_handler.setFormatter(file_format)
|
53 |
+
console_handler.setFormatter(console_format)
|
54 |
+
|
55 |
+
# Add handlers to the logger
|
56 |
+
logger.addHandler(file_handler)
|
57 |
+
logger.addHandler(console_handler)
|
58 |
+
|
59 |
+
_logger = logger
|
60 |
+
return logger
|
src/fabrics_processor/markdown_parser.py
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Markdown parsing module for fabric-to-espanso."""
|
2 |
+
from typing import Tuple, List, Optional, Set
|
3 |
+
from pathlib import Path
|
4 |
+
import regex
|
5 |
+
import logging
|
6 |
+
|
7 |
+
from .exceptions import ParsingError
|
8 |
+
from .config import config
|
9 |
+
|
10 |
+
logger = logging.getLogger('fabric_to_espanso')
|
11 |
+
|
12 |
+
def create_section_pattern(keywords: Set[str]) -> regex.Pattern:
|
13 |
+
keyword_pattern = '|'.join(regex.escape(kw) for kw in keywords)
|
14 |
+
return regex.compile(
|
15 |
+
rf'^#\s+.*(?:{keyword_pattern}).*$\n?(?:(?!^#).*\n?)*',
|
16 |
+
regex.MULTILINE | regex.IGNORECASE
|
17 |
+
)
|
18 |
+
|
19 |
+
def parse_markdown_file(
|
20 |
+
file_path: str | Path,
|
21 |
+
keywords: Optional[Set[str]] = None
|
22 |
+
) -> Tuple[str, Optional[str]]:
|
23 |
+
"""Extract sections with specified keywords from markdown file.
|
24 |
+
|
25 |
+
Args:
|
26 |
+
file_path: Path to markdown file
|
27 |
+
keywords: Set of keywords to match in headings. If None, uses defaults from config
|
28 |
+
|
29 |
+
Returns:
|
30 |
+
Tuple of (full_content, extracted_sections)
|
31 |
+
If no sections match, returns (full_content, None)
|
32 |
+
|
33 |
+
Raises:
|
34 |
+
ParsingError: If file reading or parsing fails
|
35 |
+
"""
|
36 |
+
try:
|
37 |
+
# Use provided keywords or defaults from config
|
38 |
+
keywords = keywords or set(config.base_words)
|
39 |
+
|
40 |
+
# Create regex pattern for keywords in headings and text
|
41 |
+
section_pattern = create_section_pattern(keywords)
|
42 |
+
|
43 |
+
# Read file content
|
44 |
+
path = Path(file_path)
|
45 |
+
try:
|
46 |
+
content = path.read_text(encoding='utf-8')
|
47 |
+
except Exception as e:
|
48 |
+
raise ParsingError(f"Failed to read {path}: {str(e)}") from e
|
49 |
+
|
50 |
+
# Find all matching headings
|
51 |
+
section_matches = list(section_pattern.findall(content))
|
52 |
+
|
53 |
+
# If no matches found, return full content
|
54 |
+
if not section_matches:
|
55 |
+
logger.debug(f"No matching sections found in {path.name}")
|
56 |
+
return content, None
|
57 |
+
|
58 |
+
# Join sections with double newline
|
59 |
+
extracted = '\n\n'.join(section_matches)
|
60 |
+
logger.debug(f"Extracted {len(section_matches)} sections from {path.name}")
|
61 |
+
|
62 |
+
return content, extracted
|
63 |
+
|
64 |
+
except Exception as e:
|
65 |
+
logger.error(f"Error parsing {file_path}: {str(e)}", exc_info=True)
|
66 |
+
if isinstance(e, ParsingError):
|
67 |
+
raise
|
68 |
+
raise ParsingError(f"Unexpected error parsing {file_path}: {str(e)}") from e
|
69 |
+
|
70 |
+
def main():
|
71 |
+
# Example usage
|
72 |
+
try:
|
73 |
+
# Custom keywords can be passed as second argument
|
74 |
+
result = parse_markdown_file('document.md')
|
75 |
+
# result = extract_sections('document.md', {'Identity', 'Purpose', 'Scope'})
|
76 |
+
|
77 |
+
print(result)
|
78 |
+
|
79 |
+
except Exception as e:
|
80 |
+
print(f"An error occurred: {e}")
|
81 |
+
|
82 |
+
if __name__ == '__main__':
|
83 |
+
main()
|
src/fabrics_processor/obsidian2fabric.py
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
from shutil import copy2, rmtree
|
3 |
+
from fastcore.utils import L
|
4 |
+
import re
|
5 |
+
|
6 |
+
from src.fabrics_processor.config import config
|
7 |
+
|
8 |
+
def sentence2snake(name: str) -> str:
|
9 |
+
"""Convert any string to snake_case, replacing non-alphanumeric with underscore"""
|
10 |
+
s1 = name.lower()
|
11 |
+
s2 = re.sub(r'\W', r'_', s1)
|
12 |
+
return re.sub(r'_+', r'_', s2)
|
13 |
+
|
14 |
+
def round_timestamp(ts: float) -> int:
|
15 |
+
"""Round timestamp to handle filesystem differences"""
|
16 |
+
return int(str(ts).split('.')[0][:-4])
|
17 |
+
|
18 |
+
def get_md_files_obsidian(path: Path) -> dict:
|
19 |
+
"""Get files from obsidian vault: stem -> (path, timestamp, size)"""
|
20 |
+
# Rename files to snake_case and add identifier to distinguish own prompts from others
|
21 |
+
return {sentence2snake(p.stem)+"-"+p.parent.name.lower(): (p, p.stat().st_mtime, p.stat().st_size)
|
22 |
+
for p in Path(path).glob('**/*.md')}
|
23 |
+
|
24 |
+
def get_md_files_fabricsfolder(path: Path) -> dict:
|
25 |
+
"""Get files from target structure: dir_name -> (system.md_path, timestamp, size)"""
|
26 |
+
target_subdirs = [x for x in path.iterdir() if x.is_dir()]
|
27 |
+
return {x.stem: (x/'system.md', (x/'system.md').stat().st_mtime, (x/'system.md').stat().st_size)
|
28 |
+
for x in target_subdirs
|
29 |
+
if (x/'system.md').exists()}
|
30 |
+
|
31 |
+
def get_modified_files(source_files: dict, target_files: dict) -> list:
|
32 |
+
"""Compare timestamps between source and target files, returns dictionary of
|
33 |
+
entries needing updates. The dictionary has the filename as key and the following
|
34 |
+
values:
|
35 |
+
path, timestamp, size"""
|
36 |
+
existing_files = L(k for k in source_files.keys() if k in target_files)
|
37 |
+
# removed checking for timestamp. Because you don't want false positives because of file system differences
|
38 |
+
# or daylight savings. But you also want to be able to update files that have almost the same timestamp
|
39 |
+
# when you change the file.
|
40 |
+
# different_timestamps = L(k for k in existing_files
|
41 |
+
# if round_timestamp(source_files[k][1]) > round_timestamp(target_files[k][1]))
|
42 |
+
# return L(source_files[k][0] for k in different_timestamps
|
43 |
+
# if source_files[k][2] != target_files[k][2])
|
44 |
+
return L({k: source_files[k]} for k in existing_files if source_files[k][2] != target_files[k][2])
|
45 |
+
|
46 |
+
def get_new_files(source_files: dict, target_files: dict) -> list:
|
47 |
+
"""Return list of dictionaries containing with the key as filename and these values:
|
48 |
+
path, timestamp, size"""
|
49 |
+
return L({k: source_files[k]} for k in source_files.keys() if k not in target_files)
|
50 |
+
|
51 |
+
def process_file(source: dict, target_dir: Path) -> None:
|
52 |
+
"""
|
53 |
+
Process a single file: create directory, copy as system.md, create user.md
|
54 |
+
|
55 |
+
Args:
|
56 |
+
source: Dict of source file: filename:(path, timestamp, size)
|
57 |
+
target_dir: Base target directory (e.g. 'md_target')
|
58 |
+
"""
|
59 |
+
filename = next(iter(source))
|
60 |
+
filepath = next(iter(source.values()))[0]
|
61 |
+
subdir = target_dir/filename
|
62 |
+
subdir.mkdir(mode=0o755, exist_ok=True)
|
63 |
+
copy2(filepath, subdir/'system.md')
|
64 |
+
(subdir/'user.md').touch()
|
65 |
+
|
66 |
+
def sync_folders(source_dir: Path, target_dir: Path) -> None:
|
67 |
+
"""
|
68 |
+
Main function to synchronize folders
|
69 |
+
|
70 |
+
Args:
|
71 |
+
source_dir: Path to source directory (obsidian vault)
|
72 |
+
target_dir: Path to target directory (fabrics folder)
|
73 |
+
"""
|
74 |
+
source_files = get_md_files_obsidian(Path(source_dir))
|
75 |
+
target_files = get_md_files_fabricsfolder(Path(target_dir))
|
76 |
+
|
77 |
+
# Get all files that need processing
|
78 |
+
files_to_process = L(get_new_files(source_files, target_files) +
|
79 |
+
get_modified_files(source_files, target_files))
|
80 |
+
|
81 |
+
# Process each file
|
82 |
+
for i in files_to_process:
|
83 |
+
process_file(i, target_dir)
|
84 |
+
|
85 |
+
# Get all files that need deleting
|
86 |
+
files_to_delete = L(k for k in target_files.keys() if k not in source_files and "-" in k)
|
87 |
+
|
88 |
+
# Delete each directory and its contents
|
89 |
+
for file_name in files_to_delete:
|
90 |
+
rmtree(target_dir/file_name)
|
src/fabrics_processor/output_files_generator.py
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""YAML file generation for fabric-to-espanso and
|
2 |
+
markdown file generation for Obsidian TextGenerator plugin."""
|
3 |
+
from pathlib import Path
|
4 |
+
from shutil import rmtree
|
5 |
+
from typing import Dict, Any, List
|
6 |
+
import yaml
|
7 |
+
import logging
|
8 |
+
|
9 |
+
from qdrant_client import QdrantClient
|
10 |
+
from qdrant_client.http.exceptions import UnexpectedResponse
|
11 |
+
from src.fabrics_processor.config import config
|
12 |
+
|
13 |
+
from .exceptions import DatabaseError
|
14 |
+
|
15 |
+
logger = logging.getLogger('fabric_to_espanso')
|
16 |
+
|
17 |
+
class BlockString(str):
|
18 |
+
"""String subclass for YAML block-style string representation."""
|
19 |
+
pass
|
20 |
+
|
21 |
+
def repr_block_string(dumper: yaml.Dumper, data: BlockString) -> yaml.ScalarNode:
|
22 |
+
"""Custom YAML representer for block strings."""
|
23 |
+
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
|
24 |
+
|
25 |
+
yaml.add_representer(BlockString, repr_block_string)
|
26 |
+
|
27 |
+
def generate_yaml_file(client: QdrantClient, collection_name: str, yaml_output_folder: str) -> None:
|
28 |
+
"""Generate a complete YAML file from the Qdrant database.
|
29 |
+
|
30 |
+
Args:
|
31 |
+
client: Initialized Qdrant client
|
32 |
+
yaml_output_folder: Directory where the YAML file will be created
|
33 |
+
|
34 |
+
Raises:
|
35 |
+
DatabaseError: If database query fails
|
36 |
+
OSError: If file operations fail
|
37 |
+
ValueError: If output folder is invalid
|
38 |
+
"""
|
39 |
+
try:
|
40 |
+
# Validate output folder
|
41 |
+
output_path = Path(yaml_output_folder)
|
42 |
+
if not output_path.exists():
|
43 |
+
logger.info(f"YAML output path doesn't exist. Check the Espanso matches directory with `espanso path` in PowerShell: {output_path}")
|
44 |
+
raise ValueError(f"YAML output path doesn't exist. Check the Espanso matches directory with `espanso path` in PowerShell: {output_path}")
|
45 |
+
|
46 |
+
# Query all entries from the database
|
47 |
+
try:
|
48 |
+
results = client.scroll(
|
49 |
+
collection_name=collection_name,
|
50 |
+
limit=10000 # Adjust based on expected maximum files
|
51 |
+
)[0]
|
52 |
+
except UnexpectedResponse as e:
|
53 |
+
raise DatabaseError(f"Failed to query database: {str(e)}") from e
|
54 |
+
|
55 |
+
# Prepare YAML data
|
56 |
+
data: Dict[str, List[Dict[str, Any]]] = {'matches': []}
|
57 |
+
|
58 |
+
for result in results:
|
59 |
+
entry = {
|
60 |
+
'trigger': result.payload['trigger'],
|
61 |
+
'replace': BlockString(result.payload['content'] + '\n{{clipb}}'),
|
62 |
+
'label': result.payload['filename'],
|
63 |
+
'vars': [
|
64 |
+
{'name': 'clipb', 'type': 'clipboard'}
|
65 |
+
]
|
66 |
+
}
|
67 |
+
data['matches'].append(entry)
|
68 |
+
|
69 |
+
# Write the YAML file
|
70 |
+
yaml_output_path = output_path / "fabric_patterns.yml"
|
71 |
+
with open(yaml_output_path, 'w') as yaml_file:
|
72 |
+
yaml.dump(data, yaml_file, sort_keys=False, default_flow_style=False)
|
73 |
+
|
74 |
+
logger.info(f"YAML file generated successfully at {yaml_output_path}")
|
75 |
+
except Exception as e:
|
76 |
+
logger.error(f"Error generating YAML file: {str(e)}", exc_info=True)
|
77 |
+
if isinstance(e, (DatabaseError, OSError, ValueError)):
|
78 |
+
raise
|
79 |
+
raise RuntimeError(f"Unexpected error generating YAML: {str(e)}") from e
|
80 |
+
|
81 |
+
def generate_markdown_files(client: QdrantClient, collection_name: str, markdown_output_folder: str) -> None:
|
82 |
+
"""Generate markdown files from the Qdrant database.
|
83 |
+
|
84 |
+
Args:
|
85 |
+
client: Initialized Qdrant client
|
86 |
+
collection_name: Name of the collection to query
|
87 |
+
markdown_output_folder: Directory where the markdown files will be created
|
88 |
+
|
89 |
+
Raises:
|
90 |
+
DatabaseError: If database query fails
|
91 |
+
OSError: If file operations fail
|
92 |
+
ValueError: If output folder is invalid
|
93 |
+
"""
|
94 |
+
try:
|
95 |
+
# Validate output folder
|
96 |
+
output_path = Path(markdown_output_folder)
|
97 |
+
if not output_path.exists():
|
98 |
+
logger.info(f"Markdown output path doesn't exist. Check if this folder in parameters.py matches the Textgenerator folder in you Obsidian vault. {output_path}")
|
99 |
+
raise ValueError(f"Markdown output path doesn't exist. Check if this folder in parameters.py matches the Textgenerator folder in you Obsidian vault. {output_path}")
|
100 |
+
|
101 |
+
# Query all entries from the database
|
102 |
+
try:
|
103 |
+
# Simply first remove all existing markdown files in Obisdian Textgenerator folder
|
104 |
+
rmtree(output_path)
|
105 |
+
output_path.mkdir(mode=0o755)
|
106 |
+
|
107 |
+
results = client.scroll(
|
108 |
+
collection_name=collection_name,
|
109 |
+
limit=10000 # Adjust based on expected maximum files
|
110 |
+
)[0]
|
111 |
+
|
112 |
+
# Generate markdown files for each entry
|
113 |
+
for result in results:
|
114 |
+
metadata = result.payload
|
115 |
+
filename = metadata['filename']
|
116 |
+
purpose = metadata['purpose']
|
117 |
+
content = metadata['content']
|
118 |
+
markdown_path = output_path / f"{filename}.md"
|
119 |
+
with open(markdown_path, 'w', encoding='utf-8') as markdown_file:
|
120 |
+
markdown_file.write(apply_markdown_template(filename, purpose, content))
|
121 |
+
|
122 |
+
logger.info(f"Generated {len(results)} Markdown files generated successfully at {markdown_output_folder}")
|
123 |
+
|
124 |
+
except UnexpectedResponse as e:
|
125 |
+
raise DatabaseError(f"Failed to query database: {str(e)}") from e
|
126 |
+
|
127 |
+
except Exception as e:
|
128 |
+
logger.error(f"Error generating Markdown files: {str(e)}")
|
129 |
+
|
130 |
+
|
131 |
+
def apply_markdown_template(filename: str, purpose: str, content: str) -> str:
|
132 |
+
"""Apply the markdown template to the given content.
|
133 |
+
To generate markdown files that can be used in Obsidian by
|
134 |
+
the TextGenerator plugin."""
|
135 |
+
|
136 |
+
# Ensure proper indentation
|
137 |
+
purpose_indented = purpose.replace('\n', '\n ')
|
138 |
+
content_indented = content.replace('\n', '\n ')
|
139 |
+
|
140 |
+
return f"""---
|
141 |
+
PromptInfo:
|
142 |
+
promptId: {filename}
|
143 |
+
name: {filename}
|
144 |
+
description: |
|
145 |
+
{purpose_indented}
|
146 |
+
required_values:
|
147 |
+
author: fabric
|
148 |
+
tags:
|
149 |
+
version: 1
|
150 |
+
config:
|
151 |
+
mode: insert
|
152 |
+
system: |
|
153 |
+
{content_indented}
|
154 |
+
---
|
155 |
+
|
156 |
+
{{{{selection}}}}
|
157 |
+
"""
|
src/fabrics_processor/output_files_generator_temp.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
from pathlib import Path
|
3 |
+
from qdrant_client import QdrantClient
|
4 |
+
|
5 |
+
logger = logging.getLogger('fabric_to_espanso')
|
6 |
+
|
7 |
+
def generate_yaml(markdown_content, filename, trigger="/:", label=None):
|
8 |
+
"""
|
9 |
+
Generate YAML content from parsed markdown.
|
10 |
+
|
11 |
+
Args:
|
12 |
+
markdown_content (str): The content of the markdown file.
|
13 |
+
filename (str): The name of the markdown file (without extension).
|
14 |
+
trigger (str, optional): The trigger for the YAML entry. Defaults to "/:".
|
15 |
+
label (str, optional): The label for the YAML entry. If None, uses the filename.
|
16 |
+
|
17 |
+
Returns:
|
18 |
+
str: The generated YAML content.
|
19 |
+
"""
|
20 |
+
try:
|
21 |
+
# Clean and format the markdown content
|
22 |
+
content = markdown_content.strip()
|
23 |
+
# Remove extra newlines and normalize spacing
|
24 |
+
content = '\n'.join(line.strip() for line in content.split('\n') if line.strip())
|
25 |
+
# Add INPUT section at the end
|
26 |
+
content = f"{content}\n\n# INPUT\n{{clipb}}"
|
27 |
+
|
28 |
+
return content
|
29 |
+
except Exception as e:
|
30 |
+
logger.error(f"Error generating YAML for {filename}: {str(e)}", exc_info=True)
|
31 |
+
return None
|
32 |
+
|
33 |
+
def generate_markdown(filename: str, content: str, purpose: str) -> str:
|
34 |
+
"""
|
35 |
+
Generate markdown content for a database entry.
|
36 |
+
|
37 |
+
Args:
|
38 |
+
filename (str): The name of the markdown file (without extension).
|
39 |
+
content (str): The system content/instructions.
|
40 |
+
purpose (str): The purpose/description of the prompt.
|
41 |
+
|
42 |
+
Returns:
|
43 |
+
str: The generated markdown content.
|
44 |
+
"""
|
45 |
+
markdown_template = f"""---
|
46 |
+
PromptInfo:
|
47 |
+
promptId: {filename}
|
48 |
+
name: {filename}
|
49 |
+
description: {purpose}
|
50 |
+
required_values:
|
51 |
+
author: fabric
|
52 |
+
tags:
|
53 |
+
version: 1
|
54 |
+
config:
|
55 |
+
mode: insert
|
56 |
+
system: {content}
|
57 |
+
---
|
58 |
+
|
59 |
+
{{{{selection}}}}
|
60 |
+
"""
|
61 |
+
return markdown_template
|
62 |
+
|
63 |
+
def generate_markdown_files(client: QdrantClient, collection_name: str, output_folder: str) -> None:
|
64 |
+
"""Generate markdown files from the Qdrant database.
|
65 |
+
|
66 |
+
Args:
|
67 |
+
client: Initialized Qdrant client
|
68 |
+
collection_name: Name of the collection to query
|
69 |
+
output_folder: Directory where the markdown files will be created
|
70 |
+
|
71 |
+
Raises:
|
72 |
+
DatabaseError: If database query fails
|
73 |
+
OSError: If file operations fail
|
74 |
+
ValueError: If output folder is invalid
|
75 |
+
"""
|
76 |
+
try:
|
77 |
+
# Validate output folder
|
78 |
+
output_path = Path(output_folder)
|
79 |
+
if not output_path.exists():
|
80 |
+
output_path.mkdir(parents=True, exist_ok=True)
|
81 |
+
logger.info(f"Created markdown output directory: {output_path}")
|
82 |
+
|
83 |
+
# Query all entries from the database
|
84 |
+
try:
|
85 |
+
results = client.scroll(
|
86 |
+
collection_name=collection_name,
|
87 |
+
limit=10000 # Adjust based on expected maximum files
|
88 |
+
)[0] # scroll returns a tuple (points, next_page_offset)
|
89 |
+
|
90 |
+
# Generate markdown files for each entry
|
91 |
+
for point in results:
|
92 |
+
metadata = point.metadata
|
93 |
+
filename = metadata['filename']
|
94 |
+
content = metadata['content']
|
95 |
+
purpose = metadata['purpose']
|
96 |
+
|
97 |
+
# Generate markdown content
|
98 |
+
markdown_content = generate_markdown(filename, content, purpose)
|
99 |
+
|
100 |
+
# Write to file
|
101 |
+
file_path = output_path / f"{filename}.md"
|
102 |
+
with open(file_path, 'w', encoding='utf-8') as f:
|
103 |
+
f.write(markdown_content)
|
104 |
+
|
105 |
+
logger.info(f"Generated {len(results)} markdown files in {output_path}")
|
106 |
+
|
107 |
+
except Exception as e:
|
108 |
+
logger.error(f"Error querying database: {e}")
|
109 |
+
raise
|
110 |
+
|
111 |
+
except Exception as e:
|
112 |
+
logger.error(f"Error generating markdown files: {e}")
|
113 |
+
raise
|
src/search_qdrant/__init__.py
ADDED
File without changes
|
src/search_qdrant/database_query.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
from src.fabrics_processor.database import initialize_qdrant_database
|
3 |
+
from qdrant_client import QdrantClient
|
4 |
+
from qdrant_client.models import QueryResponse
|
5 |
+
import argparse
|
6 |
+
from src.fabrics_processor.config import config
|
7 |
+
|
8 |
+
def query_qdrant_database(
|
9 |
+
query: str,
|
10 |
+
client: QdrantClient,
|
11 |
+
num_results: int = 5,
|
12 |
+
collection_name: str = config.embedding.collection_name) -> list[QueryResponse]:
|
13 |
+
"""Query the Qdrant database for similar documents.
|
14 |
+
|
15 |
+
Args:
|
16 |
+
query: The search query text
|
17 |
+
client: Initialized QdrantClient instance
|
18 |
+
num_results: Maximum number of results to return
|
19 |
+
collection_name: Name of the collection to query
|
20 |
+
|
21 |
+
Returns:
|
22 |
+
List of QueryResponse objects containing matches
|
23 |
+
|
24 |
+
Raises:
|
25 |
+
QdrantException: If there's an error querying the database
|
26 |
+
"""
|
27 |
+
try:
|
28 |
+
results = client.query(collection_name=collection_name, query_text=query, limit=num_results)
|
29 |
+
return results
|
30 |
+
except Exception as e:
|
31 |
+
logging.error(f"Error querying Qdrant database: {e}")
|
32 |
+
raise
|
33 |
+
|
34 |
+
def main():
|
35 |
+
client = initialize_qdrant_database()
|
36 |
+
|
37 |
+
parser = argparse.ArgumentParser(description="Query Qdrant database")
|
38 |
+
parser.add_argument("query", type=str, help="The search query text")
|
39 |
+
parser.add_argument("--num_results", "-n", type=int, default=5, help="The number of results to return (default: 5)")
|
40 |
+
parser.add_argument("--collection_name", "-c", type=str, default=config.embedding.collection_name, help="The name of the collection to query.")
|
41 |
+
|
42 |
+
args = parser.parse_args()
|
43 |
+
|
44 |
+
try:
|
45 |
+
results = query_qdrant_database(query=args.query,
|
46 |
+
client=client,
|
47 |
+
num_results=args.num_results,
|
48 |
+
collection_name=args.collection_name
|
49 |
+
)
|
50 |
+
|
51 |
+
filenames = [r.metadata['filename'] for r in results]
|
52 |
+
print(filenames)
|
53 |
+
finally:
|
54 |
+
client.close()
|
55 |
+
|
56 |
+
if __name__ == "__main__":
|
57 |
+
main()
|
src/search_qdrant/logs/fabric_to_espanso.log.1
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
2025-01-10 20:20:51,583 - fabric_to_espanso - INFO - Processed: create_ttrc_narrative
|
2 |
+
2025-01-10 20:20:51,597 - fabric_to_espanso - INFO - Processed: prepare_7s_strategy
|
3 |
+
2025-01-10 20:20:51,601 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/convert_to_markdown/system.md
|
4 |
+
2025-01-10 20:20:51,606 - fabric_to_espanso - INFO - Processed: convert_to_markdown
|
5 |
+
2025-01-10 20:20:51,611 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/analyze_incident/system.md
|
6 |
+
2025-01-10 20:20:51,615 - fabric_to_espanso - INFO - Processed: analyze_incident
|
7 |
+
2025-01-10 20:20:51,619 - fabric_to_espanso - INFO - Processed: summarize_meeting
|
8 |
+
2025-01-10 20:20:51,623 - fabric_to_espanso - INFO - Processed: create_formal_email
|
9 |
+
2025-01-10 20:20:51,627 - fabric_to_espanso - INFO - Processed: refine_design_document
|
10 |
+
2025-01-10 20:20:51,631 - fabric_to_espanso - INFO - Processed: improve_prompt
|
11 |
+
2025-01-10 20:20:51,636 - fabric_to_espanso - INFO - Processed: create_logo
|
12 |
+
2025-01-10 20:20:51,640 - fabric_to_espanso - INFO - Processed: create_network_threat_landscape
|
13 |
+
2025-01-10 20:20:51,645 - fabric_to_espanso - INFO - Processed: extract_most_redeeming_thing
|
14 |
+
2025-01-10 20:20:51,649 - fabric_to_espanso - INFO - Processed: create_rpg_summary
|
15 |
+
2025-01-10 20:20:51,653 - fabric_to_espanso - INFO - Processed: analyze_proposition
|
16 |
+
2025-01-10 20:20:51,658 - fabric_to_espanso - INFO - Processed: write_nuclei_template_rule
|
17 |
+
2025-01-10 20:20:51,664 - fabric_to_espanso - INFO - Processed: analyze_email_headers
|
18 |
+
2025-01-10 20:20:51,668 - fabric_to_espanso - INFO - Processed: analyze_presentation
|
19 |
+
2025-01-10 20:20:51,672 - fabric_to_espanso - INFO - Processed: improve_writing
|
20 |
+
2025-01-10 20:20:51,677 - fabric_to_espanso - INFO - Processed: create_user_story
|
21 |
+
2025-01-10 20:20:51,682 - fabric_to_espanso - INFO - Processed: create_stride_threat_model
|
22 |
+
2025-01-10 20:20:51,686 - fabric_to_espanso - INFO - Processed: analyze_debate
|
23 |
+
2025-01-10 20:20:51,691 - fabric_to_espanso - INFO - Processed: analyze_spiritual_text
|
24 |
+
2025-01-10 20:20:51,696 - fabric_to_espanso - INFO - Processed: write_pull-request
|
25 |
+
2025-01-10 20:20:51,701 - fabric_to_espanso - INFO - Processed: extract_insights_dm
|
26 |
+
2025-01-10 20:20:51,705 - fabric_to_espanso - INFO - Processed: analyze_military_strategy
|
27 |
+
2025-01-10 20:20:51,709 - fabric_to_espanso - INFO - Processed: analyze_personality
|
28 |
+
2025-01-10 20:20:51,714 - fabric_to_espanso - INFO - Processed: transcribe_minutes
|
29 |
+
2025-01-10 20:20:51,718 - fabric_to_espanso - INFO - Processed: extract_recipe
|
30 |
+
2025-01-10 20:20:51,722 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/write_python_code_with_explanations/system.md
|
31 |
+
2025-01-10 20:20:51,726 - fabric_to_espanso - INFO - Processed: write_python_code_with_explanations
|
32 |
+
2025-01-10 20:20:51,730 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/summarize_paper/system.md
|
33 |
+
2025-01-10 20:20:51,734 - fabric_to_espanso - INFO - Processed: summarize_paper
|
34 |
+
2025-01-10 20:20:51,738 - fabric_to_espanso - INFO - Processed: check_agreement
|
35 |
+
2025-01-10 20:20:51,744 - fabric_to_espanso - INFO - Processed: find_logical_fallacies
|
36 |
+
2025-01-10 20:20:51,749 - fabric_to_espanso - INFO - Processed: extract_wisdom
|
37 |
+
2025-01-10 20:20:51,753 - fabric_to_espanso - INFO - Processed: extract_wisdom_nometa
|
38 |
+
2025-01-10 20:20:51,757 - fabric_to_espanso - INFO - Processed: create_image_prompt_from_book_extract
|
39 |
+
2025-01-10 20:20:51,762 - fabric_to_espanso - INFO - Processed: identify_dsrp_distinctions
|
40 |
+
2025-01-10 20:20:51,766 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/rewrite_python_code_with_explanations/system.md
|
41 |
+
2025-01-10 20:20:51,770 - fabric_to_espanso - INFO - Processed: rewrite_python_code_with_explanations
|
42 |
+
2025-01-10 20:20:51,774 - fabric_to_espanso - INFO - Processed: extract_controversial_ideas
|
43 |
+
2025-01-10 20:20:51,779 - fabric_to_espanso - INFO - Processed: create_tags
|
44 |
+
2025-01-10 20:20:51,783 - fabric_to_espanso - INFO - Processed: review_design
|
45 |
+
2025-01-10 20:20:51,787 - fabric_to_espanso - INFO - Processed: create_art_prompt
|
46 |
+
2025-01-10 20:20:51,791 - fabric_to_espanso - INFO - Processed: analyze_patent
|
47 |
+
2025-01-10 20:20:51,795 - fabric_to_espanso - INFO - Processed: identify_dsrp_relationships
|
48 |
+
2025-01-10 20:20:51,799 - fabric_to_espanso - INFO - Processed: analyze_cfp_submission
|
49 |
+
2025-01-10 20:20:51,803 - fabric_to_espanso - INFO - Processed: create_mermaid_visualization_for_github
|
50 |
+
2025-01-10 20:20:51,807 - fabric_to_espanso - INFO - Processed: create_graph_from_input
|
51 |
+
2025-01-10 20:20:51,812 - fabric_to_espanso - INFO - Processed: extract_main_idea
|
52 |
+
2025-01-10 20:20:51,816 - fabric_to_espanso - INFO - Processed: extract_latest_video
|
53 |
+
2025-01-10 20:20:51,819 - fabric_to_espanso - INFO - Processed: extract_core_message
|
54 |
+
2025-01-10 20:20:51,823 - fabric_to_espanso - INFO - Processed: extract_jokes
|
55 |
+
2025-01-10 20:20:51,827 - fabric_to_espanso - INFO - Processed: create_academic_paper
|
56 |
+
2025-01-10 20:20:51,831 - fabric_to_espanso - INFO - Processed: create_reading_plan
|
57 |
+
2025-01-10 20:20:51,835 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/added_something_stupid/system.md
|
58 |
+
2025-01-10 20:20:51,839 - fabric_to_espanso - INFO - Processed: added_something_stupid
|
59 |
+
2025-01-10 20:20:51,844 - fabric_to_espanso - INFO - Processed: analyze_risk
|
60 |
+
2025-01-10 20:20:51,848 - fabric_to_espanso - INFO - Processed: improve_report_finding
|
61 |
+
2025-01-10 20:20:51,852 - fabric_to_espanso - INFO - Processed: explain_math
|
62 |
+
2025-01-10 20:20:51,855 - fabric_to_espanso - INFO - Processed: summarize_git_changes
|
63 |
+
2025-01-10 20:20:51,860 - fabric_to_espanso - INFO - Processed: recommend_talkpanel_topics
|
64 |
+
2025-01-10 20:20:51,864 - fabric_to_espanso - INFO - Processed: extract_predictions
|
65 |
+
2025-01-10 20:20:51,868 - fabric_to_espanso - INFO - Processed: extract_primary_solution
|
66 |
+
2025-01-10 20:20:51,872 - fabric_to_espanso - INFO - Processed: extract_videoid
|
67 |
+
2025-01-10 20:20:51,877 - fabric_to_espanso - INFO - Processed: create_show_intro
|
68 |
+
2025-01-10 20:20:51,881 - fabric_to_espanso - INFO - Processed: summarize_git_diff
|
69 |
+
2025-01-10 20:20:51,884 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/website_description/system.md
|
70 |
+
2025-01-10 20:20:51,889 - fabric_to_espanso - INFO - Processed: website_description
|
71 |
+
2025-01-10 20:20:51,892 - fabric_to_espanso - INFO - Processed: create_quiz
|
72 |
+
2025-01-10 20:20:51,897 - fabric_to_espanso - INFO - Processed: write_semgrep_rule
|
73 |
+
2025-01-10 20:20:51,901 - fabric_to_espanso - INFO - Processed: write_hackerone_report
|
74 |
+
2025-01-10 20:20:51,905 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/translate_to_dutch_or_from_dutch_to_english/system.md
|
75 |
+
2025-01-10 20:20:51,909 - fabric_to_espanso - INFO - Processed: translate_to_dutch_or_from_dutch_to_english
|
76 |
+
2025-01-10 20:20:51,913 - fabric_to_espanso - INFO - Processed: summarize_micro
|
77 |
+
2025-01-10 20:20:51,917 - fabric_to_espanso - INFO - Processed: create_ai_jobs_analysis
|
78 |
+
2025-01-10 20:20:51,920 - fabric_to_espanso - INFO - Processed: create_pattern
|
79 |
+
2025-01-10 20:20:51,924 - fabric_to_espanso - INFO - Processed: capture_thinkers_work
|
80 |
+
2025-01-10 20:20:51,929 - fabric_to_espanso - INFO - Processed: analyze_prose_pinker
|
81 |
+
2025-01-10 20:20:51,933 - fabric_to_espanso - INFO - Processed: create_threat_scenarios
|
82 |
+
2025-01-10 20:20:51,938 - fabric_to_espanso - INFO - Processed: extract_ctf_writeup
|
83 |
+
2025-01-10 20:20:51,941 - fabric_to_espanso - INFO - Processed: create_fabric_patterns
|
84 |
+
2025-01-10 20:20:51,946 - fabric_to_espanso - INFO - Processed: ai
|
85 |
+
2025-01-10 20:20:51,950 - fabric_to_espanso - INFO - Processed: rate_ai_response
|
86 |
+
2025-01-10 20:20:51,954 - fabric_to_espanso - INFO - Processed: create_prd
|
87 |
+
2025-01-10 20:20:51,958 - fabric_to_espanso - INFO - Processed: clean_text
|
88 |
+
2025-01-10 20:20:51,962 - fabric_to_espanso - INFO - Processed: create_video_chapters
|
89 |
+
2025-01-10 20:20:51,966 - fabric_to_espanso - INFO - Processed: summarize_lecture
|
90 |
+
2025-01-10 20:20:51,971 - fabric_to_espanso - INFO - Processed: identify_dsrp_perspectives
|
91 |
+
2025-01-10 20:20:51,975 - fabric_to_espanso - INFO - Processed: recommend_artists
|
92 |
+
2025-01-10 20:20:51,979 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process_detailed/system.md
|
93 |
+
2025-01-10 20:20:51,983 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process_detailed
|
94 |
+
2025-01-10 20:20:51,987 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process_detailed_extreme/system.md
|
95 |
+
2025-01-10 20:20:51,992 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process_detailed_extreme
|
96 |
+
2025-01-10 20:20:51,996 - fabric_to_espanso - INFO - Processed: extract_ideas
|
97 |
+
2025-01-10 20:20:52,000 - fabric_to_espanso - INFO - Processed: to_flashcards
|
98 |
+
2025-01-10 20:20:52,016 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/extract_instructions/system.md
|
99 |
+
2025-01-10 20:20:52,028 - fabric_to_espanso - INFO - Processed: extract_instructions
|
100 |
+
2025-01-10 20:20:52,032 - fabric_to_espanso - INFO - Processed: write_micro_essay
|
101 |
+
2025-01-10 20:20:52,036 - fabric_to_espanso - INFO - Processed: extract_keywords_and_subjects_from_text
|
102 |
+
2025-01-10 20:20:52,045 - fabric_to_espanso - INFO - Processed: extract_primary_problem
|
103 |
+
2025-01-10 20:20:52,053 - fabric_to_espanso - INFO - Processed: create_hormozi_offer
|
104 |
+
2025-01-10 20:20:52,059 - fabric_to_espanso - INFO - Processed: analyze_prose
|
105 |
+
2025-01-10 20:20:52,064 - fabric_to_espanso - INFO - Processed: analyze_logs
|
106 |
+
2025-01-10 20:20:52,068 - fabric_to_espanso - INFO - Processed: create_recursive_outline
|
107 |
+
2025-01-10 20:20:52,072 - fabric_to_espanso - INFO - Processed: analyze_tech_impact
|
108 |
+
2025-01-10 20:20:52,077 - fabric_to_espanso - INFO - Processed: find_hidden_message
|
109 |
+
2025-01-10 20:20:52,088 - fabric_to_espanso - INFO - Processed: create_npc
|
110 |
+
2025-01-10 20:20:52,104 - fabric_to_espanso - INFO - Processed: provide_guidance
|
111 |
+
2025-01-10 20:20:52,113 - fabric_to_espanso - INFO - Processed: export_data_as_csv
|
112 |
+
2025-01-10 20:20:52,120 - fabric_to_espanso - INFO - Processed: show_fabric_options_markmap
|
113 |
+
2025-01-10 20:20:52,127 - fabric_to_espanso - INFO - Processed: summarize_debate
|
114 |
+
2025-01-10 20:20:52,134 - fabric_to_espanso - INFO - Processed: answer_interview_question
|
115 |
+
2025-01-10 20:20:52,141 - fabric_to_espanso - INFO - Processed: extract_poc
|
116 |
+
2025-01-10 20:20:52,148 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process/system.md
|
117 |
+
2025-01-10 20:20:52,155 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process
|
118 |
+
2025-01-10 20:20:52,163 - fabric_to_espanso - INFO - Processed: rate_content
|
119 |
+
2025-01-10 20:20:52,170 - fabric_to_espanso - INFO - Processed: create_diy
|
120 |
+
2025-01-10 20:20:52,178 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/create_costar_prompt/system.md
|
121 |
+
2025-01-10 20:20:52,186 - fabric_to_espanso - INFO - Processed: create_costar_prompt
|
122 |
+
2025-01-10 20:20:52,193 - fabric_to_espanso - INFO - Processed: create_idea_compass
|
123 |
+
2025-01-10 20:20:52,200 - fabric_to_espanso - INFO - Processed: create_security_update
|
124 |
+
2025-01-10 20:20:52,206 - fabric_to_espanso - INFO - Processed: extract_recommendations
|
125 |
+
2025-01-10 20:20:52,214 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/md_callout/system.md
|
126 |
+
2025-01-10 20:20:52,222 - fabric_to_espanso - INFO - Processed: md_callout
|
127 |
+
2025-01-10 20:20:52,229 - fabric_to_espanso - INFO - Processed: analyze_threat_report
|
128 |
+
2025-01-10 20:20:52,236 - fabric_to_espanso - INFO - Processed: dialog_with_socrates
|
129 |
+
2025-01-10 20:20:52,245 - fabric_to_espanso - INFO - Processed: summarize_newsletter
|
130 |
+
2025-01-10 20:20:52,251 - fabric_to_espanso - INFO - Processed: create_mermaid_visualization
|
131 |
+
2025-01-10 20:20:52,258 - fabric_to_espanso - INFO - Processed: analyze_comments
|
132 |
+
2025-01-10 20:20:52,265 - fabric_to_espanso - INFO - Processed: summarize
|
133 |
+
2025-01-10 20:20:52,271 - fabric_to_espanso - INFO - Processed: compare_and_contrast
|
134 |
+
2025-01-10 20:20:52,278 - fabric_to_espanso - INFO - Successfully processed 199 files in fabric patterns folder
|
135 |
+
2025-01-10 20:20:52,323 - fabric_to_espanso - INFO - Changes detected: 0 new, 0 modified, 0 deleted
|
src/search_qdrant/logs/fabric_to_espanso.log.2
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
2025-01-10 20:20:51,570 - fabric_to_espanso - INFO - Processed: extract_wisdom_dm
|
2 |
+
2025-01-10 20:20:51,583 - fabric_to_espanso - INFO - Processed: create_ttrc_narrative
|
3 |
+
2025-01-10 20:20:51,597 - fabric_to_espanso - INFO - Processed: prepare_7s_strategy
|
4 |
+
2025-01-10 20:20:51,601 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/convert_to_markdown/system.md
|
5 |
+
2025-01-10 20:20:51,606 - fabric_to_espanso - INFO - Processed: convert_to_markdown
|
6 |
+
2025-01-10 20:20:51,611 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/analyze_incident/system.md
|
7 |
+
2025-01-10 20:20:51,615 - fabric_to_espanso - INFO - Processed: analyze_incident
|
8 |
+
2025-01-10 20:20:51,619 - fabric_to_espanso - INFO - Processed: summarize_meeting
|
9 |
+
2025-01-10 20:20:51,623 - fabric_to_espanso - INFO - Processed: create_formal_email
|
10 |
+
2025-01-10 20:20:51,627 - fabric_to_espanso - INFO - Processed: refine_design_document
|
11 |
+
2025-01-10 20:20:51,631 - fabric_to_espanso - INFO - Processed: improve_prompt
|
12 |
+
2025-01-10 20:20:51,636 - fabric_to_espanso - INFO - Processed: create_logo
|
13 |
+
2025-01-10 20:20:51,640 - fabric_to_espanso - INFO - Processed: create_network_threat_landscape
|
14 |
+
2025-01-10 20:20:51,645 - fabric_to_espanso - INFO - Processed: extract_most_redeeming_thing
|
15 |
+
2025-01-10 20:20:51,649 - fabric_to_espanso - INFO - Processed: create_rpg_summary
|
16 |
+
2025-01-10 20:20:51,653 - fabric_to_espanso - INFO - Processed: analyze_proposition
|
17 |
+
2025-01-10 20:20:51,658 - fabric_to_espanso - INFO - Processed: write_nuclei_template_rule
|
18 |
+
2025-01-10 20:20:51,664 - fabric_to_espanso - INFO - Processed: analyze_email_headers
|
19 |
+
2025-01-10 20:20:51,668 - fabric_to_espanso - INFO - Processed: analyze_presentation
|
20 |
+
2025-01-10 20:20:51,672 - fabric_to_espanso - INFO - Processed: improve_writing
|
21 |
+
2025-01-10 20:20:51,677 - fabric_to_espanso - INFO - Processed: create_user_story
|
22 |
+
2025-01-10 20:20:51,682 - fabric_to_espanso - INFO - Processed: create_stride_threat_model
|
23 |
+
2025-01-10 20:20:51,686 - fabric_to_espanso - INFO - Processed: analyze_debate
|
24 |
+
2025-01-10 20:20:51,691 - fabric_to_espanso - INFO - Processed: analyze_spiritual_text
|
25 |
+
2025-01-10 20:20:51,696 - fabric_to_espanso - INFO - Processed: write_pull-request
|
26 |
+
2025-01-10 20:20:51,701 - fabric_to_espanso - INFO - Processed: extract_insights_dm
|
27 |
+
2025-01-10 20:20:51,705 - fabric_to_espanso - INFO - Processed: analyze_military_strategy
|
28 |
+
2025-01-10 20:20:51,709 - fabric_to_espanso - INFO - Processed: analyze_personality
|
29 |
+
2025-01-10 20:20:51,714 - fabric_to_espanso - INFO - Processed: transcribe_minutes
|
30 |
+
2025-01-10 20:20:51,718 - fabric_to_espanso - INFO - Processed: extract_recipe
|
31 |
+
2025-01-10 20:20:51,722 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/write_python_code_with_explanations/system.md
|
32 |
+
2025-01-10 20:20:51,726 - fabric_to_espanso - INFO - Processed: write_python_code_with_explanations
|
33 |
+
2025-01-10 20:20:51,730 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/summarize_paper/system.md
|
34 |
+
2025-01-10 20:20:51,734 - fabric_to_espanso - INFO - Processed: summarize_paper
|
35 |
+
2025-01-10 20:20:51,738 - fabric_to_espanso - INFO - Processed: check_agreement
|
36 |
+
2025-01-10 20:20:51,744 - fabric_to_espanso - INFO - Processed: find_logical_fallacies
|
37 |
+
2025-01-10 20:20:51,749 - fabric_to_espanso - INFO - Processed: extract_wisdom
|
38 |
+
2025-01-10 20:20:51,753 - fabric_to_espanso - INFO - Processed: extract_wisdom_nometa
|
39 |
+
2025-01-10 20:20:51,757 - fabric_to_espanso - INFO - Processed: create_image_prompt_from_book_extract
|
40 |
+
2025-01-10 20:20:51,762 - fabric_to_espanso - INFO - Processed: identify_dsrp_distinctions
|
41 |
+
2025-01-10 20:20:51,766 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/rewrite_python_code_with_explanations/system.md
|
42 |
+
2025-01-10 20:20:51,770 - fabric_to_espanso - INFO - Processed: rewrite_python_code_with_explanations
|
43 |
+
2025-01-10 20:20:51,774 - fabric_to_espanso - INFO - Processed: extract_controversial_ideas
|
44 |
+
2025-01-10 20:20:51,779 - fabric_to_espanso - INFO - Processed: create_tags
|
45 |
+
2025-01-10 20:20:51,783 - fabric_to_espanso - INFO - Processed: review_design
|
46 |
+
2025-01-10 20:20:51,787 - fabric_to_espanso - INFO - Processed: create_art_prompt
|
47 |
+
2025-01-10 20:20:51,791 - fabric_to_espanso - INFO - Processed: analyze_patent
|
48 |
+
2025-01-10 20:20:51,795 - fabric_to_espanso - INFO - Processed: identify_dsrp_relationships
|
49 |
+
2025-01-10 20:20:51,799 - fabric_to_espanso - INFO - Processed: analyze_cfp_submission
|
50 |
+
2025-01-10 20:20:51,803 - fabric_to_espanso - INFO - Processed: create_mermaid_visualization_for_github
|
51 |
+
2025-01-10 20:20:51,807 - fabric_to_espanso - INFO - Processed: create_graph_from_input
|
52 |
+
2025-01-10 20:20:51,812 - fabric_to_espanso - INFO - Processed: extract_main_idea
|
53 |
+
2025-01-10 20:20:51,816 - fabric_to_espanso - INFO - Processed: extract_latest_video
|
54 |
+
2025-01-10 20:20:51,819 - fabric_to_espanso - INFO - Processed: extract_core_message
|
55 |
+
2025-01-10 20:20:51,823 - fabric_to_espanso - INFO - Processed: extract_jokes
|
56 |
+
2025-01-10 20:20:51,827 - fabric_to_espanso - INFO - Processed: create_academic_paper
|
57 |
+
2025-01-10 20:20:51,831 - fabric_to_espanso - INFO - Processed: create_reading_plan
|
58 |
+
2025-01-10 20:20:51,835 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/added_something_stupid/system.md
|
59 |
+
2025-01-10 20:20:51,839 - fabric_to_espanso - INFO - Processed: added_something_stupid
|
60 |
+
2025-01-10 20:20:51,844 - fabric_to_espanso - INFO - Processed: analyze_risk
|
61 |
+
2025-01-10 20:20:51,848 - fabric_to_espanso - INFO - Processed: improve_report_finding
|
62 |
+
2025-01-10 20:20:51,852 - fabric_to_espanso - INFO - Processed: explain_math
|
63 |
+
2025-01-10 20:20:51,855 - fabric_to_espanso - INFO - Processed: summarize_git_changes
|
64 |
+
2025-01-10 20:20:51,860 - fabric_to_espanso - INFO - Processed: recommend_talkpanel_topics
|
65 |
+
2025-01-10 20:20:51,864 - fabric_to_espanso - INFO - Processed: extract_predictions
|
66 |
+
2025-01-10 20:20:51,868 - fabric_to_espanso - INFO - Processed: extract_primary_solution
|
67 |
+
2025-01-10 20:20:51,872 - fabric_to_espanso - INFO - Processed: extract_videoid
|
68 |
+
2025-01-10 20:20:51,877 - fabric_to_espanso - INFO - Processed: create_show_intro
|
69 |
+
2025-01-10 20:20:51,881 - fabric_to_espanso - INFO - Processed: summarize_git_diff
|
70 |
+
2025-01-10 20:20:51,884 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/website_description/system.md
|
71 |
+
2025-01-10 20:20:51,889 - fabric_to_espanso - INFO - Processed: website_description
|
72 |
+
2025-01-10 20:20:51,892 - fabric_to_espanso - INFO - Processed: create_quiz
|
73 |
+
2025-01-10 20:20:51,897 - fabric_to_espanso - INFO - Processed: write_semgrep_rule
|
74 |
+
2025-01-10 20:20:51,901 - fabric_to_espanso - INFO - Processed: write_hackerone_report
|
75 |
+
2025-01-10 20:20:51,905 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/translate_to_dutch_or_from_dutch_to_english/system.md
|
76 |
+
2025-01-10 20:20:51,909 - fabric_to_espanso - INFO - Processed: translate_to_dutch_or_from_dutch_to_english
|
77 |
+
2025-01-10 20:20:51,913 - fabric_to_espanso - INFO - Processed: summarize_micro
|
78 |
+
2025-01-10 20:20:51,917 - fabric_to_espanso - INFO - Processed: create_ai_jobs_analysis
|
79 |
+
2025-01-10 20:20:51,920 - fabric_to_espanso - INFO - Processed: create_pattern
|
80 |
+
2025-01-10 20:20:51,924 - fabric_to_espanso - INFO - Processed: capture_thinkers_work
|
81 |
+
2025-01-10 20:20:51,929 - fabric_to_espanso - INFO - Processed: analyze_prose_pinker
|
82 |
+
2025-01-10 20:20:51,933 - fabric_to_espanso - INFO - Processed: create_threat_scenarios
|
83 |
+
2025-01-10 20:20:51,938 - fabric_to_espanso - INFO - Processed: extract_ctf_writeup
|
84 |
+
2025-01-10 20:20:51,941 - fabric_to_espanso - INFO - Processed: create_fabric_patterns
|
85 |
+
2025-01-10 20:20:51,946 - fabric_to_espanso - INFO - Processed: ai
|
86 |
+
2025-01-10 20:20:51,950 - fabric_to_espanso - INFO - Processed: rate_ai_response
|
87 |
+
2025-01-10 20:20:51,954 - fabric_to_espanso - INFO - Processed: create_prd
|
88 |
+
2025-01-10 20:20:51,958 - fabric_to_espanso - INFO - Processed: clean_text
|
89 |
+
2025-01-10 20:20:51,962 - fabric_to_espanso - INFO - Processed: create_video_chapters
|
90 |
+
2025-01-10 20:20:51,966 - fabric_to_espanso - INFO - Processed: summarize_lecture
|
91 |
+
2025-01-10 20:20:51,971 - fabric_to_espanso - INFO - Processed: identify_dsrp_perspectives
|
92 |
+
2025-01-10 20:20:51,975 - fabric_to_espanso - INFO - Processed: recommend_artists
|
93 |
+
2025-01-10 20:20:51,979 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process_detailed/system.md
|
94 |
+
2025-01-10 20:20:51,983 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process_detailed
|
95 |
+
2025-01-10 20:20:51,987 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process_detailed_extreme/system.md
|
96 |
+
2025-01-10 20:20:51,992 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process_detailed_extreme
|
97 |
+
2025-01-10 20:20:51,996 - fabric_to_espanso - INFO - Processed: extract_ideas
|
98 |
+
2025-01-10 20:20:52,000 - fabric_to_espanso - INFO - Processed: to_flashcards
|
99 |
+
2025-01-10 20:20:52,016 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/extract_instructions/system.md
|
100 |
+
2025-01-10 20:20:52,028 - fabric_to_espanso - INFO - Processed: extract_instructions
|
101 |
+
2025-01-10 20:20:52,032 - fabric_to_espanso - INFO - Processed: write_micro_essay
|
102 |
+
2025-01-10 20:20:52,036 - fabric_to_espanso - INFO - Processed: extract_keywords_and_subjects_from_text
|
103 |
+
2025-01-10 20:20:52,045 - fabric_to_espanso - INFO - Processed: extract_primary_problem
|
104 |
+
2025-01-10 20:20:52,053 - fabric_to_espanso - INFO - Processed: create_hormozi_offer
|
105 |
+
2025-01-10 20:20:52,059 - fabric_to_espanso - INFO - Processed: analyze_prose
|
106 |
+
2025-01-10 20:20:52,064 - fabric_to_espanso - INFO - Processed: analyze_logs
|
107 |
+
2025-01-10 20:20:52,068 - fabric_to_espanso - INFO - Processed: create_recursive_outline
|
108 |
+
2025-01-10 20:20:52,072 - fabric_to_espanso - INFO - Processed: analyze_tech_impact
|
109 |
+
2025-01-10 20:20:52,077 - fabric_to_espanso - INFO - Processed: find_hidden_message
|
110 |
+
2025-01-10 20:20:52,088 - fabric_to_espanso - INFO - Processed: create_npc
|
111 |
+
2025-01-10 20:20:52,104 - fabric_to_espanso - INFO - Processed: provide_guidance
|
112 |
+
2025-01-10 20:20:52,113 - fabric_to_espanso - INFO - Processed: export_data_as_csv
|
113 |
+
2025-01-10 20:20:52,120 - fabric_to_espanso - INFO - Processed: show_fabric_options_markmap
|
114 |
+
2025-01-10 20:20:52,127 - fabric_to_espanso - INFO - Processed: summarize_debate
|
115 |
+
2025-01-10 20:20:52,134 - fabric_to_espanso - INFO - Processed: answer_interview_question
|
116 |
+
2025-01-10 20:20:52,141 - fabric_to_espanso - INFO - Processed: extract_poc
|
117 |
+
2025-01-10 20:20:52,148 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process/system.md
|
118 |
+
2025-01-10 20:20:52,155 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process
|
119 |
+
2025-01-10 20:20:52,163 - fabric_to_espanso - INFO - Processed: rate_content
|
120 |
+
2025-01-10 20:20:52,170 - fabric_to_espanso - INFO - Processed: create_diy
|
121 |
+
2025-01-10 20:20:52,178 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/create_costar_prompt/system.md
|
122 |
+
2025-01-10 20:20:52,186 - fabric_to_espanso - INFO - Processed: create_costar_prompt
|
123 |
+
2025-01-10 20:20:52,193 - fabric_to_espanso - INFO - Processed: create_idea_compass
|
124 |
+
2025-01-10 20:20:52,200 - fabric_to_espanso - INFO - Processed: create_security_update
|
125 |
+
2025-01-10 20:20:52,206 - fabric_to_espanso - INFO - Processed: extract_recommendations
|
126 |
+
2025-01-10 20:20:52,214 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/md_callout/system.md
|
127 |
+
2025-01-10 20:20:52,222 - fabric_to_espanso - INFO - Processed: md_callout
|
128 |
+
2025-01-10 20:20:52,229 - fabric_to_espanso - INFO - Processed: analyze_threat_report
|
129 |
+
2025-01-10 20:20:52,236 - fabric_to_espanso - INFO - Processed: dialog_with_socrates
|
130 |
+
2025-01-10 20:20:52,245 - fabric_to_espanso - INFO - Processed: summarize_newsletter
|
131 |
+
2025-01-10 20:20:52,251 - fabric_to_espanso - INFO - Processed: create_mermaid_visualization
|
132 |
+
2025-01-10 20:20:52,258 - fabric_to_espanso - INFO - Processed: analyze_comments
|
133 |
+
2025-01-10 20:20:52,265 - fabric_to_espanso - INFO - Processed: summarize
|
134 |
+
2025-01-10 20:20:52,271 - fabric_to_espanso - INFO - Processed: compare_and_contrast
|
135 |
+
2025-01-10 20:20:52,278 - fabric_to_espanso - INFO - Successfully processed 199 files in fabric patterns folder
|
136 |
+
2025-01-10 20:20:52,323 - fabric_to_espanso - INFO - Changes detected: 0 new, 0 modified, 0 deleted
|
src/search_qdrant/logs/fabric_to_espanso.log.3
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
2025-01-10 20:20:51,570 - fabric_to_espanso - INFO - Processed: extract_wisdom_dm
|
2 |
+
2025-01-10 20:20:51,583 - fabric_to_espanso - INFO - Processed: create_ttrc_narrative
|
3 |
+
2025-01-10 20:20:51,597 - fabric_to_espanso - INFO - Processed: prepare_7s_strategy
|
4 |
+
2025-01-10 20:20:51,601 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/convert_to_markdown/system.md
|
5 |
+
2025-01-10 20:20:51,606 - fabric_to_espanso - INFO - Processed: convert_to_markdown
|
6 |
+
2025-01-10 20:20:51,611 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/analyze_incident/system.md
|
7 |
+
2025-01-10 20:20:51,615 - fabric_to_espanso - INFO - Processed: analyze_incident
|
8 |
+
2025-01-10 20:20:51,619 - fabric_to_espanso - INFO - Processed: summarize_meeting
|
9 |
+
2025-01-10 20:20:51,623 - fabric_to_espanso - INFO - Processed: create_formal_email
|
10 |
+
2025-01-10 20:20:51,627 - fabric_to_espanso - INFO - Processed: refine_design_document
|
11 |
+
2025-01-10 20:20:51,631 - fabric_to_espanso - INFO - Processed: improve_prompt
|
12 |
+
2025-01-10 20:20:51,636 - fabric_to_espanso - INFO - Processed: create_logo
|
13 |
+
2025-01-10 20:20:51,640 - fabric_to_espanso - INFO - Processed: create_network_threat_landscape
|
14 |
+
2025-01-10 20:20:51,645 - fabric_to_espanso - INFO - Processed: extract_most_redeeming_thing
|
15 |
+
2025-01-10 20:20:51,649 - fabric_to_espanso - INFO - Processed: create_rpg_summary
|
16 |
+
2025-01-10 20:20:51,653 - fabric_to_espanso - INFO - Processed: analyze_proposition
|
17 |
+
2025-01-10 20:20:51,658 - fabric_to_espanso - INFO - Processed: write_nuclei_template_rule
|
18 |
+
2025-01-10 20:20:51,664 - fabric_to_espanso - INFO - Processed: analyze_email_headers
|
19 |
+
2025-01-10 20:20:51,668 - fabric_to_espanso - INFO - Processed: analyze_presentation
|
20 |
+
2025-01-10 20:20:51,672 - fabric_to_espanso - INFO - Processed: improve_writing
|
21 |
+
2025-01-10 20:20:51,677 - fabric_to_espanso - INFO - Processed: create_user_story
|
22 |
+
2025-01-10 20:20:51,682 - fabric_to_espanso - INFO - Processed: create_stride_threat_model
|
23 |
+
2025-01-10 20:20:51,686 - fabric_to_espanso - INFO - Processed: analyze_debate
|
24 |
+
2025-01-10 20:20:51,691 - fabric_to_espanso - INFO - Processed: analyze_spiritual_text
|
25 |
+
2025-01-10 20:20:51,696 - fabric_to_espanso - INFO - Processed: write_pull-request
|
26 |
+
2025-01-10 20:20:51,701 - fabric_to_espanso - INFO - Processed: extract_insights_dm
|
27 |
+
2025-01-10 20:20:51,705 - fabric_to_espanso - INFO - Processed: analyze_military_strategy
|
28 |
+
2025-01-10 20:20:51,709 - fabric_to_espanso - INFO - Processed: analyze_personality
|
29 |
+
2025-01-10 20:20:51,714 - fabric_to_espanso - INFO - Processed: transcribe_minutes
|
30 |
+
2025-01-10 20:20:51,718 - fabric_to_espanso - INFO - Processed: extract_recipe
|
31 |
+
2025-01-10 20:20:51,722 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/write_python_code_with_explanations/system.md
|
32 |
+
2025-01-10 20:20:51,726 - fabric_to_espanso - INFO - Processed: write_python_code_with_explanations
|
33 |
+
2025-01-10 20:20:51,730 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/summarize_paper/system.md
|
34 |
+
2025-01-10 20:20:51,734 - fabric_to_espanso - INFO - Processed: summarize_paper
|
35 |
+
2025-01-10 20:20:51,738 - fabric_to_espanso - INFO - Processed: check_agreement
|
36 |
+
2025-01-10 20:20:51,744 - fabric_to_espanso - INFO - Processed: find_logical_fallacies
|
37 |
+
2025-01-10 20:20:51,749 - fabric_to_espanso - INFO - Processed: extract_wisdom
|
38 |
+
2025-01-10 20:20:51,753 - fabric_to_espanso - INFO - Processed: extract_wisdom_nometa
|
39 |
+
2025-01-10 20:20:51,757 - fabric_to_espanso - INFO - Processed: create_image_prompt_from_book_extract
|
40 |
+
2025-01-10 20:20:51,762 - fabric_to_espanso - INFO - Processed: identify_dsrp_distinctions
|
41 |
+
2025-01-10 20:20:51,766 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/rewrite_python_code_with_explanations/system.md
|
42 |
+
2025-01-10 20:20:51,770 - fabric_to_espanso - INFO - Processed: rewrite_python_code_with_explanations
|
43 |
+
2025-01-10 20:20:51,774 - fabric_to_espanso - INFO - Processed: extract_controversial_ideas
|
44 |
+
2025-01-10 20:20:51,779 - fabric_to_espanso - INFO - Processed: create_tags
|
45 |
+
2025-01-10 20:20:51,783 - fabric_to_espanso - INFO - Processed: review_design
|
46 |
+
2025-01-10 20:20:51,787 - fabric_to_espanso - INFO - Processed: create_art_prompt
|
47 |
+
2025-01-10 20:20:51,791 - fabric_to_espanso - INFO - Processed: analyze_patent
|
48 |
+
2025-01-10 20:20:51,795 - fabric_to_espanso - INFO - Processed: identify_dsrp_relationships
|
49 |
+
2025-01-10 20:20:51,799 - fabric_to_espanso - INFO - Processed: analyze_cfp_submission
|
50 |
+
2025-01-10 20:20:51,803 - fabric_to_espanso - INFO - Processed: create_mermaid_visualization_for_github
|
51 |
+
2025-01-10 20:20:51,807 - fabric_to_espanso - INFO - Processed: create_graph_from_input
|
52 |
+
2025-01-10 20:20:51,812 - fabric_to_espanso - INFO - Processed: extract_main_idea
|
53 |
+
2025-01-10 20:20:51,816 - fabric_to_espanso - INFO - Processed: extract_latest_video
|
54 |
+
2025-01-10 20:20:51,819 - fabric_to_espanso - INFO - Processed: extract_core_message
|
55 |
+
2025-01-10 20:20:51,823 - fabric_to_espanso - INFO - Processed: extract_jokes
|
56 |
+
2025-01-10 20:20:51,827 - fabric_to_espanso - INFO - Processed: create_academic_paper
|
57 |
+
2025-01-10 20:20:51,831 - fabric_to_espanso - INFO - Processed: create_reading_plan
|
58 |
+
2025-01-10 20:20:51,835 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/added_something_stupid/system.md
|
59 |
+
2025-01-10 20:20:51,839 - fabric_to_espanso - INFO - Processed: added_something_stupid
|
60 |
+
2025-01-10 20:20:51,844 - fabric_to_espanso - INFO - Processed: analyze_risk
|
61 |
+
2025-01-10 20:20:51,848 - fabric_to_espanso - INFO - Processed: improve_report_finding
|
62 |
+
2025-01-10 20:20:51,852 - fabric_to_espanso - INFO - Processed: explain_math
|
63 |
+
2025-01-10 20:20:51,855 - fabric_to_espanso - INFO - Processed: summarize_git_changes
|
64 |
+
2025-01-10 20:20:51,860 - fabric_to_espanso - INFO - Processed: recommend_talkpanel_topics
|
65 |
+
2025-01-10 20:20:51,864 - fabric_to_espanso - INFO - Processed: extract_predictions
|
66 |
+
2025-01-10 20:20:51,868 - fabric_to_espanso - INFO - Processed: extract_primary_solution
|
67 |
+
2025-01-10 20:20:51,872 - fabric_to_espanso - INFO - Processed: extract_videoid
|
68 |
+
2025-01-10 20:20:51,877 - fabric_to_espanso - INFO - Processed: create_show_intro
|
69 |
+
2025-01-10 20:20:51,881 - fabric_to_espanso - INFO - Processed: summarize_git_diff
|
70 |
+
2025-01-10 20:20:51,884 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/website_description/system.md
|
71 |
+
2025-01-10 20:20:51,889 - fabric_to_espanso - INFO - Processed: website_description
|
72 |
+
2025-01-10 20:20:51,892 - fabric_to_espanso - INFO - Processed: create_quiz
|
73 |
+
2025-01-10 20:20:51,897 - fabric_to_espanso - INFO - Processed: write_semgrep_rule
|
74 |
+
2025-01-10 20:20:51,901 - fabric_to_espanso - INFO - Processed: write_hackerone_report
|
75 |
+
2025-01-10 20:20:51,905 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/translate_to_dutch_or_from_dutch_to_english/system.md
|
76 |
+
2025-01-10 20:20:51,909 - fabric_to_espanso - INFO - Processed: translate_to_dutch_or_from_dutch_to_english
|
77 |
+
2025-01-10 20:20:51,913 - fabric_to_espanso - INFO - Processed: summarize_micro
|
78 |
+
2025-01-10 20:20:51,917 - fabric_to_espanso - INFO - Processed: create_ai_jobs_analysis
|
79 |
+
2025-01-10 20:20:51,920 - fabric_to_espanso - INFO - Processed: create_pattern
|
80 |
+
2025-01-10 20:20:51,924 - fabric_to_espanso - INFO - Processed: capture_thinkers_work
|
81 |
+
2025-01-10 20:20:51,929 - fabric_to_espanso - INFO - Processed: analyze_prose_pinker
|
82 |
+
2025-01-10 20:20:51,933 - fabric_to_espanso - INFO - Processed: create_threat_scenarios
|
83 |
+
2025-01-10 20:20:51,938 - fabric_to_espanso - INFO - Processed: extract_ctf_writeup
|
84 |
+
2025-01-10 20:20:51,941 - fabric_to_espanso - INFO - Processed: create_fabric_patterns
|
85 |
+
2025-01-10 20:20:51,946 - fabric_to_espanso - INFO - Processed: ai
|
86 |
+
2025-01-10 20:20:51,950 - fabric_to_espanso - INFO - Processed: rate_ai_response
|
87 |
+
2025-01-10 20:20:51,954 - fabric_to_espanso - INFO - Processed: create_prd
|
88 |
+
2025-01-10 20:20:51,958 - fabric_to_espanso - INFO - Processed: clean_text
|
89 |
+
2025-01-10 20:20:51,962 - fabric_to_espanso - INFO - Processed: create_video_chapters
|
90 |
+
2025-01-10 20:20:51,966 - fabric_to_espanso - INFO - Processed: summarize_lecture
|
91 |
+
2025-01-10 20:20:51,971 - fabric_to_espanso - INFO - Processed: identify_dsrp_perspectives
|
92 |
+
2025-01-10 20:20:51,975 - fabric_to_espanso - INFO - Processed: recommend_artists
|
93 |
+
2025-01-10 20:20:51,979 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process_detailed/system.md
|
94 |
+
2025-01-10 20:20:51,983 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process_detailed
|
95 |
+
2025-01-10 20:20:51,987 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process_detailed_extreme/system.md
|
96 |
+
2025-01-10 20:20:51,992 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process_detailed_extreme
|
97 |
+
2025-01-10 20:20:51,996 - fabric_to_espanso - INFO - Processed: extract_ideas
|
98 |
+
2025-01-10 20:20:52,000 - fabric_to_espanso - INFO - Processed: to_flashcards
|
99 |
+
2025-01-10 20:20:52,016 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/extract_instructions/system.md
|
100 |
+
2025-01-10 20:20:52,028 - fabric_to_espanso - INFO - Processed: extract_instructions
|
101 |
+
2025-01-10 20:20:52,032 - fabric_to_espanso - INFO - Processed: write_micro_essay
|
102 |
+
2025-01-10 20:20:52,036 - fabric_to_espanso - INFO - Processed: extract_keywords_and_subjects_from_text
|
103 |
+
2025-01-10 20:20:52,045 - fabric_to_espanso - INFO - Processed: extract_primary_problem
|
104 |
+
2025-01-10 20:20:52,053 - fabric_to_espanso - INFO - Processed: create_hormozi_offer
|
105 |
+
2025-01-10 20:20:52,059 - fabric_to_espanso - INFO - Processed: analyze_prose
|
106 |
+
2025-01-10 20:20:52,064 - fabric_to_espanso - INFO - Processed: analyze_logs
|
107 |
+
2025-01-10 20:20:52,068 - fabric_to_espanso - INFO - Processed: create_recursive_outline
|
108 |
+
2025-01-10 20:20:52,072 - fabric_to_espanso - INFO - Processed: analyze_tech_impact
|
109 |
+
2025-01-10 20:20:52,077 - fabric_to_espanso - INFO - Processed: find_hidden_message
|
110 |
+
2025-01-10 20:20:52,088 - fabric_to_espanso - INFO - Processed: create_npc
|
111 |
+
2025-01-10 20:20:52,104 - fabric_to_espanso - INFO - Processed: provide_guidance
|
112 |
+
2025-01-10 20:20:52,113 - fabric_to_espanso - INFO - Processed: export_data_as_csv
|
113 |
+
2025-01-10 20:20:52,120 - fabric_to_espanso - INFO - Processed: show_fabric_options_markmap
|
114 |
+
2025-01-10 20:20:52,127 - fabric_to_espanso - INFO - Processed: summarize_debate
|
115 |
+
2025-01-10 20:20:52,134 - fabric_to_espanso - INFO - Processed: answer_interview_question
|
116 |
+
2025-01-10 20:20:52,141 - fabric_to_espanso - INFO - Processed: extract_poc
|
117 |
+
2025-01-10 20:20:52,148 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/solveitwithcode_review_repl_driven_process/system.md
|
118 |
+
2025-01-10 20:20:52,155 - fabric_to_espanso - INFO - Processed: solveitwithcode_review_repl_driven_process
|
119 |
+
2025-01-10 20:20:52,163 - fabric_to_espanso - INFO - Processed: rate_content
|
120 |
+
2025-01-10 20:20:52,170 - fabric_to_espanso - INFO - Processed: create_diy
|
121 |
+
2025-01-10 20:20:52,178 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/create_costar_prompt/system.md
|
122 |
+
2025-01-10 20:20:52,186 - fabric_to_espanso - INFO - Processed: create_costar_prompt
|
123 |
+
2025-01-10 20:20:52,193 - fabric_to_espanso - INFO - Processed: create_idea_compass
|
124 |
+
2025-01-10 20:20:52,200 - fabric_to_espanso - INFO - Processed: create_security_update
|
125 |
+
2025-01-10 20:20:52,206 - fabric_to_espanso - INFO - Processed: extract_recommendations
|
126 |
+
2025-01-10 20:20:52,214 - fabric_to_espanso - WARNING - No sections extracted from /home/jelle/.config/fabric/patterns/md_callout/system.md
|
127 |
+
2025-01-10 20:20:52,222 - fabric_to_espanso - INFO - Processed: md_callout
|
128 |
+
2025-01-10 20:20:52,229 - fabric_to_espanso - INFO - Processed: analyze_threat_report
|
129 |
+
2025-01-10 20:20:52,236 - fabric_to_espanso - INFO - Processed: dialog_with_socrates
|
130 |
+
2025-01-10 20:20:52,245 - fabric_to_espanso - INFO - Processed: summarize_newsletter
|
131 |
+
2025-01-10 20:20:52,251 - fabric_to_espanso - INFO - Processed: create_mermaid_visualization
|
132 |
+
2025-01-10 20:20:52,258 - fabric_to_espanso - INFO - Processed: analyze_comments
|
133 |
+
2025-01-10 20:20:52,265 - fabric_to_espanso - INFO - Processed: summarize
|
134 |
+
2025-01-10 20:20:52,271 - fabric_to_espanso - INFO - Processed: compare_and_contrast
|
135 |
+
2025-01-10 20:20:52,278 - fabric_to_espanso - INFO - Successfully processed 199 files in fabric patterns folder
|
136 |
+
2025-01-10 20:20:52,323 - fabric_to_espanso - INFO - Changes detected: 0 new, 0 modified, 0 deleted
|
src/search_qdrant/logs/fabric_to_espanso.log.4
ADDED
The diff for this file is too large to render.
See raw diff
|
|
src/search_qdrant/run_query.sh
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
|
3 |
+
# Add the project root to PYTHONPATH
|
4 |
+
export PYTHONPATH="/home/jelle/Tools/pythagora-core/workspace/fabric-to-espanso:$PYTHONPATH"
|
5 |
+
|
6 |
+
# Run the query script with all arguments passed to this script
|
7 |
+
python src/search_qdrant/database_query.py "$@"
|
src/search_qdrant/run_streamlit.bup2
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
|
3 |
+
# Add the project root to PYTHONPATH
|
4 |
+
export PYTHONPATH="/home/jelle/Tools/pythagora-core/workspace/fabric-to-espanso:$PYTHONPATH"
|
5 |
+
|
6 |
+
# Run the streamlit app
|
7 |
+
/home/jelle/Tools/pythagora-core/workspace/fabric-to-espanso/.venv/bin/streamlit run ~/Tools/pythagora-core/workspace/fabric-to-espanso/src/search_qdrant/streamlit_app.py > nohup.out 2>&1 &
|
8 |
+
PID=$!
|
9 |
+
|
10 |
+
until grep -q "You can now view your Streamlit app" nohup.out
|
11 |
+
do
|
12 |
+
if ! kill -0 $PID 2>/dev/null; then
|
13 |
+
echo "Streamlit failed to start"
|
14 |
+
exit 1
|
15 |
+
fi
|
16 |
+
sleep 1
|
17 |
+
done
|
18 |
+
|
19 |
+
cat nohup.out | grep -A 3 "You can now view your Streamlit app"
|
20 |
+
|
21 |
+
sleep 3
|
22 |
+
|
23 |
+
exit
|
src/search_qdrant/run_streamlit.sh
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
|
3 |
+
# Add the project root to PYTHONPATH
|
4 |
+
export PYTHONPATH="/home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso:$PYTHONPATH"
|
5 |
+
|
6 |
+
# Create a log directory if it doesn't exist
|
7 |
+
LOG_DIR="/home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso/logs"
|
8 |
+
mkdir -p "$LOG_DIR"
|
9 |
+
LOG_FILE="$LOG_DIR/streamlit.log"
|
10 |
+
|
11 |
+
# Clean up any existing nohup.out
|
12 |
+
if [ -f nohup.out ]; then
|
13 |
+
cat /dev/null > nohup.out
|
14 |
+
fi
|
15 |
+
|
16 |
+
# Check if streamlit is already running on port 8501
|
17 |
+
if ss -tuln | grep -q ":8501 "; then
|
18 |
+
echo "Port 8501 is already in use. No need to start the app again."
|
19 |
+
exit 0
|
20 |
+
fi
|
21 |
+
|
22 |
+
|
23 |
+
# Run the streamlit app
|
24 |
+
echo "Starting Streamlit app..."
|
25 |
+
nohup /home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso/.venv/bin/streamlit run ~/Tools/pythagora-core/workspace/fabric_to_espanso/src/search_qdrant/streamlit_app.py >> "LOG_FILE" 2>&1 &
|
26 |
+
|
27 |
+
echo "Streamlit process started with PID: $!"
|
28 |
+
|
29 |
+
# Wait a moment and check if the process is still running
|
30 |
+
sleep 2
|
31 |
+
if ps -p $! > /dev/null; then
|
32 |
+
echo "Streamlit successfully started"
|
33 |
+
else
|
34 |
+
echo "Failed to start Streamlit. Check $LOG_FILE for details"
|
35 |
+
exit 1
|
36 |
+
fi
|
37 |
+
# Wait for Streamlit to start and capture its initial output
|
38 |
+
# max_attempts=5
|
39 |
+
# attempt=0
|
40 |
+
# while [ $attempt -lt $max_attempts ]; do
|
41 |
+
# if grep -q "You can now view your Streamlit app" streamlit.log; then
|
42 |
+
# cat streamlit.log | grep -A 3 "You can now view your Streamlit app"
|
43 |
+
# exit 0
|
44 |
+
# fi
|
45 |
+
# sleep 1
|
46 |
+
# ((attempt++))
|
47 |
+
# done
|
48 |
+
|
49 |
+
# echo "Failed to start Streamlit server"
|
src/search_qdrant/run_streamlit_query_only_terminal_visible.sh
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
|
3 |
+
# Add the project root to PYTHONPATH
|
4 |
+
export PYTHONPATH="/home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso:$PYTHONPATH"
|
5 |
+
|
6 |
+
# Create a log directory if it doesn't exist
|
7 |
+
LOG_DIR="/home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso/logs"
|
8 |
+
mkdir -p "$LOG_DIR"
|
9 |
+
LOG_FILE="$LOG_DIR/streamlit.log"
|
10 |
+
|
11 |
+
# Run the streamlit app
|
12 |
+
echo "Starting Streamlit app..."
|
13 |
+
/home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso/.venv/bin/streamlit run ~/Tools/pythagora-core/workspace/fabric_to_espanso/src/search_qdrant/streamlit_app_query_only.py
|
src/search_qdrant/run_streamlit_terminal_visible.sh
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
|
3 |
+
# Add the project root to PYTHONPATH
|
4 |
+
export PYTHONPATH="/home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso:$PYTHONPATH"
|
5 |
+
|
6 |
+
# Create a log directory if it doesn't exist
|
7 |
+
LOG_DIR="/home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso/logs"
|
8 |
+
mkdir -p "$LOG_DIR"
|
9 |
+
LOG_FILE="$LOG_DIR/streamlit.log"
|
10 |
+
|
11 |
+
# Run the streamlit app
|
12 |
+
echo "Starting Streamlit app..."
|
13 |
+
/home/jelle/Tools/pythagora-core/workspace/fabric_to_espanso/.venv/bin/streamlit run ~/Tools/pythagora-core/workspace/fabric_to_espanso/src/search_qdrant/streamlit_app.py
|
src/search_qdrant/streamlit_app.py
ADDED
@@ -0,0 +1,257 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import pyperclip
|
3 |
+
from pathlib import Path
|
4 |
+
from src.fabrics_processor.database import initialize_qdrant_database
|
5 |
+
from src.fabrics_processor.database_updater import update_qdrant_database
|
6 |
+
from src.fabrics_processor.file_change_detector import detect_file_changes
|
7 |
+
from src.search_qdrant.database_query import query_qdrant_database
|
8 |
+
from src.fabrics_processor.obsidian2fabric import sync_folders
|
9 |
+
from src.fabrics_processor.logger import setup_logger
|
10 |
+
import logging
|
11 |
+
import atexit
|
12 |
+
from src.fabrics_processor.config import config
|
13 |
+
|
14 |
+
# Configure logging
|
15 |
+
logger = setup_logger()
|
16 |
+
|
17 |
+
def init_session_state():
|
18 |
+
"""Initialize session state variables."""
|
19 |
+
if 'client' not in st.session_state:
|
20 |
+
client = initialize_qdrant_database(api_key=st.secrets["api_key"])
|
21 |
+
st.session_state.client = client
|
22 |
+
# Register cleanup function
|
23 |
+
atexit.register(lambda: client.close() if hasattr(client, '_transport') else None)
|
24 |
+
if 'selected_prompts' not in st.session_state:
|
25 |
+
st.session_state.selected_prompts = []
|
26 |
+
if 'comparing' not in st.session_state:
|
27 |
+
st.session_state.comparing = False
|
28 |
+
if 'comparison_selected' not in st.session_state:
|
29 |
+
st.session_state.comparison_selected = None
|
30 |
+
|
31 |
+
def show_comparison_view(prompts):
|
32 |
+
"""Show a full-width comparison view of the selected prompts."""
|
33 |
+
st.write("## Compare Selected Prompts")
|
34 |
+
|
35 |
+
# Add the back button at the top
|
36 |
+
if st.button("Back to search"):
|
37 |
+
st.session_state.comparing = False
|
38 |
+
st.rerun()
|
39 |
+
|
40 |
+
# Create columns for each prompt
|
41 |
+
cols = st.columns(len(prompts))
|
42 |
+
|
43 |
+
# Track which prompt is selected for copying
|
44 |
+
selected_idx = None
|
45 |
+
|
46 |
+
for idx, (col, prompt) in enumerate(zip(cols, prompts)):
|
47 |
+
with col:
|
48 |
+
st.markdown(f"### {prompt.metadata['filename']}")
|
49 |
+
|
50 |
+
# Create two columns for trigger and button
|
51 |
+
trigger_col, button_col = st.columns([0.7, 0.3])
|
52 |
+
|
53 |
+
with trigger_col:
|
54 |
+
# Add trigger field
|
55 |
+
current_trigger = prompt.metadata.get('trigger', '')
|
56 |
+
new_trigger = st.text_input("Trigger",
|
57 |
+
value=current_trigger,
|
58 |
+
key=f"trigger_{idx}")
|
59 |
+
|
60 |
+
# Update trigger if changed
|
61 |
+
if new_trigger != current_trigger:
|
62 |
+
try:
|
63 |
+
st.session_state.client.set_payload(
|
64 |
+
collection_name=config.embedding.collection_name,
|
65 |
+
payload={"trigger": new_trigger},
|
66 |
+
points=[prompt.id]
|
67 |
+
)
|
68 |
+
st.success(f"Updated trigger to: {new_trigger}")
|
69 |
+
except Exception as e:
|
70 |
+
st.error(f"Failed to update trigger: {str(e)}")
|
71 |
+
|
72 |
+
with button_col:
|
73 |
+
# Align button with text input using empty space
|
74 |
+
st.write("") # This creates some vertical space
|
75 |
+
if st.button(f"Use this prompt", key=f"compare_use_{idx}"):
|
76 |
+
selected_idx = idx
|
77 |
+
|
78 |
+
# Display content as markdown
|
79 |
+
st.markdown("### Content")
|
80 |
+
st.markdown(prompt.metadata["content"])
|
81 |
+
|
82 |
+
# Handle selection
|
83 |
+
if selected_idx is not None:
|
84 |
+
pyperclip.copy(prompts[selected_idx].metadata['content'])
|
85 |
+
st.success(f"Copied {prompts[selected_idx].metadata['filename']} to clipboard!")
|
86 |
+
# Clear comparison view
|
87 |
+
st.session_state.comparing = False
|
88 |
+
st.rerun()
|
89 |
+
|
90 |
+
def search_interface():
|
91 |
+
"""Show the search interface."""
|
92 |
+
if st.session_state.comparing:
|
93 |
+
show_comparison_view(st.session_state.selected_prompts)
|
94 |
+
return
|
95 |
+
|
96 |
+
st.subheader("Search for prompts")
|
97 |
+
|
98 |
+
query = st.text_area("What are you trying to accomplish? I will then search for good prompts to give you a good start.")
|
99 |
+
|
100 |
+
if query:
|
101 |
+
try:
|
102 |
+
results = query_qdrant_database(
|
103 |
+
query=query,
|
104 |
+
client=st.session_state.client,
|
105 |
+
num_results=5,
|
106 |
+
collection_name=config.embedding.collection_name
|
107 |
+
)
|
108 |
+
|
109 |
+
if results:
|
110 |
+
st.write("Which prompts would you like to investigate? Max 3.")
|
111 |
+
|
112 |
+
# Create checkboxes for selection
|
113 |
+
selected = []
|
114 |
+
for r in results:
|
115 |
+
if st.checkbox(f"{r.metadata['filename']}", key=f"select_{r.id}"):
|
116 |
+
selected.append(r)
|
117 |
+
|
118 |
+
st.session_state.selected_prompts = selected
|
119 |
+
|
120 |
+
if selected:
|
121 |
+
col1, col2 = st.columns(2)
|
122 |
+
with col1:
|
123 |
+
if st.button("Use: copy to clipboard"):
|
124 |
+
if len(selected) == 1:
|
125 |
+
pyperclip.copy(selected[0].metadata['content'])
|
126 |
+
st.success("Copied to clipboard!")
|
127 |
+
|
128 |
+
with col2:
|
129 |
+
if len(selected) > 1 and st.button("Compare"):
|
130 |
+
st.session_state.comparing = True
|
131 |
+
st.rerun()
|
132 |
+
|
133 |
+
except Exception as e:
|
134 |
+
logger.error(f"Error in search_interface: {e}", exc_info=True)
|
135 |
+
st.error(f"Error searching database: {e}")
|
136 |
+
|
137 |
+
def update_database():
|
138 |
+
"""Update the markdown folder with prompt files from Obsidian.
|
139 |
+
Then update the Qdrant database.
|
140 |
+
Finally based on the Qdrant database create a new espanso YAML file and
|
141 |
+
the Obsidian Textgenerator markdown files."""
|
142 |
+
try:
|
143 |
+
with st.spinner("Processing markdown files..."):
|
144 |
+
# First check if there are any changes in the prompt files in Obsidian.
|
145 |
+
# If so, add them to the markdown folder before updating the database.
|
146 |
+
sync_folders(source_dir=Path(config.obsidian_input_folder), target_dir=Path(config.fabric_patterns_folder))
|
147 |
+
|
148 |
+
# Get current collection info
|
149 |
+
collection_info = st.session_state.client.get_collection(config.embedding.collection_name)
|
150 |
+
initial_points = collection_info.points_count
|
151 |
+
|
152 |
+
# Detect file changes
|
153 |
+
new_files, modified_files, deleted_files = detect_file_changes(
|
154 |
+
client=st.session_state.client,
|
155 |
+
fabric_patterns_folder=config.fabric_patterns_folder
|
156 |
+
)
|
157 |
+
|
158 |
+
# Update the database if chenges are detected
|
159 |
+
if any([new_files, modified_files, deleted_files]):
|
160 |
+
update_qdrant_database(
|
161 |
+
client=st.session_state.client,
|
162 |
+
collection_name=config.embedding.collection_name,
|
163 |
+
new_files=new_files,
|
164 |
+
modified_files=modified_files,
|
165 |
+
deleted_files=deleted_files
|
166 |
+
)
|
167 |
+
|
168 |
+
# Get updated collection info
|
169 |
+
collection_info = st.session_state.client.get_collection(config.embedding.collection_name)
|
170 |
+
final_points = collection_info.points_count
|
171 |
+
|
172 |
+
# Show summary
|
173 |
+
st.success(f"""
|
174 |
+
Database update completed successfully!
|
175 |
+
|
176 |
+
Changes detected:
|
177 |
+
- {len(new_files)} new files
|
178 |
+
- {len(modified_files)} modified files
|
179 |
+
- {len(deleted_files)} deleted files
|
180 |
+
|
181 |
+
Database entries:
|
182 |
+
- Initial: {initial_points}
|
183 |
+
- Final: {final_points}
|
184 |
+
""")
|
185 |
+
|
186 |
+
except Exception as e:
|
187 |
+
logger.error(f"Error updating database: {e}", exc_info=True)
|
188 |
+
st.error(f"Error updating database: {e}")
|
189 |
+
|
190 |
+
def display_trigger_table():
|
191 |
+
"""Display the trigger table in the sidebar."""
|
192 |
+
with st.sidebar:
|
193 |
+
# Add some space to push the table to the bottom
|
194 |
+
st.markdown("<br>" * 10, unsafe_allow_html=True)
|
195 |
+
|
196 |
+
# Create the table
|
197 |
+
st.markdown("""
|
198 |
+
| trigger | description |
|
199 |
+
|---------|-------------|
|
200 |
+
| ;;c | code |
|
201 |
+
| ;;s | summarize and extract |
|
202 |
+
| ;;t | think |
|
203 |
+
""")
|
204 |
+
|
205 |
+
def main():
|
206 |
+
st.set_page_config(
|
207 |
+
page_title="Fabric to Espanso Prompt Manager",
|
208 |
+
layout="wide")
|
209 |
+
init_session_state()
|
210 |
+
|
211 |
+
# Sidebar
|
212 |
+
with st.sidebar:
|
213 |
+
# Add logo to sidebar
|
214 |
+
image_path = Path(__file__).parent.parent.parent / "data" / "Fab2Esp_transparent.png"
|
215 |
+
st.image(str(image_path), width=200, use_container_width=False)
|
216 |
+
|
217 |
+
st.title("Prompt Manager")
|
218 |
+
page = st.radio("Select Option:", ["Search for prompts", "Update database and prompt files"])
|
219 |
+
|
220 |
+
if st.button("Quit"):
|
221 |
+
if hasattr(st.session_state.client, '_transport'):
|
222 |
+
st.session_state.client.close()
|
223 |
+
st.success("Database connection closed.")
|
224 |
+
st.stop()
|
225 |
+
|
226 |
+
# Main content
|
227 |
+
if page == "Search for prompts":
|
228 |
+
search_interface()
|
229 |
+
else:
|
230 |
+
st.subheader("Update Database")
|
231 |
+
if st.button("Start Update"):
|
232 |
+
update_database()
|
233 |
+
|
234 |
+
# Add the trigger table at the end
|
235 |
+
display_trigger_table()
|
236 |
+
|
237 |
+
# Add credits at the bottom left
|
238 |
+
st.markdown("""
|
239 |
+
<style>
|
240 |
+
.credits {
|
241 |
+
position: fixed;
|
242 |
+
left: 1rem;
|
243 |
+
bottom: 1rem;
|
244 |
+
font-size: 0.8rem;
|
245 |
+
color: #666;
|
246 |
+
max-width: 600px;
|
247 |
+
}
|
248 |
+
</style>
|
249 |
+
<div class="credits">
|
250 |
+
This tool searches the great list of prompts available at <a href="https://github.com/danielmiessler/fabric">https://github.com/danielmiessler/fabric</a>.
|
251 |
+
A great commandline utilty build by Daniel Miessler to make the use of LLM more frictionless.<br>
|
252 |
+
All credits to him and his fellow fabric builders.
|
253 |
+
</div>
|
254 |
+
""", unsafe_allow_html=True)
|
255 |
+
|
256 |
+
if __name__ == "__main__":
|
257 |
+
main()
|
streamlit_app_query_only.py
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import pyperclip
|
3 |
+
from src.fabrics_processor.database import initialize_qdrant_database
|
4 |
+
from src.search_qdrant.database_query import query_qdrant_database
|
5 |
+
from src.fabrics_processor.logger import setup_logger
|
6 |
+
import logging
|
7 |
+
import atexit
|
8 |
+
from src.fabrics_processor.config import config
|
9 |
+
import time
|
10 |
+
|
11 |
+
# Configure logging
|
12 |
+
logger = setup_logger()
|
13 |
+
|
14 |
+
def init_session_state():
|
15 |
+
"""Initialize session state variables."""
|
16 |
+
if 'client' not in st.session_state:
|
17 |
+
client = initialize_qdrant_database(api_key=st.secrets["api_key"])
|
18 |
+
st.session_state.client = client
|
19 |
+
# Register cleanup function
|
20 |
+
atexit.register(lambda: client.close() if hasattr(client, '_transport') else None)
|
21 |
+
if 'selected_prompts' not in st.session_state:
|
22 |
+
st.session_state.selected_prompts = []
|
23 |
+
if 'comparing' not in st.session_state:
|
24 |
+
st.session_state.comparing = False
|
25 |
+
if 'comparison_selected' not in st.session_state:
|
26 |
+
st.session_state.comparison_selected = None
|
27 |
+
if 'status_key' not in st.session_state:
|
28 |
+
st.session_state.status_key = 0
|
29 |
+
|
30 |
+
def show_comparison_view(prompts):
|
31 |
+
"""Show a full-width comparison view of the selected prompts."""
|
32 |
+
st.write("## Compare Selected Prompts")
|
33 |
+
|
34 |
+
# Add the back button at the top
|
35 |
+
if st.button("Back to search"):
|
36 |
+
st.session_state.comparing = False
|
37 |
+
st.rerun()
|
38 |
+
|
39 |
+
# Create columns for each prompt
|
40 |
+
cols = st.columns(len(prompts))
|
41 |
+
|
42 |
+
# Track which prompt is selected for copying
|
43 |
+
selected_idx = None
|
44 |
+
|
45 |
+
for idx, (col, prompt) in enumerate(zip(cols, prompts)):
|
46 |
+
with col:
|
47 |
+
st.markdown(f"### {prompt.metadata['filename']}")
|
48 |
+
|
49 |
+
# Display content as markdown
|
50 |
+
st.markdown("### Content")
|
51 |
+
st.code(prompt.metadata["content"], language="markdown", wrap_lines=True)
|
52 |
+
|
53 |
+
# Add copy button for each prompt
|
54 |
+
if st.button(f"Use this prompt", key=f"compare_use_{idx}"):
|
55 |
+
st.code(prompt.metadata["content"], language="markdown", wrap_lines=True)
|
56 |
+
selected_idx = idx
|
57 |
+
|
58 |
+
# Handle selection
|
59 |
+
if selected_idx is not None:
|
60 |
+
st.session_state.comparing = False
|
61 |
+
st.rerun()
|
62 |
+
|
63 |
+
def search_interface():
|
64 |
+
"""Show the search interface."""
|
65 |
+
if st.session_state.comparing:
|
66 |
+
show_comparison_view(st.session_state.selected_prompts)
|
67 |
+
return
|
68 |
+
|
69 |
+
query = st.text_area("What are you trying to accomplish? I will then search for good prompts to give you a good start.")
|
70 |
+
|
71 |
+
if query:
|
72 |
+
try:
|
73 |
+
results = query_qdrant_database(
|
74 |
+
query=query,
|
75 |
+
client=st.session_state.client,
|
76 |
+
num_results=5,
|
77 |
+
collection_name=config.embedding.collection_name
|
78 |
+
)
|
79 |
+
|
80 |
+
if results:
|
81 |
+
st.write("Which prompts would you like to investigate? Max 3.")
|
82 |
+
|
83 |
+
# Create checkboxes for selection
|
84 |
+
selected = []
|
85 |
+
for r in results:
|
86 |
+
if st.checkbox(f"{r.metadata['filename']}", key=f"select_{r.id}"):
|
87 |
+
selected.append(r)
|
88 |
+
|
89 |
+
st.session_state.selected_prompts = selected
|
90 |
+
|
91 |
+
if selected:
|
92 |
+
col1, col2 = st.columns(2)
|
93 |
+
with col1:
|
94 |
+
if len(selected) == 1:
|
95 |
+
st.code(selected[0].metadata["content"], language="markdown", wrap_lines=True)
|
96 |
+
|
97 |
+
with col2:
|
98 |
+
if len(selected) > 1 and st.button("Compare"):
|
99 |
+
st.session_state.comparing = True
|
100 |
+
st.rerun()
|
101 |
+
except Exception as e:
|
102 |
+
logger.error(f"Error in search_interface: {e}", exc_info=True)
|
103 |
+
st.error(f"Error searching database: {e}")
|
104 |
+
|
105 |
+
def main():
|
106 |
+
"""Main function to run the Streamlit app."""
|
107 |
+
st.set_page_config(
|
108 |
+
page_title="Find fabric prompts",
|
109 |
+
page_icon="🔍",
|
110 |
+
layout="wide"
|
111 |
+
)
|
112 |
+
|
113 |
+
st.title("Find fabric prompts")
|
114 |
+
|
115 |
+
try:
|
116 |
+
init_session_state()
|
117 |
+
search_interface()
|
118 |
+
|
119 |
+
# Add credits at the bottom left
|
120 |
+
st.markdown("""
|
121 |
+
<style>
|
122 |
+
.credits {
|
123 |
+
position: fixed;
|
124 |
+
left: 1rem;
|
125 |
+
bottom: 1rem;
|
126 |
+
font-size: 0.8rem;
|
127 |
+
color: #666;
|
128 |
+
max-width: 600px;
|
129 |
+
}
|
130 |
+
</style>
|
131 |
+
<div class="credits">
|
132 |
+
This tool searches the great list of prompts available at <a href="https://github.com/danielmiessler/fabric">https://github.com/danielmiessler/fabric</a>.
|
133 |
+
A great commandline utilty build by Daniel Miessler to make the use of LLM more frictionless.<br>
|
134 |
+
All credits to him and his fellow fabric builders.
|
135 |
+
</div>
|
136 |
+
""", unsafe_allow_html=True)
|
137 |
+
|
138 |
+
except Exception as e:
|
139 |
+
logger.error(f"Error in main: {str(e)}")
|
140 |
+
st.error(f"An error occurred: {str(e)}")
|
141 |
+
|
142 |
+
if __name__ == "__main__":
|
143 |
+
main()
|
tests/__init__.py
ADDED
File without changes
|