Repository: Fosowl/agenticSeek
Branch: main
Commit: 1036c5fbc1fc
Files: 127
Total size: 1015.4 KB
Directory structure:
gitextract_7bezd6cg/
├── .dockerignore
├── .github/
│ ├── FUNDING.yml
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── Dockerfile.backend
├── LICENSE
├── README.md
├── README_CHS.md
├── README_CHT.md
├── README_ES.md
├── README_FR.md
├── README_JP.md
├── README_PTBR.md
├── README_TR.md
├── api.py
├── cli.py
├── crx/
│ └── nopecha.crx
├── docker-compose.yml
├── docs/
│ ├── CODE_OF_CONDUCT.md
│ └── CONTRIBUTING.md
├── frontend/
│ ├── .gitignore
│ ├── Dockerfile.frontend
│ ├── README.md
│ └── agentic-seek-front/
│ ├── package.json
│ ├── public/
│ │ ├── index.html
│ │ ├── manifest.json
│ │ └── robots.txt
│ └── src/
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── colors.js
│ ├── components/
│ │ ├── ResizableLayout.css
│ │ ├── ResizableLayout.js
│ │ └── ThemeToggle.js
│ ├── contexts/
│ │ └── ThemeContext.js
│ ├── index.css
│ ├── index.js
│ ├── reportWebVitals.js
│ ├── setupTests.js
│ └── styles/
│ └── globals.css
├── install.bat
├── install.sh
├── llm_router/
│ ├── config.json
│ ├── dl_safetensors.sh
│ └── examples.json
├── llm_server/
│ ├── Dockerfile
│ ├── app.py
│ ├── install.sh
│ ├── requirements.txt
│ └── sources/
│ ├── cache.py
│ ├── decorator.py
│ ├── generator.py
│ ├── llamacpp_handler.py
│ └── ollama_handler.py
├── prompts/
│ ├── base/
│ │ ├── browser_agent.txt
│ │ ├── casual_agent.txt
│ │ ├── coder_agent.txt
│ │ ├── file_agent.txt
│ │ ├── mcp_agent.txt
│ │ └── planner_agent.txt
│ └── jarvis/
│ ├── browser_agent.txt
│ ├── casual_agent.txt
│ ├── coder_agent.txt
│ ├── file_agent.txt
│ ├── mcp_agent.txt
│ └── planner_agent.txt
├── pyproject.toml
├── requirements.txt
├── scripts/
│ ├── linux_install.sh
│ ├── macos_install.sh
│ └── windows_install.bat
├── searxng/
│ ├── docker-compose.yml
│ ├── limiter.toml
│ ├── settings.yml
│ ├── setup_searxng.sh
│ └── uwsgi.ini
├── setup.py
├── sources/
│ ├── agents/
│ │ ├── __init__.py
│ │ ├── agent.py
│ │ ├── browser_agent.py
│ │ ├── casual_agent.py
│ │ ├── code_agent.py
│ │ ├── file_agent.py
│ │ ├── mcp_agent.py
│ │ └── planner_agent.py
│ ├── browser.py
│ ├── interaction.py
│ ├── language.py
│ ├── llm_provider.py
│ ├── logger.py
│ ├── memory.py
│ ├── router.py
│ ├── schemas.py
│ ├── speech_to_text.py
│ ├── text_to_speech.py
│ ├── tools/
│ │ ├── BashInterpreter.py
│ │ ├── C_Interpreter.py
│ │ ├── GoInterpreter.py
│ │ ├── JavaInterpreter.py
│ │ ├── PyInterpreter.py
│ │ ├── __init__.py
│ │ ├── fileFinder.py
│ │ ├── flightSearch.py
│ │ ├── mcpFinder.py
│ │ ├── safety.py
│ │ ├── searxSearch.py
│ │ ├── tools.py
│ │ └── webSearch.py
│ ├── utility.py
│ └── web_scripts/
│ ├── find_inputs.js
│ ├── inject_safety_script.js
│ └── spoofing.js
├── start_services.cmd
├── start_services.sh
└── tests/
├── test_browser_agent_parsing.py
├── test_chromedriver_update.py
├── test_logger.py
├── test_memory.py
├── test_minimax_provider.py
├── test_planner_agent_parsing.py
├── test_provider.py
├── test_searx_search.py
├── test_tools_parsing.py
└── test_utility.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
# Python cache files
__pycache__/
*.py[cod]
# Virtual environments
agentic_seek_env/
.agentic_seek_env/
.env
# Git metadata
.git/
# macOS Finder files
.DS_Store
# Log files
*.log
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: [Fosowl ]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**LLM Model used**
The model you used, for example deepseek-r1:14b
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .gitignore
================================================
*.wav
*.DS_Store
*.log
*.tmp
*.safetensors
*.egg-info
cookies.json
test_agent.py
searxng/uwsgi.ini.new
searxng/settings.yml.new
config.ini
.voices/
experimental/
chrome_bundle/
.logs/
.screenshots/*.png
.screenshots/*.jpg
conversations/
agentic_env/*
agentic_seek_env/*
.env
*/.env
dsk/
chrome136/
### react ###
.DS_*
*.log
logs
**/*.backup.*
**/*.back.*
node_modules
bower_components
*.sublime*
psd
thumb
sketch
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# PyPI configuration file
.pypirc
================================================
FILE: .pre-commit-config.yaml
================================================
repos:
- repo: local
hooks:
- id: trufflehog
name: TruffleHog
description: Detect secrets in your data.
entry: bash -c 'trufflehog git file://. --since-commit HEAD --results=verified,unknown --no-update'
language: system
stages: ["commit", "push"]
================================================
FILE: .python-version
================================================
3.10
================================================
FILE: Dockerfile.backend
================================================
FROM --platform=linux/amd64 python:3.11.12
ENV DEBIAN_FRONTEND=noninteractive
# Install essential packages and Chrome dependencies
RUN apt-get update -y && apt-get install -y \
wget \
gnupg2 \
ca-certificates \
unzip \
xvfb \
libxss1 \
#libappindicator1 \
fonts-liberation \
libnss3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
xdg-utils \
dbus \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update -y && \
apt-get install -y \
gcc \
g++ \
gfortran \
libportaudio2 \
portaudio19-dev \
ffmpeg \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
gnupg2 \
wget \
unzip \
python3 \
python3-pip \
libasound2 \
libatk-bridge2.0-0 \
libgtk-4-1 \
libnss3 \
xdg-utils \
wget \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update -y && \
apt-get install -y \
alsa-utils \
&& rm -rf /var/lib/apt/lists/*
ENV CHROME_TESTING_VERSION=134.0.6998.88
ENV DISPLAY=:99
WORKDIR /app
RUN set -eux; \
wget -qO /tmp/chrome.zip \
"https://storage.googleapis.com/chrome-for-testing-public/${CHROME_TESTING_VERSION}/linux64/chrome-linux64.zip"; \
unzip -q /tmp/chrome.zip -d /opt; \
rm /tmp/chrome.zip; \
ln -s /opt/chrome-linux64/chrome /usr/local/bin/google-chrome; \
ln -s /opt/chrome-linux64/chrome /usr/local/bin/chrome; \
mkdir -p /opt/chrome; \
ln -s /opt/chrome-linux64/chrome /opt/chrome/chrome; \
google-chrome --version
RUN set -eux; \
wget -qO /tmp/chromedriver.zip \
"https://storage.googleapis.com/chrome-for-testing-public/${CHROME_TESTING_VERSION}/linux64/chromedriver-linux64.zip"; \
unzip -q /tmp/chromedriver.zip -d /tmp; \
mv /tmp/chromedriver-linux64/chromedriver /usr/local/bin; \
rm /tmp/chromedriver.zip; \
chmod +x /usr/local/bin/chromedriver; \
chromedriver --version
RUN chmod +x /opt/chrome/chrome
RUN pip3 install --upgrade pip setuptools wheel
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN mkdir -p /opt/workspace
RUN mkdir -p /tmp && chmod 1777 /tmp
# Copy application code
COPY api.py .
COPY sources/ ./sources/
COPY prompts/ ./prompts/
COPY crx/ crx/
COPY llm_router/ llm_router/
COPY config.ini .
EXPOSE 8000
# Run the application
CMD ["python3", "api.py"]
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: README.md
================================================
# AgenticSeek: Private, Local Manus Alternative.
English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Français](./README_FR.md) | [日本語](./README_JP.md) | [Português (Brasil)](./README_PTBR.md) | [Español](./README_ES.md) | [Türkçe](./README_TR.md)
*A **100% local alternative to Manus AI**, this voice-enabled AI assistant autonomously browses the web, writes code, and plans tasks while keeping all data on your device. Tailored for local reasoning models, it runs entirely on your hardware, ensuring complete privacy and zero cloud dependency.*
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460) [](https://github.com/Fosowl/agenticSeek/stargazers)
### Why AgenticSeek ?
* 🔒 Fully Local & Private - Everything runs on your machine — no cloud, no data sharing. Your files, conversations, and searches stay private.
* 🌐 Smart Web Browsing - AgenticSeek can browse the internet by itself — search, read, extract info, fill web form — all hands-free.
* 💻 Autonomous Coding Assistant - Need code? It can write, debug, and run programs in Python, C, Go, Java, and more — all without supervision.
* 🧠 Smart Agent Selection - You ask, it figures out the best agent for the job automatically. Like having a team of experts ready to help.
* 📋 Plans & Executes Complex Tasks - From trip planning to complex projects — it can split big tasks into steps and get things done using multiple AI agents.
* 🎙️ Voice-Enabled - Clean, fast, futuristic voice and speech to text allowing you to talk to it like it's your personal AI from a sci-fi movie. (In progress)
### **Demo**
> *Can you search for the agenticSeek project, learn what skills are required, then open the CV_candidates.zip and then tell me which match best the project*
https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316
Disclaimer: This demo, including all the files that appear (e.g: CV_candidates.zip), are entirely fictional. We are not a corporation, we seek open-source contributors not candidates.
> 🛠⚠️️ **Active Work in Progress**
> 🙏 This project started as a side-project and has zero roadmap and zero funding. It's grown way beyond what I expected by ending in GitHub Trending. Contributions, feedback, and patience are deeply appreciated.
## Prerequisites
Before you begin, ensure you have the following software installed:
* **Git:** For cloning the repository. [Download Git](https://git-scm.com/downloads)
* **Python 3.10.x:** We strongly recommend using Python version 3.10.x. Using other versions might lead to dependency errors. [Download Python 3.10](https://www.python.org/downloads/release/python-3100/) (pick a 3.10.x version).
* **Docker Engine & Docker Compose:** For running bundled services like SearxNG.
* Install Docker Desktop (which includes Docker Compose V2): [Windows](https://docs.docker.com/desktop/install/windows-install/) | [Mac](https://docs.docker.com/desktop/install/mac-install/) | [Linux](https://docs.docker.com/desktop/install/linux-install/)
* Alternatively, install Docker Engine and Docker Compose separately on Linux: [Docker Engine](https://docs.docker.com/engine/install/) | [Docker Compose](https://docs.docker.com/compose/install/) (ensure you install Compose V2, e.g., `sudo apt-get install docker-compose-plugin`).
### 1. **Clone the repository and setup**
```sh
git clone https://github.com/Fosowl/agenticSeek.git
cd agenticSeek
mv .env.example .env
```
### 2. Change the .env file content
```sh
SEARXNG_BASE_URL="http://searxng:8080" # http://127.0.0.1:8080 if running on host
REDIS_BASE_URL="redis://redis:6379/0"
WORK_DIR="/Users/mlg/Documents/workspace_for_ai"
OLLAMA_PORT="11434"
LM_STUDIO_PORT="1234"
CUSTOM_ADDITIONAL_LLM_PORT="11435"
OPENAI_API_KEY='optional'
DEEPSEEK_API_KEY='optional'
OPENROUTER_API_KEY='optional'
TOGETHER_API_KEY='optional'
GOOGLE_API_KEY='optional'
ANTHROPIC_API_KEY='optional'
```
Update the `.env` file with your own values as needed:
- **SEARXNG_BASE_URL**: Leave unchanged unless running on host with CLI mode.
- **REDIS_BASE_URL**: Leave unchanged
- **WORK_DIR**: Path to your working directory on your local machine. AgenticSeek will be able to read and interact with these files.
- **OLLAMA_PORT**: Port number for the Ollama service.
- **LM_STUDIO_PORT**: Port number for the LM Studio service.
- **CUSTOM_ADDITIONAL_LLM_PORT**: Port for any additional custom LLM service.
**API Key are totally optional for user who choose to run LLM locally. Which is the primary purpose of this project. Leave empty if you have sufficient hardware**
### 3. **Start Docker**
Make sure Docker is installed and running on your system. You can start Docker using the following commands:
- **On Linux/macOS:**
Open a terminal and run:
```sh
sudo systemctl start docker
```
Or launch Docker Desktop from your applications menu if installed.
- **On Windows:**
Start Docker Desktop from the Start menu.
You can verify Docker is running by executing:
```sh
docker info
```
If you see information about your Docker installation, it is running correctly.
See the table of [Local Providers](#list-of-local-providers) below for a summary.
Next step: [Run AgenticSeek locally](#start-services-and-run)
*See the [Troubleshooting](#troubleshooting) section if you are having issues.*
*If your hardware can't run LLMs locally, see [Setup to run with an API](#setup-to-run-with-an-api).*
*For detailed `config.ini` explanations, see [Config Section](#config).*
---
## Setup for running LLM locally on your machine
**Hardware Requirements:**
To run LLMs locally, you'll need sufficient hardware. At a minimum, a GPU capable of running Magistral, Qwen or Deepseek 14B is required. See the FAQ for detailed model/performance recommendations.
**Setup your local provider**
Start your local provider (for example with ollama):
Unless you wish to to run AgenticSeek on host (CLI mode), export or set the provider listen address:
```sh
export OLLAMA_HOST=0.0.0.0:11434
```
Then, start you provider:
```sh
ollama serve
```
See below for a list of local supported provider.
**Update the config.ini**
Change the config.ini file to set the provider_name to a supported provider and provider_model to a LLM supported by your provider. We recommend reasoning model such as *Magistral* or *Deepseek*.
See the **FAQ** at the end of the README for required hardware.
```sh
[MAIN]
is_local = True # Whenever you are running locally or with remote provider.
provider_name = ollama # or lm-studio, openai, etc..
provider_model = deepseek-r1:14b # choose a model that fit your hardware
provider_server_address = 127.0.0.1:11434
agent_name = Jarvis # name of your AI
recover_last_session = True # whenever to recover the previous session
save_session = True # whenever to remember the current session
speak = False # text to speech
listen = False # Speech to text, only for CLI, experimental
jarvis_personality = False # Whenever to use a more "Jarvis" like personality (experimental)
languages = en zh # The list of languages, Text to speech will default to the first language on the list
[BROWSER]
headless_browser = True # leave unchanged unless using CLI on host.
stealth_mode = True # Use undetected selenium to reduce browser detection
```
**Warning**:
- The `config.ini` file format does not support comments.
Do not copy and paste the example configuration directly, as comments will cause errors. Instead, manually modify the `config.ini` file with your desired settings, excluding any comments.
- Do *NOT* set provider_name to `openai` if using LM-studio for running LLMs. Set it to `lm-studio`.
- Some provider (eg: lm-studio) require you to have `http://` in front of the IP. For example `http://127.0.0.1:1234`
**List of local providers**
| Provider | Local? | Description |
|-----------|--------|-----------------------------------------------------------|
| ollama | Yes | Run LLMs locally with ease using ollama as a LLM provider |
| lm-studio | Yes | Run LLM locally with LM studio (set `provider_name` to `lm-studio`)|
| openai | Yes | Use openai compatible API (eg: llama.cpp server) |
Next step: [Start services and run AgenticSeek](#Start-services-and-Run)
*See the [Troubleshooting](#troubleshooting) section if you are having issues.*
*If your hardware can't run LLMs locally, see [Setup to run with an API](#setup-to-run-with-an-api).*
*For detailed `config.ini` explanations, see [Config Section](#config).*
## Setup to run with an API
This setup uses external, cloud-based LLM providers. You'll need an API key from your chosen service.
**1. Choose an API Provider and Get an API Key:**
Refer to the [List of API Providers](#list-of-api-providers) below. Visit their websites to sign up and obtain an API key.
**2. Set Your API Key as an Environment Variable:**
* **Linux/macOS:**
Open your terminal and use the `export` command. It's best to add this to your shell's profile file (e.g., `~/.bashrc`, `~/.zshrc`) for persistence.
```sh
export PROVIDER_API_KEY="your_api_key_here"
# Replace PROVIDER_API_KEY with the specific variable name, e.g., OPENAI_API_KEY, GOOGLE_API_KEY
```
Example for TogetherAI:
```sh
export TOGETHER_API_KEY="xxxxxxxxxxxxxxxxxxxxxx"
```
* **Windows:**
* **Command Prompt (Temporary for current session):**
```cmd
set PROVIDER_API_KEY=your_api_key_here
```
* **PowerShell (Temporary for current session):**
```powershell
$env:PROVIDER_API_KEY="your_api_key_here"
```
* **Permanently:** Search for "environment variables" in the Windows search bar, click "Edit the system environment variables," then click the "Environment Variables..." button. Add a new User variable with the appropriate name (e.g., `OPENAI_API_KEY`) and your key as the value.
*(See FAQ: [How do I set API keys?](#how-do-i-set-api-keys) for more details).*
**3. Update `config.ini`:**
```ini
[MAIN]
is_local = False
provider_name = openai # Or google, deepseek, togetherAI, huggingface
provider_model = gpt-3.5-turbo # Or gemini-1.5-flash, deepseek-chat, mistralai/Mixtral-8x7B-Instruct-v0.1 etc.
provider_server_address = # Typically ignored or can be left blank when is_local = False for most APIs
# ... other settings ...
```
*Warning:* Make sure there are no trailing spaces in the `config.ini` values.
**List of API Providers**
| Provider | `provider_name` | Local? | Description | API Key Link (Examples) |
|--------------|-----------------|--------|---------------------------------------------------|---------------------------------------------|
| OpenAI | `openai` | No | Use ChatGPT models via OpenAI's API. | [platform.openai.com/signup](https://platform.openai.com/signup) |
| Google Gemini| `google` | No | Use Google Gemini models via Google AI Studio. | [aistudio.google.com/keys](https://aistudio.google.com/keys) |
| Deepseek | `deepseek` | No | Use Deepseek models via their API. | [platform.deepseek.com](https://platform.deepseek.com) |
| Hugging Face | `huggingface` | No | Use models from Hugging Face Inference API. | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) |
| TogetherAI | `togetherAI` | No | Use various open-source models via TogetherAI API.| [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys) |
| OpenRouter | `openrouter` | No | Use OpenRouter Models| [https://openrouter.ai/](https://openrouter.ai/) |
| MiniMax | `minimax` | No | Use MiniMax M2.5 series models (e.g., MiniMax-M2.5).| [platform.minimax.io](https://platform.minimax.io/user-center/basic-information) |
*Note:*
* We advise against using `gpt-4o` or other OpenAI models for complex web browsing and task planning as current prompt optimizations are geared towards models like Deepseek.
* Coding/bash tasks might encounter issues with Gemini, as it may not strictly follow formatting prompts optimized for Deepseek.
* The `provider_server_address` in `config.ini` is generally not used when `is_local = False` as the API endpoint is usually hardcoded in the respective provider's library.
Next step: [Start services and run AgenticSeek](#Start-services-and-Run)
*See the **Known issues** section if you are having issues*
*See the **Config** section for detailed config file explanation.*
---
## Start services and Run
By default AgenticSeek is run fully in docker.
**Option 1:** Run in Docker, use web interface:
Start required services. This will start all services from the docker-compose.yml, including:
- searxng
- redis (required by searxng)
- frontend
- backend (if using `full` when using the web interface)
```sh
./start_services.sh full # MacOS
start start_services.cmd full # Window
```
**Warning:** This step will download and load all Docker images, which may take up to 30 minutes. After starting the services, please wait until the backend service is fully running (you should see **backend: "GET /health HTTP/1.1" 200 OK** in the log) before sending any messages. The backend services might take 5 minute to start on first run.
Go to `http://localhost:3000/` and you should see the web interface.
*Troubleshooting service start:* If these scripts fail, ensure Docker Engine is running and Docker Compose (V2, `docker compose`) is correctly installed. Check the output in the terminal for error messages. See [FAQ: Help! I get an error when running AgenticSeek or its scripts.](#faq-troubleshooting)
**Option 2:** CLI mode:
To run with CLI interface you would have to install package on host:
```sh
./install.sh
./install.bat # windows
```
Then you must change the SEARXNG_BASE_URL in `config.ini` to:
```sh
SEARXNG_BASE_URL="http://localhost:8080"
```
Start required services. This will start some services from the docker-compose.yml, including:
- searxng
- redis (required by searxng)
- frontend
```sh
./start_services.sh # MacOS
start start_services.cmd # Window
```
Run: uv run: `uv run python -m ensurepip` to ensure uv has pip enabled.
Use the CLI: `uv run cli.py`
---
## Usage
Make sure the services are up and running with `./start_services.sh full` and go to `localhost:3000` for web interface.
You can also use speech to text by setting `listen = True` in the config. Only for CLI mode.
To exit, simply say/type `goodbye`.
Here are some example usage:
> *Make a snake game in python!*
> *Search the web for top cafes in Rennes, France, and save a list of three with their addresses in rennes_cafes.txt.*
> *Write a Go program to calculate the factorial of a number, save it as factorial.go in your workspace*
> *Search my summer_pictures folder for all JPG files, rename them with today’s date, and save a list of renamed files in photos_list.txt*
> *Search online for popular sci-fi movies from 2024 and pick three to watch tonight. Save the list in movie_night.txt.*
> *Search the web for the latest AI news articles from 2025, select three, and write a Python script to scrape their titles and summaries. Save the script as news_scraper.py and the summaries in ai_news.txt in /home/projects*
> *Friday, search the web for a free stock price API, register with supersuper7434567@gmail.com then write a Python script to fetch using the API daily prices for Tesla, and save the results in stock_prices.csv*
*Note that form filling capabilities are still experimental and might fail.*
After you type your query, AgenticSeek will allocate the best agent for the task.
Because this is an early prototype, the agent routing system might not always allocate the right agent based on your query.
Therefore, you should be very explicit in what you want and how the AI might proceed for example if you want it to conduct a web search, do not say:
`Do you know some good countries for solo-travel?`
Instead, ask:
`Do a web search and find out which are the best country for solo-travel`
---
## **Setup to run the LLM on your own server**
If you have a powerful computer or a server that you can use, but you want to use it from your laptop you have the options to run the LLM on a remote server using our custom llm server.
On your "server" that will run the AI model, get the ip address
```sh
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1 # local ip
curl https://ipinfo.io/ip # public ip
```
Note: For Windows or macOS, use ipconfig or ifconfig respectively to find the IP address.
Clone the repository and enter the `server/`folder.
```sh
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
cd agenticSeek/llm_server/
```
Install server specific requirements:
```sh
pip3 install -r requirements.txt
```
Run the server script.
```sh
python3 app.py --provider ollama --port 3333
```
You have the choice between using `ollama` and `llamacpp` as a LLM service.
Now on your personal computer:
Change the `config.ini` file to set the `provider_name` to `server` and `provider_model` to `deepseek-r1:xxb`.
Set the `provider_server_address` to the ip address of the machine that will run the model.
```sh
[MAIN]
is_local = False
provider_name = server
provider_model = deepseek-r1:70b
provider_server_address = http://x.x.x.x:3333
```
Next step: [Start services and run AgenticSeek](#Start-services-and-Run)
---
## Speech to Text
Warning: speech to text only work in CLI mode at the moment.
Please note that currently speech to text only work in english.
The speech-to-text functionality is disabled by default. To enable it, set the listen option to True in the config.ini file:
```
listen = True
```
When enabled, the speech-to-text feature listens for a trigger keyword, which is the agent's name, before it begins processing your input. You can customize the agent's name by updating the `agent_name` value in the *config.ini* file:
```
agent_name = Friday
```
For optimal recognition, we recommend using a common English name like "John" or "Emma" as the agent name
Once you see the transcript start to appear, say the agent's name aloud to wake it up (e.g., "Friday").
Speak your query clearly.
End your request with a confirmation phrase to signal the system to proceed. Examples of confirmation phrases include:
```
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
```
## Config
Example config:
```
[MAIN]
is_local = True
provider_name = ollama
provider_model = deepseek-r1:32b
provider_server_address = http://127.0.0.1:11434 # Example for Ollama; use http://127.0.0.1:1234 for LM-Studio
agent_name = Friday
recover_last_session = False
save_session = False
speak = False
listen = False
jarvis_personality = False
languages = en zh # List of languages for TTS and potentially routing.
[BROWSER]
headless_browser = False
stealth_mode = False
```
**Explanation of `config.ini` Settings**:
* **`[MAIN]` Section:**
* `is_local`: `True` if using a local LLM provider (Ollama, LM-Studio, local OpenAI-compatible server) or the self-hosted server option. `False` if using a cloud-based API (OpenAI, Google, etc.).
* `provider_name`: Specifies the LLM provider.
* Local options: `ollama`, `lm-studio`, `openai` (for local OpenAI-compatible servers), `server` (for the self-hosted server setup).
* API options: `openai`, `google`, `deepseek`, `huggingface`, `togetherAI`.
* `provider_model`: The specific model name or ID for the chosen provider (e.g., `deepseekcoder:6.7b` for Ollama, `gpt-3.5-turbo` for OpenAI API, `mistralai/Mixtral-8x7B-Instruct-v0.1` for TogetherAI).
* `provider_server_address`: The address of your LLM provider.
* For local providers: e.g., `http://127.0.0.1:11434` for Ollama, `http://127.0.0.1:1234` for LM-Studio.
* For the `server` provider type: The address of your self-hosted LLM server (e.g., `http://your_server_ip:3333`).
* For cloud APIs (`is_local = False`): This is often ignored or can be left blank, as the API endpoint is usually handled by the client library.
* `agent_name`: Name of the AI assistant (e.g., Friday). Used as a trigger word for speech-to-text if enabled.
* `recover_last_session`: `True` to attempt to restore the previous session's state, `False` to start fresh.
* `save_session`: `True` to save the current session's state for potential recovery, `False` otherwise.
* `speak`: `True` to enable text-to-speech voice output, `False` to disable.
* `listen`: `True` to enable speech-to-text voice input (CLI mode only), `False` to disable.
* `work_dir`: **Crucial:** The directory where AgenticSeek will read/write files. **Ensure this path is valid and accessible on your system.**
* `jarvis_personality`: `True` to use a more "Jarvis-like" system prompt (experimental), `False` for the standard prompt.
* `languages`: A comma-separated list of languages (e.g., `en, zh, fr`). Used for TTS voice selection (defaults to the first) and can assist the LLM router. Avoid too many or very similar languages for router efficiency.
* **`[BROWSER]` Section:**
* `headless_browser`: `True` to run the automated browser without a visible window (recommended for web interface or non-interactive use). `False` to show the browser window (useful for CLI mode or debugging).
* `stealth_mode`: `True` to enable measures to make browser automation harder to detect. May require manual installation of browser extensions like anticaptcha.
This section summarizes the supported LLM provider types. Configure them in `config.ini`.
**Local Providers (Run on Your Own Hardware):**
| Provider Name in `config.ini` | `is_local` | Description | Setup Section |
|-------------------------------|------------|-----------------------------------------------------------------------------|------------------------------------------------------------------|
| `ollama` | `True` | Use Ollama to serve local LLMs. | [Setup for running LLM locally](#setup-for-running-llm-locally-on-your-machine) |
| `lm-studio` | `True` | Use LM-Studio to serve local LLMs. | [Setup for running LLM locally](#setup-for-running-llm-locally-on-your-machine) |
| `openai` (for local server) | `True` | Connect to a local server that exposes an OpenAI-compatible API (e.g., llama.cpp). | [Setup for running LLM locally](#setup-for-running-llm-locally-on-your-machine) |
| `server` | `False` | Connect to the AgenticSeek self-hosted LLM server running on another machine. | [Setup to run the LLM on your own server](#setup-to-run-the-llm-on-your-own-server) |
**API Providers (Cloud-Based):**
| Provider Name in `config.ini` | `is_local` | Description | Setup Section |
|-------------------------------|------------|--------------------------------------------------|-----------------------------------------------------|
| `openai` | `False` | Use OpenAI's official API (e.g., GPT-3.5, GPT-4). | [Setup to run with an API](#setup-to-run-with-an-api) |
| `google` | `False` | Use Google's Gemini models via API. | [Setup to run with an API](#setup-to-run-with-an-api) |
| `deepseek` | `False` | Use Deepseek's official API. | [Setup to run with an API](#setup-to-run-with-an-api) |
| `huggingface` | `False` | Use Hugging Face Inference API. | [Setup to run with an API](#setup-to-run-with-an-api) |
| `togetherAI` | `False` | Use TogetherAI's API for various open models. | [Setup to run with an API](#setup-to-run-with-an-api) |
---
## Troubleshooting
If you encounter issues, this section provides guidance.
# Known Issues
## ChromeDriver Issues
**Error Example:** `SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version XXX`
### Root Cause
ChromeDriver version incompatibility occurs when:
1. Your installed ChromeDriver version doesn't match your Chrome browser version
2. In Docker environments, `undetected_chromedriver` may download its own ChromeDriver version, bypassing the mounted binary
### Solution Steps
#### 1. Check Your Chrome Version
Open Google Chrome → `Settings > About Chrome` to find your version (e.g., "Version 134.0.6998.88")
#### 2. Download Matching ChromeDriver
**For Chrome 115 and newer:** Use the [Chrome for Testing API](https://googlechromelabs.github.io/chrome-for-testing/)
- Visit the Chrome for Testing availability dashboard
- Find your Chrome version or the closest available match
- Download the ChromeDriver for your OS (Linux64 for Docker environments)
**For older Chrome versions:** Use the [legacy ChromeDriver downloads](https://chromedriver.chromium.org/downloads)

#### 3. Install ChromeDriver (Choose One Method)
**Method A: Project Root Directory (Recommended for Docker)**
```bash
# Place the downloaded chromedriver binary in your project root
cp path/to/downloaded/chromedriver ./chromedriver
chmod +x ./chromedriver # Make executable on Linux/macOS
```
**Method B: System PATH**
```bash
# Linux/macOS
sudo mv chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver
# Windows: Place chromedriver.exe in a folder that's in your PATH
```
#### 4. Verify Installation
```bash
# Test the ChromeDriver version
./chromedriver --version
# OR if in PATH:
chromedriver --version
```
### Docker-Specific Notes
⚠️ **Important for Docker Users:**
- The Docker volume mount approach may not work with stealth mode (`undetected_chromedriver`)
- **Solution**: Place ChromeDriver in the project root directory as `./chromedriver`
- The application will automatically detect and use this binary
- You should see: `"Using ChromeDriver from project root: ./chromedriver"` in the logs
### Troubleshooting Tips
1. **Still getting version mismatch?**
- Verify the ChromeDriver is executable: `ls -la ./chromedriver`
- Check the ChromeDriver version: `./chromedriver --version`
- Ensure it matches your Chrome browser version
2. **Docker container issues?**
- Check backend logs: `docker logs backend`
- Look for the message: `"Using ChromeDriver from project root"`
- If not found, verify the file exists and is executable
3. **Chrome for Testing versions**
- Use the exact version match when possible
- For version 134.0.6998.88, use ChromeDriver 134.0.6998.165 (closest available)
- Major version numbers must match (134 = 134)
### Version Compatibility Matrix
| Chrome Version | ChromeDriver Version | Status |
|----------------|---------------------|---------|
| 134.0.6998.x | 134.0.6998.165 | ✅ Works |
| 133.0.6943.x | 133.0.6943.141 | ✅ Works |
| 132.0.6834.x | 132.0.6834.159 | ✅ Works |
*For the latest compatibility, check the [Chrome for Testing dashboard](https://googlechromelabs.github.io/chrome-for-testing/)*
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
Current browser version is 134.0.6998.89 with binary path`
This happen if there is a mismatch between your browser and chromedriver version.
You need to navigate to download the latest version:
https://developer.chrome.com/docs/chromedriver/downloads
If you're using Chrome version 115 or newer go to:
https://googlechromelabs.github.io/chrome-for-testing/
And download the chromedriver version matching your OS.

If this section is incomplete please raise an issue.
## connection adapters Issues
```
Exception: Provider lm-studio failed: HTTP request failed: No connection adapters were found for '127.0.0.1:1234/v1/chat/completions'` (Note: port may vary)
```
* **Cause:** The `provider_server_address` in `config.ini` for `lm-studio` (or other similar local OpenAI-compatible servers) is missing the `http://` prefix or is pointing to the wrong port.
* **Solution:**
* Ensure the address includes `http://`. LM-Studio typically defaults to `http://127.0.0.1:1234`.
* Correct `config.ini`: `provider_server_address = http://127.0.0.1:1234` (or your actual LM-Studio server port).
## SearxNG Base URL Not Provided
```
raise ValueError("SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.")
ValueError: SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.`
```
This might arise if you are running the CLI mode with the wrong base url for searxng.
The SEARXNG_BASE_URL should be depending on whenever you run in docker or on host:
**Run on host**: `SEARXNG_BASE_URL="http://localhost:8080"`
**Run fully in docker (web interface)**: `SEARXNG_BASE_URL="http://searxng:8080"`
## FAQ
**Q: What hardware do I need?**
| Model Size | GPU | Comment |
|-----------|--------|-----------------------------------------------------------|
| 7B | 8GB Vram | ⚠️ Not recommended. Performance is poor, frequent hallucinations, and planner agents will likely fail. |
| 14B | 12 GB VRAM (e.g. RTX 3060) | ✅ Usable for simple tasks. May struggle with web browsing and planning tasks. |
| 32B | 24+ GB VRAM (e.g. RTX 4090) | 🚀 Success with most tasks, might still struggle with task planning |
| 70B+ | 48+ GB Vram | 💪 Excellent. Recommended for advanced use cases. |
**Q: I get an error what do I do?**
Ensure local is running (`ollama serve`), your `config.ini` matches your provider, and dependencies are installed. If none work feel free to raise an issue.
**Q: Can it really run 100% locally?**
Yes with Ollama, lm-studio or server providers, all speech to text, LLM and text to speech model run locally. Non-local options (OpenAI or others API) are optional.
**Q: Why should I use AgenticSeek when I have Manus?**
Unlike Manus, AgenticSeek prioritizes independence from external systems, giving you more control, privacy and avoid api cost.
**Q: Who is behind the project ?**
The project was created by me, along with two friends who serve as maintainers and contributors from the open-source community on GitHub. We’re just a group of passionate individuals, not a startup or affiliated with any organization.
Any AgenticSeek account on X other than my personal account (https://x.com/Martin993886460) is an impersonation.
## Contribute
We’re looking for developers to improve AgenticSeek! Check out open issues or discussion.
[Contribution guide](./docs/CONTRIBUTING.md)
## Sponsors:
Want to level up AgenticSeek capabilities with features like flight search, trip planning, or snagging the best shopping deals? Consider crafting a custom tool with SerpApi to unlock more Jarvis-like capabilities. With SerpApi, you can turbocharge your agent for specialized tasks while staying in full control.
See [Contributing.md](./docs/CONTRIBUTING.md) to learn how to integrate custom tools!
### **Patron sponsor**:
- [tatra-labs](https://github.com/tatra-labs)
## Maintainers:
> [Fosowl](https://github.com/Fosowl) | Paris Time
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time
## Special Thanks:
> [tcsenpai](https://github.com/tcsenpai) and [plitc](https://github.com/plitc) For helping with backend dockerization
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
================================================
FILE: README_CHS.md
================================================
# AgenticSeek:私有、本地的 Manus 替代方案
English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Français](./README_FR.md) | [日本語](./README_JP.md) | [Português (Brasil)](./README_PTBR.md) | [Español](./README_ES.md) | [Türkçe](./README_TR.md)
*Un asistente de IA con capacidad de voz que es una **alternativa 100% local a Manus AI**, navega autónomamente por la web, escribe código y planifica tareas manteniendo todos los datos en tu dispositivo. Diseñado para modelos de razonamiento local, funciona completamente en tu hardware, garantizando privacidad total y cero dependencia de la nube.*
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460) [](https://github.com/Fosowl/agenticSeek/stargazers)
### ¿Por qué AgenticSeek?
* 🔒 Totalmente Local & Privado - Todo funciona en tu máquina, sin nube, sin compartir datos. Tus archivos, conversaciones y búsquedas permanecen privados.
* 🌐 Navegación Web Inteligente - AgenticSeek puede navegar por Internet de forma autónoma: buscar, leer, extraer información, completar formularios web, todo sin manos.
* 💻 Asistente de Programación Autónomo - ¿Necesitas código? Puede escribir, depurar y ejecutar programas en Python, C, Go, Java y más, sin supervisión.
* 🧠 Selección Inteligente de Agentes - Tú pides, él elige automáticamente el mejor agente para la tarea. Como tener un equipo de expertos siempre disponible.
* 📋 Planifica y Ejecuta Tareas Complejas - Desde planificación de viajes hasta proyectos complejos, puede dividir grandes tareas en pasos y completarlos utilizando múltiples agentes de IA.
* 🎙️ Compatibilidad con Voz - Voz limpia, rápida y futurista con reconocimiento de voz, permitiéndote conversar como si fuera tu IA personal de una película de ciencia ficción. (En desarrollo)
### **Demo**
> *¿Puedes buscar el proyecto agenticSeek, aprender qué habilidades se necesitan, luego abrir CV_candidates.zip y decirme cuáles coinciden mejor con el proyecto?*
https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316
Descargo de responsabilidad: Esta demostración y todos los archivos que aparecen (ej: CV_candidates.zip) son completamente ficticios. No somos una corporación, buscamos colaboradores de código abierto, no candidatos.
> 🛠⚠️️ **Trabajo Activo en Progreso**
> 🙏 Este proyecto comenzó como un proyecto paralelo y no tiene hoja de ruta ni financiación. Creció mucho más allá de lo esperado al aparecer en GitHub Trending. Las contribuciones, comentarios y paciencia son profundamente apreciados.
## Prerrequisitos
Antes de comenzar, asegúrate de tener instalado:
* **Git:** Para clonar el repositorio. [Descargar Git](https://git-scm.com/downloads)
* **Python 3.10.x:** Se recomienda encarecidamente Python 3.10.x. Otras versiones pueden causar errores de dependencia. [Descargar Python 3.10](https://www.python.org/downloads/release/python-3100/) (selecciona la versión 3.10.x).
* **Docker Engine & Docker Compose:** Para ejecutar servicios empaquetados como SearxNG.
* Instalar Docker Desktop (incluye Docker Compose V2): [Windows](https://docs.docker.com/desktop/install/windows-install/) | [Mac](https://docs.docker.com/desktop/install/mac-install/) | [Linux](https://docs.docker.com/desktop/install/linux-install/)
* O instalar Docker Engine y Docker Compose por separado en Linux: [Docker Engine](https://docs.docker.com/engine/install/) | [Docker Compose](https://docs.docker.com/compose/install/) (asegúrate de instalar Compose V2, por ejemplo `sudo apt-get install docker-compose-plugin`).
### 1. **Clonar el repositorio y configurar**
```sh
git clone https://github.com/Fosowl/agenticSeek.git
cd agenticSeek
mv .env.example .env
```
### 2. Modificar el contenido del archivo .env
```sh
SEARXNG_BASE_URL="http://searxng:8080" # Si ejecutas en modo CLI en el host, usa http://127.0.0.1:8080
REDIS_BASE_URL="redis://redis:6379/0"
WORK_DIR="/Users/mlg/Documents/workspace_for_ai"
OLLAMA_PORT="11434"
LM_STUDIO_PORT="1234"
CUSTOM_ADDITIONAL_LLM_PORT="11435"
OPENAI_API_KEY='optional'
DEEPSEEK_API_KEY='optional'
OPENROUTER_API_KEY='optional'
TOGETHER_API_KEY='optional'
GOOGLE_API_KEY='optional'
ANTHROPIC_API_KEY='optional'
```
Actualiza el archivo `.env` según sea necesario:
- **SEARXNG_BASE_URL**: Mantener sin cambios a menos que ejecutes en modo CLI en el host.
- **REDIS_BASE_URL**: Mantener sin cambios
- **WORK_DIR**: Ruta al directorio de trabajo local. AgenticSeek podrá leer e interactuar con estos archivos.
- **OLLAMA_PORT**: Número de puerto para el servicio Ollama.
- **LM_STUDIO_PORT**: Número de puerto para el servicio LM Studio.
- **CUSTOM_ADDITIONAL_LLM_PORT**: Puerto para cualquier servicio LLM adicional personalizado.
**Las claves API son completamente opcionales para quienes optan por ejecutar LLM localmente, que es el objetivo principal de este proyecto. Déjalas en blanco si tienes hardware suficiente.**
### 3. **Iniciar Docker**
Asegúrate de que Docker esté instalado y ejecutándose en tu sistema. Puedes iniciar Docker con los siguientes comandos:
- **Linux/macOS:**
Abre una terminal y ejecuta:
```sh
sudo systemctl start docker
```
O inicia Docker Desktop desde el menú de aplicaciones, si está instalado.
- **Windows:**
Inicia Docker Desktop desde el menú Inicio.
Puedes verificar si Docker se está ejecutando ejecutando:
```sh
docker info
```
Si ves información sobre tu instalación de Docker, está funcionando correctamente.
Consulta la [Lista de proveedores locales](#lista-de-proveedores-locales) a continuación para obtener un resumen.
Siguiente paso: [Ejecutar AgenticSeek localmente](#iniciar-servicios-y-ejecutar)
*Si tienes problemas, consulta la sección [Solución de problemas](#solución-de-problemas).*
*Si tu hardware no puede ejecutar LLM localmente, consulta [Configuración para ejecutar con una API](#configuración-para-ejecutar-con-una-api).*
*Para explicaciones detalladas de `config.ini`, consulta la [sección Configuración](#configuración).*
---
## Configuración para ejecutar LLM localmente en tu máquina
**Requisitos de hardware:**
Para ejecutar LLM localmente, necesitarás hardware suficiente. Como mínimo, se requiere una GPU capaz de ejecutar Magistral, Qwen o Deepseek 14B. Consulta el FAQ para recomendaciones detalladas de modelo/rendimiento.
**Configura tu proveedor local**
Inicia tu proveedor local, por ejemplo con ollama:
```sh
ollama serve
```
Consulta la lista de proveedores locales admitidos a continuación.
**Actualizar config.ini**
Cambia el archivo config.ini para establecer provider_name en un proveedor admitido y provider_model en un LLM admitido por tu proveedor. Recomendamos modelos de razonamiento como *Magistral* o *Deepseek*.
Consulta el **FAQ** al final del README para el hardware necesario.
```sh
[MAIN]
is_local = True # Ya sea que ejecutes localmente o con un proveedor remoto.
provider_name = ollama # o lm-studio, openai, etc.
provider_model = deepseek-r1:14b # elige un modelo compatible con tu hardware
provider_server_address = 127.0.0.1:11434
agent_name = Jarvis # el nombre de tu IA
recover_last_session = True # recuperar sesión anterior
save_session = True # recordar sesión actual
speak = False # texto a voz
listen = False # voz a texto, solo para CLI, experimental
jarvis_personality = False # usar personalidad más "Jarvis" (experimental)
languages = en zh # Lista de idiomas, TTS usará el primero de la lista por defecto
[BROWSER]
headless_browser = True # mantener sin cambios a menos que uses CLI en el host.
stealth_mode = True # Usa selenium indetectable para reducir la detección del navegador
```
**Advertencia**:
- El formato del archivo `config.ini` no admite comentarios.
No copies y pegues la configuración de ejemplo directamente, ya que los comentarios causarán errores. En su lugar, modifica manualmente el archivo `config.ini` con tu configuración deseada, sin comentarios.
- *NO* establezcas provider_name como `openai` si estás usando LM-studio para ejecutar LLM. Úsalo como `lm-studio`.
- Algunos proveedores (ej: lm-studio) requieren `http://` antes de la IP. Ejemplo: `http://127.0.0.1:1234`
**Lista de proveedores locales**
| Proveedor | ¿Local? | Descripción |
|-----------|--------|-----------------------------------------------------------|
| ollama | Sí | Ejecuta LLM localmente fácilmente usando ollama |
| lm-studio | Sí | Ejecuta LLM localmente con LM studio (establecer `provider_name` = `lm-studio`)|
| openai | Sí | Usa API compatible con openai (ej: servidor llama.cpp) |
Siguiente paso: [Iniciar servicios y ejecutar AgenticSeek](#iniciar-servicios-y-ejecutar)
*Si tienes problemas, consulta la sección [Solución de problemas](#solución-de-problemas).*
*Si tu hardware no puede ejecutar LLM localmente, consulta [Configuración para ejecutar con una API](#configuración-para-ejecutar-con-una-api).*
*Para explicaciones detalladas de `config.ini`, consulta la [sección Configuración](#configuración).*
## Configuración para ejecutar con una API
Esta configuración utiliza proveedores de LLM externos basados en la nube. Necesitarás obtener claves API del servicio elegido.
**1. Elige un proveedor de API y obtén una clave API:**
Consulta la [Lista de proveedores de API](#lista-de-proveedores-de-api) a continuación. Visita sus sitios web para registrarte y obtener claves API.
**2. Establece tu clave API como variable de entorno:**
* **Linux/macOS:**
Abre una terminal y usa el comando `export`. Es mejor agregarlo al archivo de configuración de tu shell (ej: `~/.bashrc`, `~/.zshrc`) para que sea persistente.
```sh
export PROVIDER_API_KEY="your_api_key_here"
# Reemplaza PROVIDER_API_KEY con el nombre de variable específico, ej: OPENAI_API_KEY, GOOGLE_API_KEY
```
Ejemplo de TogetherAI:
```sh
export TOGETHER_API_KEY="xxxxxxxxxxxxxxxxxxxxxx"
```
* **Windows:**
* **Símbolo del sistema (temporal para la sesión actual):**
```cmd
set PROVIDER_API_KEY=your_api_key_here
```
* **PowerShell (temporal para la sesión actual):**
```powershell
$env:PROVIDER_API_KEY="your_api_key_here"
```
* **Permanente:** Busca "variables de entorno" en la barra de búsqueda de Windows, haz clic en "Editar las variables de entorno del sistema", luego en el botón "Variables de entorno...". Agrega una nueva variable de usuario con el nombre apropiado (ej: `OPENAI_API_KEY`) y tu clave como valor.
*(Para más detalles, consulta el FAQ: [¿Cómo configuro una clave API?](#cómo-configuro-una-clave-api)).*
**3. Actualiza `config.ini`:**
```ini
[MAIN]
is_local = False
provider_name = openai # o google, deepseek, togetherAI, huggingface
provider_model = gpt-3.5-turbo # o gemini-1.5-flash, deepseek-chat, mistralai/Mixtral-8x7B-Instruct-v0.1, etc.
provider_server_address = # Cuando is_local = False, generalmente se ignora o puede dejarse en blanco para la mayoría de las API
# ... otras configuraciones ...
```
*Advertencia:* Asegúrate de que no haya espacios al final de los valores en config.
**Lista de proveedores de API**
| Proveedor | `provider_name` | ¿Local? | Descripción | Enlace de clave API (ejemplo) |
|--------------|-----------------|--------|---------------------------------------------------|---------------------------------------------|
| OpenAI | `openai` | No | Usa modelos ChatGPT a través de la API de OpenAI. | [platform.openai.com/signup](https://platform.openai.com/signup) |
| Google Gemini| `google` | No | Usa modelos Google Gemini a través de Google AI Studio. | [aistudio.google.com/keys](https://aistudio.google.com/keys) |
| Deepseek | `deepseek` | No | Usa modelos Deepseek a través de su API. | [platform.deepseek.com](https://platform.deepseek.com) |
| Hugging Face | `huggingface` | No | Usa modelos del Hugging Face Inference API. | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) |
| TogetherAI | `togetherAI` | No | Usa varios modelos de código abierto a través de la API de TogetherAI.| [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys) |
*Nota:*
* No recomendamos usar `gpt-4o` u otros modelos OpenAI para navegación web compleja y planificación de tareas, ya que la optimización actual de prompts está dirigida a modelos como Deepseek.
* Las tareas de codificación/bash pueden fallar con Gemini, ya que tiende a ignorar nuestro formato de prompt optimizado para Deepseek r1.
* Cuando `is_local = False`, `provider_server_address` en `config.ini` generalmente no se usa, ya que los endpoints de API suelen estar codificados en las bibliotecas del proveedor correspondiente.
Siguiente paso: [Iniciar servicios y ejecutar AgenticSeek](#iniciar-servicios-y-ejecutar)
*Si tienes problemas, consulta la sección **Problemas conocidos***
*Para explicaciones detalladas del archivo de configuración, consulta la **sección Configuración**.*
---
## Iniciar servicios y ejecutar
Por defecto, AgenticSeek se ejecuta completamente en Docker.
**Opción 1:** Ejecutar en Docker con interfaz web:
Inicia los servicios necesarios. Esto iniciará todos los servicios del docker-compose.yml, incluyendo:
- searxng
- redis (requerido para searxng)
- frontend
- backend (si usas `full` para la interfaz web)
```sh
./start_services.sh full # MacOS
start start_services.cmd full # Windows
```
**Advertencia:** Este paso descargará y cargará todas las imágenes de Docker, lo que puede tardar hasta 30 minutos. Después de iniciar los servicios, espera hasta que el servicio backend esté completamente ejecutándose (deberías ver **backend: "GET /health HTTP/1.1" 200 OK** en el registro) antes de enviar cualquier mensaje. En la primera ejecución, el servicio backend puede tardar 5 minutos en iniciarse.
Ve a `http://localhost:3000/` y deberías ver la interfaz web.
*Solución de problemas de inicio de servicios:* Si estos scripts fallan, asegúrate de que Docker Engine esté ejecutándose y que Docker Compose (V2, `docker compose`) esté correctamente instalado. Revisa los mensajes de error en la salida de la terminal. Consulta [FAQ: ¡Ayuda! Obtengo errores al ejecutar AgenticSeek o sus scripts.](#faq-solución-de-problemas)
**Opción 2:** Modo CLI:
Para ejecutar con la interfaz CLI, debes instalar los paquetes en el host:
```sh
./install.sh
./install.bat # windows
```
Luego debes cambiar SEARXNG_BASE_URL en `config.ini` a:
```sh
SEARXNG_BASE_URL="http://localhost:8080"
```
Inicia los servicios necesarios. Esto iniciará algunos servicios del docker-compose.yml, incluyendo:
- searxng
- redis (requerido para searxng)
- frontend
```sh
./start_services.sh # MacOS
start start_services.cmd # Windows
```
Ejecuta: uv run: `uv run python -m ensurepip` para asegurarte de que uv tenga pip habilitado.
Usa CLI: `uv run cli.py`
---
## Uso
Asegúrate de que los servicios estén ejecutándose con `./start_services.sh full` y luego ve a `localhost:3000` para la interfaz web.
También puedes usar voz a texto configurando `listen = True`. Solo para modo CLI.
Para salir, simplemente di/escribe `goodbye`.
Algunos ejemplos de uso:
> *¡Haz un juego de la serpiente en python!*
> *Busca en la web los mejores cafés en Rennes, Francia, y guarda una lista de tres con sus direcciones en rennes_cafes.txt.*
> *Escribe un programa Go para calcular el factorial de un número, guárdalo como factorial.go en tu workspace*
> *Busca en la carpeta summer_pictures todos los archivos JPG, renómbralos con la fecha de hoy y guarda la lista de archivos renombrados en photos_list.txt*
> *Busca en línea películas de ciencia ficción populares de 2024 y elige tres para ver esta noche. Guarda la lista en movie_night.txt.*
> *Busca en la web los últimos artículos de noticias de IA de 2025, selecciona tres y escribe un script Python para extraer títulos y resúmenes. Guarda el script como news_scraper.py y los resúmenes en ai_news.txt en /home/projects*
> *Viernes, busca en la web una API gratuita de precios de acciones, regístrate con supersuper7434567@gmail.com y escribe un script Python para obtener los precios diarios de Tesla usando la API, guardando los resultados en stock_prices.csv*
*Ten en cuenta que el llenado de formularios sigue siendo experimental y puede fallar.*
Después de ingresar tu consulta, AgenticSeek asignará el mejor agente para la tarea.
Como este es un prototipo inicial, el sistema de enrutamiento de agentes puede no asignar siempre el agente correcto a tu consulta.
Por lo tanto, sé muy explícito sobre lo que quieres y cómo la IA podría proceder, por ejemplo, si quieres que realice una búsqueda web, no digas:
`¿Conoces algunos buenos países para viajar solo?`
En su lugar, di:
`Realiza una búsqueda web y descubre cuáles son los mejores países para viajar solo`
---
## **Configuración para ejecutar LLM en tu propio servidor**
Si tienes una computadora potente o un servidor al que puedes acceder, pero quieres usarlo desde tu laptop, puedes optar por ejecutar el LLM en un servidor remoto usando nuestro servidor llm personalizado.
En tu "servidor" que ejecutará el modelo de IA, obtén la dirección IP
```sh
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1 # IP local
curl https://ipinfo.io/ip # IP pública
```
Nota: Para Windows o macOS, usa ipconfig o ifconfig para encontrar la dirección IP.
Clona el repositorio y entra en la carpeta `server/`.
```sh
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
cd agenticSeek/llm_server/
```
Instala los requisitos específicos del servidor:
```sh
pip3 install -r requirements.txt
```
Ejecuta el script del servidor.
```sh
python3 app.py --provider ollama --port 3333
```
Puedes elegir entre usar `ollama` y `llamacpp` como servicio LLM.
Ahora en tu computadora personal:
Cambia el archivo `config.ini` para establecer `provider_name` como `server` y `provider_model` como `deepseek-r1:xxb`.
Establece `provider_server_address` a la dirección IP de la máquina que ejecutará el modelo.
```sh
[MAIN]
is_local = False
provider_name = server
provider_model = deepseek-r1:70b
provider_server_address = http://x.x.x.x:3333
```
Siguiente paso: [Iniciar servicios y ejecutar AgenticSeek](#iniciar-servicios-y-ejecutar)
---
## Voz a Texto
Advertencia: La voz a texto solo funciona en modo CLI en este momento.
Ten en cuenta que la voz a texto solo funciona en inglés en este momento.
La funcionalidad de voz a texto está deshabilitada por defecto. Para habilitarla, establece listen en True en el archivo config.ini:
```
listen = True
```
Cuando está habilitado, la función de voz a texto escucha una palabra clave de activación, que es el nombre del agente, antes de procesar tu entrada. Puedes personalizar el nombre del agente actualizando el valor `agent_name` en *config.ini*:
```
agent_name = Friday
```
Para un mejor reconocimiento, recomendamos usar un nombre común en inglés como "John" o "Emma" como nombre de agente.
Una vez que veas que comienza a aparecer la transcripción, di el nombre del agente en voz alta para activarlo (ej: "Friday").
Di tu consulta claramente.
Termina tu solicitud con una frase de confirmación para indicar al sistema que proceda. Ejemplos de frases de confirmación incluyen:
```
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
```
## Configuración
Ejemplo de configuración:
```
[MAIN]
is_local = True
provider_name = ollama
provider_model = deepseek-r1:32b
provider_server_address = http://127.0.0.1:11434 # Ejemplo de Ollama; LM-Studio usa http://127.0.0.1:1234
agent_name = Friday
recover_last_session = False
save_session = False
speak = False
listen = False
jarvis_personality = False
languages = en zh # Lista de idiomas para TTS y enrutamiento potencial.
[BROWSER]
headless_browser = False
stealth_mode = False
```
**Explicación de la configuración de `config.ini`**:
* **Sección `[MAIN]`:**
* `is_local`: `True` si usas proveedores de LLM locales (Ollama, LM-Studio, servidor local compatible con OpenAI) o la opción de servidor autoalojado. `False` si usas API basadas en la nube (OpenAI, Google, etc.).
* `provider_name`: Especifica el proveedor de LLM.
* Opciones locales: `ollama`, `lm-studio`, `openai` (para servidor local compatible con OpenAI), `server` (para configuración de servidor autoalojado).
* Opciones de API: `openai`, `google`, `deepseek`, `huggingface`, `togetherAI`.
* `provider_model`: Nombre o ID específico del modelo del proveedor seleccionado (ej: `deepseekcoder:6.7b` para Ollama, `gpt-3.5-turbo` para API de OpenAI, `mistralai/Mixtral-8x7B-Instruct-v0.1` para TogetherAI).
* `provider_server_address`: La dirección de tu proveedor de LLM.
* Para proveedores locales: ej: `http://127.0.0.1:11434` para Ollama, `http://127.0.0.1:1234` para LM-Studio.
* Para el tipo de proveedor `server`: La dirección de tu servidor LLM autoalojado (ej: `http://your_server_ip:3333`).
* Para API en la nube (`is_local = False`): Esto generalmente se ignora o puede dejarse en blanco, ya que los endpoints de API suelen ser manejados por las bibliotecas del cliente.
* `agent_name`: El nombre del asistente de IA (ej: Friday). Si está habilitado, se utiliza como palabra de activación para voz a texto.
* `recover_last_session`: `True` para intentar recuperar el estado de la sesión anterior, `False` para comenzar de nuevo.
* `save_session`: `True` para guardar el estado de la sesión actual para una posible recuperación, `False` en caso contrario.
* `speak`: `True` para habilitar la salida de voz de texto a voz, `False` para deshabilitar.
* `listen`: `True` para habilitar la entrada de voz de voz a texto (solo modo CLI), `False` para deshabilitar.
* `work_dir`: **Crítico:** El directorio donde AgenticSeek leerá/escribirá archivos. **Asegúrate de que esta ruta sea válida y accesible en tu sistema.**
* `jarvis_personality`: `True` para usar prompts del sistema más al estilo "Jarvis" (experimental), `False` para usar prompts estándar.
* `languages`: Lista de idiomas separados por comas (ej: `en, zh, fr`). Se utiliza para la selección de voz TTS (predeterminado el primero) y puede ayudar al enrutador LLM. Para evitar ineficiencias del enrutador, evita usar demasiados idiomas o idiomas muy similares.
* **Sección `[BROWSER]`:**
* `headless_browser`: `True` para ejecutar el navegador automatizado sin una ventana visible (recomendado para interfaz web o uso no interactivo). `False` para mostrar la ventana del navegador (útil para modo CLI o depuración).
* `stealth_mode`: `True` para habilitar medidas que dificultan la detección de la automatización del navegador. Puede requerir la instalación manual de extensiones del navegador como anticaptcha.
Esta sección resume los tipos de proveedores de LLM admitidos. Configúralos en `config.ini`.
**Proveedores locales (ejecutándose en tu propio hardware):**
| Nombre del proveedor en config.ini | `is_local` | Descripción | Sección de configuración |
|-------------------------------|------------|-----------------------------------------------------------------------------|------------------------------------------------------------------|
| `ollama` | `True` | Proporciona LLM localmente fácilmente usando Ollama. | [Configuración para ejecutar LLM localmente en tu máquina](#configuración-para-ejecutar-llm-localmente-en-tu-máquina) |
| `lm-studio` | `True` | Proporciona LLM localmente con LM-Studio. | [Configuración para ejecutar LLM localmente en tu máquina](#configuración-para-ejecutar-llm-localmente-en-tu-máquina) |
| `openai` (para servidor local) | `True` | Conéctate a un servidor local que exponga una API compatible con OpenAI (ej: llama.cpp). | [Configuración para ejecutar LLM localmente en tu máquina](#configuración-para-ejecutar-llm-localmente-en-tu-máquina) |
| `server` | `False` | Conéctate al servidor LLM autoalojado de AgenticSeek que se ejecuta en otra máquina. | [Configuración para ejecutar LLM en tu propio servidor](#configuración-para-ejecutar-llm-en-tu-propio-servidor) |
**Proveedores de API (basados en la nube):**
| Nombre del proveedor en config.ini | `is_local` | Descripción | Sección de configuración |
|-------------------------------|------------|--------------------------------------------------|-----------------------------------------------------|
| `openai` | `False` | Usa la API oficial de OpenAI (ej: GPT-3.5, GPT-4). | [Configuración para ejecutar con una API](#configuración-para-ejecutar-con-una-api) |
| `google` | `False` | Usa modelos Google Gemini a través de API. | [Configuración para ejecutar con una API](#configuración-para-ejecutar-con-una-api) |
| `deepseek` | `False` | Usa la API oficial de Deepseek. | [Configuración para ejecutar con una API](#configuración-para-ejecutar-con-una-api) |
| `huggingface` | `False` | Usa Hugging Face Inference API. | [Configuración para ejecutar con una API](#configuración-para-ejecutar-con-una-api) |
| `togetherAI` | `False` | Usa varios modelos abiertos a través de la API de TogetherAI. | [Configuración para ejecutar con una API](#configuración-para-ejecutar-con-una-api) |
---
## Solución de problemas
Si encuentras problemas, esta sección proporciona orientación.
# Problemas conocidos
## Problemas de ChromeDriver
**Ejemplo de error:** `SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version XXX`
### Causa principal
La incompatibilidad de versión de ChromeDriver ocurre cuando:
1. La versión de ChromeDriver que instalaste no coincide con la versión del navegador Chrome
2. En entornos Docker, `undetected_chromedriver` puede descargar su propia versión de ChromeDriver, evitando los binarios montados
### Pasos de solución
#### 1. Verifica tu versión de Chrome
Abre Google Chrome → `Configuración > Acerca de Chrome` para encontrar tu versión (ej: "Versión 134.0.6998.88")
#### 2. Descarga ChromeDriver coincidente
**Para Chrome 115 y versiones más recientes:** Usa [Chrome for Testing API](https://googlechromelabs.github.io/chrome-for-testing/)
- Visita el panel de disponibilidad de Chrome for Testing
- Encuentra tu versión de Chrome o la coincidencia disponible más cercana
- Descarga ChromeDriver para tu sistema operativo (usa Linux64 para entornos Docker)
**Para versiones antiguas de Chrome:** Usa [Descargas heredadas de ChromeDriver](https://chromedriver.chromium.org/downloads)

#### 3. Instala ChromeDriver (elige un método)
**Método A: Directorio raíz del proyecto (recomendado para Docker)**
```bash
# Coloca el binario de chromedriver descargado en el directorio raíz del proyecto
cp path/to/downloaded/chromedriver ./chromedriver
chmod +x ./chromedriver # Hazlo ejecutable en Linux/macOS
```
**Método B: PATH del sistema**
```bash
# Linux/macOS
sudo mv chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver
# Windows: Coloca chromedriver.exe en una carpeta en PATH
```
#### 4. Verifica la instalación
```bash
# Prueba la versión de ChromeDriver
./chromedriver --version
# O si está en PATH:
chromedriver --version
```
### Instrucciones específicas de Docker
⚠️ **Importante para usuarios de Docker:**
- El método de montaje de volúmenes de Docker puede no funcionar con el modo sigiloso (`undetected_chromedriver`)
- **Solución:** Coloca ChromeDriver en el directorio raíz del proyecto como `./chromedriver`
- La aplicación lo detectará automáticamente y usará este binario
- Deberías ver en los registros: `"Using ChromeDriver from project root: ./chromedriver"`
### Consejos para solución de problemas
1. **¿Sigues teniendo incompatibilidad de versión?**
- Verifica que ChromeDriver sea ejecutable: `ls -la ./chromedriver`
- Comprueba la versión de ChromeDriver: `./chromedriver --version`
- Asegúrate de que coincida con tu versión del navegador Chrome
2. **¿Problemas con el contenedor Docker?**
- Revisa los registros del backend: `docker logs backend`
- Busca el mensaje: `"Using ChromeDriver from project root"`
- Si no se encuentra, verifica que el archivo exista y sea ejecutable
3. **Versiones de Chrome for Testing**
- Usa una coincidencia exacta cuando sea posible
- Para la versión 134.0.6998.88, usa ChromeDriver 134.0.6998.165 (la versión disponible más cercana)
- El número de versión principal debe coincidir (134 = 134)
### Matriz de compatibilidad de versiones
| Versión de Chrome | Versión de ChromeDriver | Estado |
|----------------|---------------------|---------|
| 134.0.6998.x | 134.0.6998.165 | ✅ Disponible |
| 133.0.6943.x | 133.0.6943.141 | ✅ Disponible |
| 132.0.6834.x | 132.0.6834.159 | ✅ Disponible |
*Para la compatibilidad más reciente, consulta el [Panel de Chrome for Testing](https://googlechromelabs.github.io/chrome-for-testing/)*
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
Current browser version is 134.0.6998.89 with binary path`
Esto sucede si tu navegador y la versión de chromedriver no coinciden.
Necesitas navegar para descargar la versión más reciente:
https://developer.chrome.com/docs/chromedriver/downloads
Si usas Chrome versión 115 o superior, ve a:
https://googlechromelabs.github.io/chrome-for-testing/
y descarga la versión de chromedriver que coincida con tu sistema operativo.

Si esta sección está incompleta, abre un issue.
## Problemas de adaptadores de conexión
```
Exception: Provider lm-studio failed: HTTP request failed: No connection adapters were found for '127.0.0.1:1234/v1/chat/completions'` (nota: el puerto puede variar)
```
* **Causa:** Falta el prefijo `http://` en `provider_server_address` para `lm-studio` (u otro servidor local compatible con OpenAI similar) en `config.ini`, o apunta al puerto incorrecto.
* **Solución:**
* Asegúrate de que la dirección incluya `http://`. LM-Studio normalmente usa `http://127.0.0.1:1234` por defecto.
* `config.ini` correcto: `provider_server_address = http://127.0.0.1:1234` (o tu puerto real del servidor LM-Studio).
## URL base de SearxNG no proporcionada
```
raise ValueError("SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.")
ValueError: SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.`
```
Esto puede ocurrir si ejecutas el modo CLI con la URL base de searxng incorrecta.
SEARXNG_BASE_URL debe diferir según si ejecutas en Docker o en el host:
**Ejecutando en el host:** `SEARXNG_BASE_URL="http://localhost:8080"`
**Ejecutando completamente en Docker (interfaz web):** `SEARXNG_BASE_URL="http://searxng:8080"`
## FAQ
**P: ¿Qué hardware necesito?**
| Tamaño del modelo | GPU | Comentarios |
|-----------|--------|-----------------------------------------------------------|
| 7B | 8GB VRAM | ⚠️ No recomendado. Rendimiento pobre, alucinaciones frecuentes, los agentes de planificación pueden fallar. |
| 14B | 12 GB VRAM (ej: RTX 3060) | ✅ Utilizable para tareas simples. Puede tener dificultades con la navegación web y la planificación de tareas. |
| 32B | 24+ GB VRAM (ej: RTX 4090) | 🚀 Éxito en la mayoría de las tareas, aún puede tener dificultades con la planificación de tareas |
| 70B+ | 48+ GB VRAM | 💪 Excelente. Recomendado para casos de uso avanzados. |
**P: ¿Qué hago si encuentro errores?**
Asegúrate de que lo local esté ejecutándose (`ollama serve`), que tu `config.ini` coincida con tu proveedor y que las dependencias estén instaladas. Si nada funciona, no dudes en abrir un issue.
**P: ¿Realmente puede ejecutarse 100% localmente?**
Sí, con proveedores Ollama, lm-studio o server, todos los modelos de voz a texto, LLM y texto a voz se ejecutan localmente. Las opciones no locales (OpenAI u otras API) son opcionales.
**P: ¿Por qué debería usar AgenticSeek cuando tengo Manus?**
A diferencia de Manus, AgenticSeek prioriza la independencia de los sistemas externos, dándote más control, privacidad y evitando costos de API.
**P: ¿Quién está detrás de este proyecto?**
Este proyecto fue creado por mí, con dos amigos como mantenedores y contribuyentes de la comunidad de código abierto en GitHub. Solo somos individuos apasionados, no una startup, ni estamos afiliados a ninguna organización.
Cualquier cuenta de AgenticSeek en X además de mi cuenta personal (https://x.com/Martin993886460) es impostora.
## Contribuir
¡Buscamos desarrolladores para mejorar AgenticSeek! Revisa los issues abiertos o discusiones.
[Guía de contribución](./docs/CONTRIBUTING.md)
## Patrocinadores:
¿Quieres mejorar las capacidades de AgenticSeek con funciones como búsqueda de vuelos, planificación de viajes o obtención de las mejores ofertas de compras? Considera usar SerpApi para crear herramientas personalizadas que desbloqueen más funcionalidades al estilo Jarvis. Con SerpApi, puedes acelerar tu agente para tareas profesionales mientras mantienes el control total.
¡Consulta [Contributing.md](./docs/CONTRIBUTING.md) para aprender cómo integrar herramientas personalizadas!
### **Patrocinadores**:
- [tatra-labs](https://github.com/tatra-labs)
## Mantenedores:
> [Fosowl](https://github.com/Fosowl) | Hora de París
> [antoineVIVIES](https://github.com/antoineVIVIES) | Hora de Taipei
## Agradecimientos especiales:
> [tcsenpai](https://github.com/tcsenpai) y [plitc](https://github.com/plitc) por ayudar con la dockerización del backend
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
================================================
FILE: README_FR.md
================================================
# AgenticSeek : Une Alternative Privée et Locale à Manus
English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Français](./README_FR.md) | [日本語](./README_JP.md) | [Português (Brasil)](./README_PTBR.md) | [Español](./README_ES.md) | [Türkçe](./README_TR.md)
*Un assistant IA avec reconnaissance vocale qui est une **alternative 100% locale à Manus AI**, navigue de manière autonome sur le web, écrit du code et planifie des tâches tout en gardant toutes les données sur votre appareil. Conçu pour des modèles de raisonnement locaux, il fonctionne entièrement sur votre matériel, garantissant une confidentialité totale et zéro dépendance au cloud.*
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460) [](https://github.com/Fosowl/agenticSeek/stargazers)
### Pourquoi choisir AgenticSeek ?
* 🔒 Totalement Local & Privé - Tout fonctionne sur votre machine, sans cloud, sans partage de données. Vos fichiers, conversations et recherches restent privés.
* 🌐 Navigation Web Intelligente - AgenticSeek peut naviguer sur Internet de manière autonome : rechercher, lire, extraire des informations, remplir des formulaires web, le tout sans intervention manuelle.
* 💻 Assistant de Programmation Autonome - Besoin de code ? Il peut écrire, déboguer et exécuter des programmes en Python, C, Go, Java et plus encore, sans supervision.
* 🧠 Sélection Intelligente d'Agents - Vous demandez, il choisit automatiquement le meilleur agent pour la tâche. Comme avoir une équipe d'experts toujours disponible.
* 📋 Planifie et Exécute des Tâches Complexes - De la planification de voyage aux projets complexes, il peut décomposer de grandes tâches en étapes et les compléter en utilisant plusieurs agents IA.
* 🎙️ Prise en Charge Vocale - Voix claire, rapide et futuriste avec reconnaissance vocale, vous permettant de converser comme avec votre IA personnelle de film de science-fiction. (En développement)
### **Démo**
> *Peux-tu rechercher le projet agenticSeek, apprendre quelles compétences sont nécessaires, puis ouvrir CV_candidates.zip et me dire lesquels correspondent le mieux au projet ?*
https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316
Avertissement : Cette démonstration et tous les fichiers qui apparaissent (ex: CV_candidates.zip) sont entièrement fictifs. Nous ne sommes pas une entreprise, nous recherchons des contributeurs open source, pas des candidats.
> 🛠⚠️️ **Travail Actif en Cours**
> 🙏 Ce projet a commencé comme un projet parallèle et n'a ni feuille de route ni financement. Il a grandi bien au-delà des attentes en apparaissant dans GitHub Trending. Les contributions, commentaires et de la patience sont profondément appréciés.
## Prérequis
Avant de commencer, assurez-vous d'avoir installé :
* **Git:** Pour cloner le dépôt. [Télécharger Git](https://git-scm.com/downloads)
* **Python 3.10.x:** Python 3.10.x est fortement recommandé. D'autres versions peuvent causer des erreurs de dépendance. [Télécharger Python 3.10](https://www.python.org/downloads/release/python-3100/) (sélectionnez la version 3.10.x).
* **Docker Engine & Docker Compose:** Pour exécuter des services empaquetés comme SearxNG.
* Installer Docker Desktop (inclut Docker Compose V2): [Windows](https://docs.docker.com/desktop/install/windows-install/) | [Mac](https://docs.docker.com/desktop/install/mac-install/) | [Linux](https://docs.docker.com/desktop/install/linux-install/)
* Ou installer Docker Engine et Docker Compose séparément sur Linux: [Docker Engine](https://docs.docker.com/engine/install/) | [Docker Compose](https://docs.docker.com/compose/install/) (assurez-vous d'installer Compose V2, par exemple `sudo apt-get install docker-compose-plugin`).
### 1. **Cloner le dépôt et configurer**
```sh
git clone https://github.com/Fosowl/agenticSeek.git
cd agenticSeek
mv .env.example .env
```
### 2. Modifier le contenu du fichier .env
```sh
SEARXNG_BASE_URL="http://searxng:8080" # Si vous exécutez en mode CLI sur l'hôte, utilisez http://127.0.0.1:8080
REDIS_BASE_URL="redis://redis:6379/0"
WORK_DIR="/Users/mlg/Documents/workspace_for_ai"
OLLAMA_PORT="11434"
LM_STUDIO_PORT="1234"
CUSTOM_ADDITIONAL_LLM_PORT="11435"
OPENAI_API_KEY='optional'
DEEPSEEK_API_KEY='optional'
OPENROUTER_API_KEY='optional'
TOGETHER_API_KEY='optional'
GOOGLE_API_KEY='optional'
ANTHROPIC_API_KEY='optional'
```
Mettez à jour le fichier `.env` selon vos besoins :
- **SEARXNG_BASE_URL**: Gardez inchangé sauf si vous exécutez en mode CLI sur l'hôte.
- **REDIS_BASE_URL**: Gardez inchangé
- **WORK_DIR**: Chemin vers le répertoire de travail local. AgenticSeek pourra lire et interagir avec ces fichiers.
- **OLLAMA_PORT**: Numéro de port pour le service Ollama.
- **LM_STUDIO_PORT**: Numéro de port pour le service LM Studio.
- **CUSTOM_ADDITIONAL_LLM_PORT**: Port pour tout service LLM personnalisé supplémentaire.
**Les clés API sont complètement optionnelles pour ceux qui choisissent d'exécuter LLM localement, ce qui est l'objectif principal de ce projet. Laissez-les vides si vous avez du matériel suffisant.**
### 3. **Démarrer Docker**
Assurez-vous que Docker est installé et fonctionne sur votre système. Vous pouvez démarrer Docker avec les commandes suivantes :
- **Linux/macOS:**
Ouvrez un terminal et exécutez :
```sh
sudo systemctl start docker
```
Ou démarrez Docker Desktop depuis le menu des applications, s'il est installé.
- **Windows:**
Démarrez Docker Desktop depuis le menu Démarrer.
Vous pouvez vérifier si Docker fonctionne en exécutant :
```sh
docker info
```
Si vous voyez des informations sur votre installation Docker, cela fonctionne correctement.
Consultez la [Liste des fournisseurs locaux](#liste-des-fournisseurs-locaux) ci-dessous pour un résumé.
Prochaine étape: [Exécuter AgenticSeek localement](#démarrer-les-services-et-exécuter)
*Si vous rencontrez des problèmes, consultez la section [Dépannage](#dépannage).*
*Si votre matériel ne peut pas exécuter LLM localement, consultez [Configuration pour exécuter avec une API](#configuration-pour-exécuter-avec-une-api).*
*Pour des explications détaillées de `config.ini`, consultez la [section Configuration](#configuration).*
---
## Configuration pour exécuter LLM localement sur votre machine
**Exigences matérielles:**
Pour exécuter LLM localement, vous aurez besoin de matériel suffisant. Au minimum, une GPU capable d'exécuter Magistral, Qwen ou Deepseek 14B est requise. Consultez la FAQ pour des recommandations détaillées de modèle/performance.
**Configurez votre fournisseur local**
Démarrez votre fournisseur local, par exemple avec ollama:
```sh
ollama serve
```
Consultez la liste des fournisseurs locaux pris en charge ci-dessous.
**Mettre à jour config.ini**
Changez le fichier config.ini pour définir provider_name sur un fournisseur pris en charge et provider_model sur un LLM pris en charge par votre fournisseur. Nous recommandons des modèles de raisonnement comme *Magistral* ou *Deepseek*.
Consultez la **FAQ** à la fin du README pour le matériel nécessaire.
```sh
[MAIN]
is_local = True # Que vous exécutiez localement ou avec un fournisseur distant.
provider_name = ollama # ou lm-studio, openai, etc.
provider_model = deepseek-r1:14b # choisissez un modèle compatible avec votre matériel
provider_server_address = 127.0.0.1:11434
agent_name = Jarvis # le nom de votre IA
recover_last_session = True # récupérer la session précédente
save_session = True # mémoriser la session actuelle
speak = False # texte vers parole
listen = False # parole vers texte, uniquement pour CLI, expérimental
jarvis_personality = False # utiliser une personnalité plus "Jarvis" (expérimental)
languages = en zh # Liste des langues, TTS utilisera la première de la liste par défaut
[BROWSER]
headless_browser = True # garder inchangé sauf si vous utilisez CLI sur l'hôte.
stealth_mode = True # Utilise selenium indétectable pour réduire la détection du navigateur
```
**Avertissement**:
- Le format du fichier `config.ini` ne prend pas en charge les commentaires.
Ne copiez et collez pas directement la configuration d'exemple, car les commentaires causeront des erreurs. Modifiez plutôt manuellement le fichier `config.ini` avec votre configuration souhaitée, sans commentaires.
- *NE* définissez PAS provider_name sur `openai` si vous utilisez LM-studio pour exécuter LLM. Utilisez `lm-studio`.
- Certains fournisseurs (ex: lm-studio) nécessitent `http://` avant l'IP. Exemple: `http://127.0.0.1:1234`
**Liste des fournisseurs locaux**
| Fournisseur | Local ? | Description |
|-----------|--------|-----------------------------------------------------------|
| ollama | Oui | Exécute LLM localement facilement en utilisant ollama |
| lm-studio | Oui | Exécute LLM localement avec LM studio (définir `provider_name` = `lm-studio`)|
| openai | Oui | Utilise une API compatible avec openai (ex: serveur llama.cpp) |
Prochaine étape: [Démarrer les services et exécuter AgenticSeek](#démarrer-les-services-et-exécuter)
*Si vous rencontrez des problèmes, consultez la section [Dépannage](#dépannage).*
*Si votre matériel ne peut pas exécuter LLM localement, consultez [Configuration pour exécuter avec une API](#configuration-pour-exécuter-avec-une-api).*
*Pour des explications détaillées de `config.ini`, consultez la [section Configuration](#configuration).*
## Configuration pour exécuter avec une API
Cette configuration utilise des fournisseurs de LLM externes basés sur le cloud. Vous devrez obtenir des clés API du service choisi.
**1. Choisissez un fournisseur d'API et obtenez une clé API:**
Consultez la [Liste des fournisseurs d'API](#liste-des-fournisseurs-dapi) ci-dessous. Visitez leurs sites web pour vous inscrire et obtenir des clés API.
**2. Définissez votre clé API comme variable d'environnement:**
* **Linux/macOS:**
Ouvrez un terminal et utilisez la commande `export`. Il est préférable de l'ajouter au fichier de configuration de votre shell (ex: `~/.bashrc`, `~/.zshrc`) pour qu'elle soit persistante.
```sh
export PROVIDER_API_KEY="your_api_key_here"
# Remplacez PROVIDER_API_KEY par le nom de variable spécifique, ex: OPENAI_API_KEY, GOOGLE_API_KEY
```
Exemple TogetherAI:
```sh
export TOGETHER_API_KEY="xxxxxxxxxxxxxxxxxxxxxx"
```
* **Windows:**
* **Invite de commandes (temporaire pour la session actuelle):**
```cmd
set PROVIDER_API_KEY=your_api_key_here
```
* **PowerShell (temporaire pour la session actuelle):**
```powershell
$env:PROVIDER_API_KEY="your_api_key_here"
```
* **Permanent:** Recherchez "variables d'environnement" dans la barre de recherche Windows, cliquez sur "Modifier les variables d'environnement système", puis sur le bouton "Variables d'environnement...". Ajoutez une nouvelle variable utilisateur avec le nom approprié (ex: `OPENAI_API_KEY`) et votre clé comme valeur.
*(Pour plus de détails, consultez la FAQ: [Comment configurer une clé API ?](#comment-configurer-une-clé-api)).*
**3. Mettez à jour `config.ini`:**
```ini
[MAIN]
is_local = False
provider_name = openai # ou google, deepseek, togetherAI, huggingface
provider_model = gpt-3.5-turbo # ou gemini-1.5-flash, deepseek-chat, mistralai/Mixtral-8x7B-Instruct-v0.1, etc.
provider_server_address = # Lorsque is_local = False, généralement ignoré ou peut être laissé vide pour la plupart des API
# ... autres configurations ...
```
*Avertissement:* Assurez-vous qu'il n'y a pas d'espaces à la fin des valeurs dans config.
**Liste des fournisseurs d'API**
| Fournisseur | `provider_name` | Local ? | Description | Lien de clé API (exemple) |
|--------------|-----------------|--------|---------------------------------------------------|---------------------------------------------|
| OpenAI | `openai` | Non | Utilise les modèles ChatGPT via l'API OpenAI. | [platform.openai.com/signup](https://platform.openai.com/signup) |
| Google Gemini| `google` | Non | Utilise les modèles Google Gemini via Google AI Studio. | [aistudio.google.com/keys](https://aistudio.google.com/keys) |
| Deepseek | `deepseek` | Non | Utilise les modèles Deepseek via leur API. | [platform.deepseek.com](https://platform.deepseek.com) |
| Hugging Face | `huggingface` | Non | Utilise les modèles du Hugging Face Inference API. | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) |
| TogetherAI | `togetherAI` | Non | Utilise divers modèles open source via l'API TogetherAI.| [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys) |
*Note:*
* Nous ne recommandons pas d'utiliser `gpt-4o` ou d'autres modèles OpenAI pour la navigation web complexe et la planification de tâches, car l'optimisation actuelle des prompts cible des modèles comme Deepseek.
* Les tâches de codage/bash peuvent échouer avec Gemini, car il a tendance à ignorer notre format de prompt optimisé pour Deepseek r1.
* Lorsque `is_local = False`, `provider_server_address` dans `config.ini` n'est généralement pas utilisé, car les endpoints d'API sont généralement gérés par les bibliothèques du fournisseur correspondant.
Prochaine étape: [Démarrer les services et exécuter AgenticSeek](#démarrer-les-services-et-exécuter)
*Si vous rencontrez des problèmes, consultez la section **Problèmes connus***
*Pour des explications détaillées du fichier de configuration, consultez la **section Configuration**.*
---
## Démarrer les services et exécuter
Par défaut, AgenticSeek s'exécute entièrement dans Docker.
**Option 1:** Exécuter dans Docker avec interface web:
Démarrez les services nécessaires. Cela démarrera tous les services du docker-compose.yml, y compris:
- searxng
- redis (requis pour searxng)
- frontend
- backend (si vous utilisez `full` pour l'interface web)
```sh
./start_services.sh full # MacOS
start start_services.cmd full # Windows
```
**Avertissement:** Cette étape téléchargera et chargera toutes les images Docker, ce qui peut prendre jusqu'à 30 minutes. Après avoir démarré les services, attendez que le service backend soit complètement opérationnel (vous devriez voir **backend: "GET /health HTTP/1.1" 200 OK** dans les logs) avant d'envoyer des messages. Lors du premier démarrage, le service backend peut prendre 5 minutes pour démarrer.
Allez à `http://localhost:3000/` et vous devriez voir l'interface web.
*Dépannage du démarrage des services:* Si ces scripts échouent, assurez-vous que Docker Engine fonctionne et que Docker Compose (V2, `docker compose`) est correctement installé. Vérifiez les messages d'erreur dans la sortie du terminal. Consultez [FAQ: Aide ! J'obtiens des erreurs lors de l'exécution d'AgenticSeek ou de ses scripts.](#faq-dépannage)
**Option 2:** Mode CLI:
Pour exécuter avec l'interface CLI, vous devez installer les packages sur l'hôte:
```sh
./install.sh
./install.bat # windows
```
Ensuite, vous devez changer SEARXNG_BASE_URL dans `config.ini` en:
```sh
SEARXNG_BASE_URL="http://localhost:8080"
```
Démarrez les services nécessaires. Cela démarrera certains services du docker-compose.yml, y compris:
- searxng
- redis (requis pour searxng)
- frontend
```sh
./start_services.sh # MacOS
start start_services.cmd # Windows
```
Exécutez: uv run: `uv run python -m ensurepip` pour vous assurer que uv a pip activé.
Utilisez CLI: `uv run cli.py`
---
## Utilisation
Assurez-vous que les services fonctionnent avec `./start_services.sh full` puis allez à `localhost:3000` pour l'interface web.
Vous pouvez également utiliser la parole vers texte en définissant `listen = True`. Uniquement pour le mode CLI.
Pour quitter, dites/tapez simplement `goodbye`.
Quelques exemples d'utilisation:
> *Fais un jeu de serpent en python !*
> *Recherche sur le web les meilleurs cafés à Rennes, France, et sauvegarde une liste de trois avec leurs adresses dans rennes_cafes.txt.*
> *Écris un programme Go pour calculer la factorielle d'un nombre, sauvegarde-le comme factorial.go dans ton workspace*
> *Recherche dans le dossier summer_pictures tous les fichiers JPG, renomme-les avec la date d'aujourd'hui et sauvegarde la liste des fichiers renommés dans photos_list.txt*
> *Recherche en ligne les films de science-fiction populaires de 2024 et choisis-en trois à regarder ce soir. Sauvegarde la liste dans movie_night.txt.*
> *Recherche sur le web les derniers articles d'actualité sur l'IA de 2025, sélectionne-en trois et écris un script Python pour extraire les titres et résumés. Sauvegarde le script comme news_scraper.py et les résumés dans ai_news.txt dans /home/projects*
> *Vendredi, recherche sur le web une API gratuite de prix d'actions, inscris-toi avec supersuper7434567@gmail.com et écris un script Python pour obtenir les prix quotidiens de Tesla en utilisant l'API, en sauvegardant les résultats dans stock_prices.csv*
*Notez que le remplissage de formulaires est toujours expérimental et peut échouer.*
Après avoir saisi votre requête, AgenticSeek attribuera le meilleur agent pour la tâche.
Comme il s'agit d'un prototype initial, le système de routage des agents peut ne pas toujours attribuer l'agent correct à votre requête.
Par conséquent, soyez très explicite sur ce que vous voulez et comment l'IA pourrait procéder, par exemple si vous voulez qu'elle effectue une recherche web, ne dites pas:
`Connais-tu de bons pays pour voyager seul ?`
Dites plutôt:
`Effectue une recherche web et découvre quels sont les meilleurs pays pour voyager seul`
---
## **Configuration pour exécuter LLM sur votre propre serveur**
Si vous avez un ordinateur puissant ou un serveur auquel vous pouvez accéder, mais que vous voulez l'utiliser depuis votre ordinateur portable, vous pouvez choisir d'exécuter le LLM sur un serveur distant en utilisant notre serveur llm personnalisé.
Sur votre "serveur" qui exécutera le modèle d'IA, obtenez l'adresse IP
```sh
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1 # IP locale
curl https://ipinfo.io/ip # IP publique
```
Note: Pour Windows ou macOS, utilisez ipconfig ou ifconfig pour trouver l'adresse IP.
Clonez le dépôt et entrez dans le dossier `server/`.
```sh
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
cd agenticSeek/llm_server/
```
Installez les exigences spécifiques au serveur:
```sh
pip3 install -r requirements.txt
```
Exécutez le script du serveur.
```sh
python3 app.py --provider ollama --port 3333
```
Vous pouvez choisir d'utiliser `ollama` et `llamacpp` comme service LLM.
Maintenant sur votre ordinateur personnel:
Changez le fichier `config.ini` pour définir `provider_name` sur `server` et `provider_model` sur `deepseek-r1:xxb`.
Définissez `provider_server_address` sur l'adresse IP de la machine qui exécutera le modèle.
```sh
[MAIN]
is_local = False
provider_name = server
provider_model = deepseek-r1:70b
provider_server_address = http://x.x.x.x:3333
```
Prochaine étape: [Démarrer les services et exécuter AgenticSeek](#démarrer-les-services-et-exécuter)
---
## Parole vers Texte
Avertissement: La speech-to-text ne fonctionne qu'en mode CLI pour le moment.
Notez que la parole vers texte ne fonctionne qu'en anglais pour le moment.
La fonctionnalité de parole vers texte est désactivée par défaut. Pour l'activer, définissez listen sur True dans le fichier config.ini:
```
listen = True
```
Lorsqu'elle est activée, la fonction de parole vers texte écoute un mot-clé de déclenchement, qui est le nom de l'agent, avant de traiter votre entrée. Vous pouvez personnaliser le nom de l'agent en mettant à jour la valeur `agent_name` dans *config.ini*:
```
agent_name = Friday
```
Pour une meilleure reconnaissance, nous recommandons d'utiliser un nom commun en anglais comme "John" ou "Emma" comme nom d'agent.
Une fois que vous voyez la transcription commencer à apparaître, dites le nom de l'agent à haute voix pour le réveiller (ex: "Friday").
Dites votre requête clairement.
Terminez votre demande par une phrase de confirmation pour indiquer au système de continuer. Les exemples de phrases de confirmation incluent:
```
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
```
## Configuration
Exemple de configuration:
```
[MAIN]
is_local = True
provider_name = ollama
provider_model = deepseek-r1:32b
provider_server_address = http://127.0.0.1:11434 # Exemple Ollama; LM-Studio utilise http://127.0.0.1:1234
agent_name = Friday
recover_last_session = False
save_session = False
speak = False
listen = False
jarvis_personality = False
languages = en zh # Liste des langues pour TTS et routage potentiel.
[BROWSER]
headless_browser = False
stealth_mode = False
```
**Explication des paramètres de `config.ini`**:
* **Section `[MAIN]`:**
* `is_local`: `True` si vous utilisez des fournisseurs de LLM locaux (Ollama, LM-Studio, serveur local compatible OpenAI) ou l'option de serveur auto-hébergé. `False` si vous utilisez des API basées sur le cloud (OpenAI, Google, etc.).
* `provider_name`: Spécifie le fournisseur de LLM.
* Options locales: `ollama`, `lm-studio`, `openai` (pour serveur local compatible OpenAI), `server` (pour configuration de serveur auto-hébergé).
* Options d'API: `openai`, `google`, `deepseek`, `huggingface`, `togetherAI`.
* `provider_model`: Nom ou ID spécifique du modèle du fournisseur sélectionné (ex: `deepseekcoder:6.7b` pour Ollama, `gpt-3.5-turbo` pour API OpenAI, `mistralai/Mixtral-8x7B-Instruct-v0.1` pour TogetherAI).
* `provider_server_address`: L'adresse de votre fournisseur de LLM.
* Pour les fournisseurs locaux: ex: `http://127.0.0.1:11434` pour Ollama, `http://127.0.0.1:1234` pour LM-Studio.
* Pour le type de fournisseur `server`: L'adresse de votre serveur LLM auto-hébergé (ex: `http://your_server_ip:3333`).
* Pour les API cloud (`is_local = False`): Ceci est généralement ignoré ou peut être laissé vide, car les endpoints d'API sont généralement gérés par les bibliothèques clientes.
* `agent_name`: Le nom de l'assistant IA (ex: Friday). Si activé, utilisé comme mot de déclenchement pour la parole vers texte.
* `recover_last_session`: `True` pour tenter de récupérer l'état de la session précédente, `False` pour recommencer.
* `save_session`: `True` pour sauvegarder l'état de la session actuelle pour une récupération potentielle, `False` sinon.
* `speak`: `True` pour activer la sortie vocale de texte vers parole, `False` pour désactiver.
* `listen`: `True` pour activer l'entrée vocale de parole vers texte (uniquement mode CLI), `False` pour désactiver.
* `work_dir`: **Critique:** Le répertoire où AgenticSeek lira/écrira des fichiers. **Assurez-vous que ce chemin est valide et accessible sur votre système.**
* `jarvis_personality`: `True` pour utiliser des invites système plus "Jarvis-like" (expérimental), `False` pour utiliser des invites standard.
* `languages`: Liste de langues séparées par des virgules (ex: `en, zh, fr`). Utilisé pour la sélection de voix TTS (première par défaut) et peut aider le routeur LLM. Pour éviter les inefficacités du routeur, évitez d'utiliser trop de langues ou des langues très similaires.
* **Section `[BROWSER]`:**
* `headless_browser`: `True` pour exécuter le navigateur automatisé sans fenêtre visible (recommandé pour l'interface web ou l'utilisation non interactive). `False` pour afficher la fenêtre du navigateur (utile pour le mode CLI ou le débogage).
* `stealth_mode`: `True` pour activer des mesures qui rendent plus difficile la détection de l'automatisation du navigateur. Peut nécessiter l'installation manuelle d'extensions de navigateur comme anticaptcha.
Cette section résume les types de fournisseurs de LLM pris en charge. Configurez-les dans `config.ini`.
**Fournisseurs locaux (fonctionnant sur votre propre matériel):**
| Nom du fournisseur dans config.ini | `is_local` | Description | Section de configuration |
|-------------------------------|------------|-----------------------------------------------------------------------------|------------------------------------------------------------------|
| `ollama` | `True` | Fournit LLM localement facilement en utilisant Ollama. | [Configuration pour exécuter LLM localement sur votre machine](#configuration-pour-exécuter-llm-localement-sur-votre-machine) |
| `lm-studio` | `True` | Fournit LLM localement avec LM-Studio. | [Configuration pour exécuter LLM localement sur votre machine](#configuration-pour-exécuter-llm-localement-sur-votre-machine) |
| `openai` (pour serveur local) | `True` | Connectez-vous à un serveur local exposant une API compatible OpenAI (ex: llama.cpp). | [Configuration pour exécuter LLM localement sur votre machine](#configuration-pour-exécuter-llm-localement-sur-votre-machine) |
| `server` | `False` | Connectez-vous au serveur LLM auto-hébergé d'AgenticSeek fonctionnant sur une autre machine. | [Configuration pour exécuter LLM sur votre propre serveur](#configuration-pour-exécuter-llm-sur-votre-propre-serveur) |
**Fournisseurs d'API (basés sur le cloud):**
| Nom du fournisseur dans config.ini | `is_local` | Description | Section de configuration |
|-------------------------------|------------|--------------------------------------------------|-----------------------------------------------------|
| `openai` | `False` | Utilise l'API officielle d'OpenAI (ex: GPT-3.5, GPT-4). | [Configuration pour exécuter avec une API](#configuration-pour-exécuter-avec-une-api) |
| `google` | `False` | Utilise les modèles Google Gemini via API. | [Configuration pour exécuter avec une API](#configuration-pour-exécuter-avec-une-api) |
| `deepseek` | `False` | Utilise l'API officielle de Deepseek. | [Configuration pour exécuter avec une API](#configuration-pour-exécuter-avec-une-api) |
| `huggingface` | `False` | Utilise Hugging Face Inference API. | [Configuration pour exécuter avec une API](#configuration-pour-exécuter-avec-une-api) |
| `togetherAI` | `False` | Utilise divers modèles ouverts via l'API TogetherAI. | [Configuration pour exécuter avec une API](#configuration-pour-exécuter-avec-une-api) |
---
## Dépannage
Si vous rencontrez des problèmes, cette section fournit des conseils.
# Problèmes connus
## Problèmes de ChromeDriver
**Exemple d'erreur:** `SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version XXX`
### Cause racine
L'incompatibilité de version de ChromeDriver se produit lorsque:
1. La version de ChromeDriver que vous avez installée ne correspond pas à la version du navigateur Chrome
2. Dans les environnements Docker, `undetected_chromedriver` peut télécharger sa propre version de ChromeDriver, contournant les binaires montés
### Étapes de résolution
#### 1. Vérifiez votre version de Chrome
Ouvrez Google Chrome → `Paramètres > À propos de Chrome` pour trouver votre version (ex: "Version 134.0.6998.88")
#### 2. Téléchargez ChromeDriver correspondant
**Pour Chrome 115 et versions ultérieures:** Utilisez [Chrome for Testing API](https://googlechromelabs.github.io/chrome-for-testing/)
- Visitez le tableau de disponibilité de Chrome for Testing
- Trouvez votre version de Chrome ou la correspondance disponible la plus proche
- Téléchargez ChromeDriver pour votre système d'exploitation (utilisez Linux64 pour les environnements Docker)
**Pour les anciennes versions de Chrome:** Utilisez [Téléchargements hérités de ChromeDriver](https://chromedriver.chromium.org/downloads)

#### 3. Installez ChromeDriver (choisissez une méthode)
**Méthode A: Répertoire racine du projet (recommandé pour Docker)**
```bash
# Placez le binaire chromedriver téléchargé dans le répertoire racine du projet
cp path/to/downloaded/chromedriver ./chromedriver
chmod +x ./chromedriver # Rendez-le exécutable sur Linux/macOS
```
**Méthode B: PATH système**
```bash
# Linux/macOS
sudo mv chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver
# Windows: Placez chromedriver.exe dans un dossier du PATH
```
#### 4. Vérifiez l'installation
```bash
# Testez la version de ChromeDriver
./chromedriver --version
# Ou s'il est dans PATH:
chromedriver --version
```
### Instructions spécifiques à Docker
⚠️ **Important pour les utilisateurs de Docker:**
- La méthode de montage de volumes Docker peut ne pas fonctionner avec le mode furtif (`undetected_chromedriver`)
- **Solution:** Placez ChromeDriver dans le répertoire racine du projet en tant que `./chromedriver`
- L'application le détectera automatiquement et utilisera ce binaire
- Vous devriez voir dans les logs: `"Using ChromeDriver from project root: ./chromedriver"`
### Conseils de dépannage
1. **Toujours une incompatibilité de version ?**
- Vérifiez que ChromeDriver est exécutable: `ls -la ./chromedriver`
- Vérifiez la version de ChromeDriver: `./chromedriver --version`
- Assurez-vous qu'elle correspond à votre version du navigateur Chrome
2. **Problèmes avec le conteneur Docker ?**
- Vérifiez les logs du backend: `docker logs backend`
- Recherchez le message: `"Using ChromeDriver from project root"`
- S'il n'est pas trouvé, vérifiez que le fichier existe et est exécutable
3. **Versions de Chrome for Testing**
- Utilisez une correspondance exacte lorsque possible
- Pour la version 134.0.6998.88, utilisez ChromeDriver 134.0.6998.165 (la version disponible la plus proche)
- Le numéro de version principal doit correspondre (134 = 134)
### Matrice de compatibilité des versions
| Version de Chrome | Version de ChromeDriver | Statut |
|----------------|---------------------|---------|
| 134.0.6998.x | 134.0.6998.165 | ✅ Disponible |
| 133.0.6943.x | 133.0.6943.141 | ✅ Disponible |
| 132.0.6834.x | 132.0.6834.159 | ✅ Disponible |
*Pour la compatibilité la plus récente, consultez le [Tableau de Chrome for Testing](https://googlechromelabs.github.io/chrome-for-testing/)*
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
Current browser version is 134.0.6998.89 with binary path`
Cela se produit si votre navigateur et la version de chromedriver ne correspondent pas.
Vous devez naviguer pour télécharger la dernière version:
https://developer.chrome.com/docs/chromedriver/downloads
Si vous utilisez Chrome version 115 ou supérieure, allez à:
https://googlechromelabs.github.io/chrome-for-testing/
et téléchargez la version de chromedriver correspondant à votre système d'exploitation.

Si cette section est incomplète, ouvrez un issue.
## Problèmes d'adaptateurs de connexion
```
Exception: Provider lm-studio failed: HTTP request failed: No connection adapters were found for '127.0.0.1:1234/v1/chat/completions'` (note: le port peut varier)
```
* **Cause:** Il manque le préfixe `http://` dans `provider_server_address` pour `lm-studio` (ou un autre serveur local compatible OpenAI similaire) dans `config.ini`, ou il pointe vers le mauvais port.
* **Solution:**
* Assurez-vous que l'adresse inclut `http://`. LM-Studio utilise généralement `http://127.0.0.1:1234` par défaut.
* `config.ini` correct: `provider_server_address = http://127.0.0.1:1234` (ou votre port réel du serveur LM-Studio).
## URL de base de SearxNG non fournie
```
raise ValueError("SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.")
ValueError: SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.`
```
Cela peut se produire si vous exécutez le mode CLI avec une URL de base de searxng incorrecte.
SEARXNG_BASE_URL doit différer selon que vous exécutez dans Docker ou sur l'hôte:
**Exécution sur l'hôte:** `SEARXNG_BASE_URL="http://localhost:8080"`
**Exécution complètement dans Docker (interface web):** `SEARXNG_BASE_URL="http://searxng:8080"`
## FAQ
**Q: De quel matériel ai-je besoin ?**
| Taille du modèle | GPU | Commentaires |
|-----------|--------|-----------------------------------------------------------|
| 7B | 8GB VRAM | ⚠️ Non recommandé. Performances médiocres, hallucinations fréquentes, les agents de planification peuvent échouer. |
| 14B | 12 GB VRAM (ex: RTX 3060) | ✅ Utilisable pour des tâches simples. Peut avoir des difficultés avec la navigation web et la planification de tâches. |
| 32B | 24+ GB VRAM (ex: RTX 4090) | 🚀 Réussit la plupart des tâches, peut encore avoir des difficultés avec la planification de tâches |
| 70B+ | 48+ GB VRAM | 💪 Excellent. Recommandé pour les cas d'utilisation avancés. |
**Q: Que faire si je rencontre des erreurs ?**
Assurez-vous que le local fonctionne (`ollama serve`), que votre `config.ini` correspond à votre fournisseur et que les dépendances sont installées. Si rien ne fonctionne, n'hésitez pas à ouvrir un issue.
**Q: Peut-il vraiment fonctionner à 100% localement ?**
Oui, avec les fournisseurs Ollama, lm-studio ou server, tous les modèles de parole vers texte, LLM et texte vers parole fonctionnent localement. Les options non locales (OpenAI ou autres API) sont optionnelles.
**Q: Pourquoi devrais-je utiliser AgenticSeek quand j'ai Manus ?**
Contrairement à Manus, AgenticSeek privilégie l'indépendance des systèmes externes, vous donnant plus de contrôle, de confidentialité et évitant les coûts d'API.
**Q: Qui est derrière ce projet ?**
Ce projet a été créé par moi, avec deux amis comme mainteneurs et des contributeurs de la communauté open source sur GitHub. Nous sommes juste des individus passionnés, pas une startup, ni affiliés à aucune organisation.
Tout compte AgenticSeek sur X autre que mon compte personnel (https://x.com/Martin993886460) est un imposteur.
## Contribuer
Nous recherchons des développeurs pour améliorer AgenticSeek ! Consultez les problèmes ouverts ou les discussions.
[Guide de contribution](./docs/CONTRIBUTING.md)
## Sponsors:
Vous voulez améliorer les capacités d'AgenticSeek avec des fonctionnalités comme la recherche de vols, la planification de voyages ou l'obtention des meilleures offres d'achat ? Envisagez d'utiliser SerpApi pour créer des outils personnalisés qui débloquent plus de fonctionnalités de type Jarvis. Avec SerpApi, vous pouvez accélérer votre agent pour des tâches professionnelles tout en gardant le contrôle total.
Consultez [Contributing.md](./docs/CONTRIBUTING.md) pour apprendre comment intégrer des outils personnalisés !
### **Sponsors**:
- [tatra-labs](https://github.com/tatra-labs)
## Mainteneurs:
> [Fosowl](https://github.com/Fosowl) | Heure de Paris
> [antoineVIVIES](https://github.com/antoineVIVIES) | Heure de Taipei
## Remerciements spéciaux:
> [tcsenpai](https://github.com/tcsenpai) et [plitc](https://github.com/plitc) pour avoir aidé à la dockerisation du backend
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
================================================
FILE: README_JP.md
================================================
# AgenticSeek: Manusのプライベートでローカルな代替品
English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Français](./README_FR.md) | [日本語](./README_JP.md) | [Português (Brasil)](./README_PTBR.md) | [Español](./README_ES.md) | [Türkçe](./README_TR.md)
*Um assistente de IA com reconhecimento de voz que é uma **alternativa 100% local ao Manus AI**, navega autonomamente na web, escreve código e planeja tarefas enquanto mantém todos os dados no seu dispositivo. Projetado para modelos de raciocínio local, funciona inteiramente no seu hardware, garantindo total privacidade e zero dependência de nuvem.*
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460) [](https://github.com/Fosowl/agenticSeek/stargazers)
### Por que escolher o AgenticSeek?
* 🔒 Totalmente Local & Privado - Tudo funciona na sua máquina, sem nuvem, sem compartilhamento de dados. Seus arquivos, conversas e pesquisas permanecem privados.
* 🌐 Navegação Web Inteligente - O AgenticSeek pode navegar na Internet autonomamente: pesquisar, ler, extrair informações, preencher formulários web, tudo sem intervenção manual.
* 💻 Assistente de Programação Autônomo - Precisa de código? Ele pode escrever, depurar e executar programas em Python, C, Go, Java e muito mais, sem supervisão.
* 🧠 Seleção Inteligente de Agentes - Você pergunta, ele escolhe automaticamente o melhor agente para a tarefa. Como ter uma equipe de especialistas sempre disponível.
* 📋 Planeja e Executa Tarefas Complexas - Desde o planejamento de viagens até projetos complexos, ele pode decompor grandes tarefas em etapas e completá-las usando múltiplos agentes de IA.
* 🎙️ Suporte de Voz - Voz clara, rápida e futurista com reconhecimento de voz, permitindo que você converse como com sua IA pessoal de filme de ficção científica. (Em desenvolvimento)
### **Demo**
> *Você pode pesquisar o projeto agenticSeek, aprender quais habilidades são necessárias e, em seguida, abrir CV_candidates.zip e me dizer quais correspondem melhor ao projeto?*
https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316
Aviso: Esta demonstração e todos os arquivos que aparecem (ex: CV_candidates.zip) são totalmente fictícios. Não somos uma empresa, estamos procurando contribuidores de código aberto, não candidatos.
> 🛠⚠️️ **Trabalho Ativo em Andamento**
> 🙏 Este projeto começou como um projeto paralelo e não tem roadmap nem financiamento. Cresceu muito além das expectativas ao aparecer no GitHub Trending. Contribuições, comentários e paciência são profundamente apreciados.
## Pré-requisitos
Antes de começar, certifique-se de ter instalado:
* **Git:** Para clonar o repositório. [Baixar Git](https://git-scm.com/downloads)
* **Python 3.10.x:** Python 3.10.x é altamente recomendado. Outras versões podem causar erros de dependência. [Baixar Python 3.10](https://www.python.org/downloads/release/python-3100/) (selecione a versão 3.10.x).
* **Docker Engine & Docker Compose:** Para executar serviços empacotados como SearxNG.
* Instalar Docker Desktop (inclui Docker Compose V2): [Windows](https://docs.docker.com/desktop/install/windows-install/) | [Mac](https://docs.docker.com/desktop/install/mac-install/) | [Linux](https://docs.docker.com/desktop/install/linux-install/)
* Ou instalar Docker Engine e Docker Compose separadamente no Linux: [Docker Engine](https://docs.docker.com/engine/install/) | [Docker Compose](https://docs.docker.com/compose/install/) (certifique-se de instalar Compose V2, por exemplo `sudo apt-get install docker-compose-plugin`).
### 1. **Clonar o repositório e configurar**
```sh
git clone https://github.com/Fosowl/agenticSeek.git
cd agenticSeek
mv .env.example .env
```
### 2. Modificar o conteúdo do arquivo .env
```sh
SEARXNG_BASE_URL="http://searxng:8080" # Se você executar no modo CLI no host, use http://127.0.0.1:8080
REDIS_BASE_URL="redis://redis:6379/0"
WORK_DIR="/Users/mlg/Documents/workspace_for_ai"
OLLAMA_PORT="11434"
LM_STUDIO_PORT="1234"
CUSTOM_ADDITIONAL_LLM_PORT="11435"
OPENAI_API_KEY='optional'
DEEPSEEK_API_KEY='optional'
OPENROUTER_API_KEY='optional'
TOGETHER_API_KEY='optional'
GOOGLE_API_KEY='optional'
ANTHROPIC_API_KEY='optional'
```
Atualize o arquivo `.env` conforme necessário:
- **SEARXNG_BASE_URL**: Mantenha inalterado, a menos que você execute no modo CLI no host.
- **REDIS_BASE_URL**: Mantenha inalterado
- **WORK_DIR**: Caminho para o diretório de trabalho local. O AgenticSeek poderá ler e interagir com esses arquivos.
- **OLLAMA_PORT**: Número da porta para o serviço Ollama.
- **LM_STUDIO_PORT**: Número da porta para o serviço LM Studio.
- **CUSTOM_ADDITIONAL_LLM_PORT**: Porta para qualquer serviço LLM personalizado adicional.
**As chaves de API são completamente opcionais para aqueles que optam por executar LLM localmente, que é o objetivo principal deste projeto. Deixe-as vazias se você tiver hardware suficiente.**
### 3. **Iniciar o Docker**
Certifique-se de que o Docker está instalado e funcionando no seu sistema. Você pode iniciar o Docker com os seguintes comandos:
- **Linux/macOS:**
Abra um terminal e execute:
```sh
sudo systemctl start docker
```
Ou inicie o Docker Desktop a partir do menu de aplicativos, se instalado.
- **Windows:**
Inicie o Docker Desktop a partir do menu Iniciar.
Você pode verificar se o Docker está funcionando executando:
```sh
docker info
```
Se você vir informações sobre sua instalação do Docker, ele está funcionando corretamente.
Consulte a [Lista de provedores locais](#lista-de-provedores-locais) abaixo para um resumo.
Próxima etapa: [Executar o AgenticSeek localmente](#iniciar-os-serviços-e-executar)
*Se você encontrar problemas, consulte a seção [Solução de problemas](#solução-de-problemas).*
*Se seu hardware não puder executar LLM localmente, consulte [Configuração para executar com uma API](#configuração-para-executar-com-uma-api).*
*Para explicações detalhadas do `config.ini`, consulte a [seção Configuração](#configuração).*
---
## Configuração para executar LLM localmente na sua máquina
**Requisitos de hardware:**
Para executar LLM localmente, você precisará de hardware suficiente. No mínimo, uma GPU capaz de executar Magistral, Qwen ou Deepseek 14B é necessária. Consulte o FAQ para recomendações detalhadas de modelo/desempenho.
**Configure seu provedor local**
Inicie seu provedor local, por exemplo com ollama:
```sh
ollama serve
```
Consulte a lista de provedores locais suportados abaixo.
**Atualizar config.ini**
Altere o arquivo config.ini para definir provider_name como um provedor suportado e provider_model como um LLM suportado pelo seu provedor. Recomendamos modelos de raciocínio como *Magistral* ou *Deepseek*.
Consulte o **FAQ** no final do README para o hardware necessário.
```sh
[MAIN]
is_local = True # Se você está executando localmente ou com um provedor remoto.
provider_name = ollama # ou lm-studio, openai, etc.
provider_model = deepseek-r1:14b # escolha um modelo compatível com seu hardware
provider_server_address = 127.0.0.1:11434
agent_name = Jarvis # o nome da sua IA
recover_last_session = True # recuperar a sessão anterior
save_session = True # memorizar a sessão atual
speak = False # texto para fala
listen = False # fala para texto, apenas para CLI, experimental
jarvis_personality = False # usar uma personalidade mais "Jarvis" (experimental)
languages = en zh # Lista de idiomas, TTS usará o primeiro da lista por padrão
[BROWSER]
headless_browser = True # mantenha inalterado, a menos que use CLI no host.
stealth_mode = True # Use selenium indetectável para reduzir a detecção do navegador
```
**Aviso**:
- O formato do arquivo `config.ini` não suporta comentários.
Não copie e cole diretamente a configuração de exemplo, pois os comentários causarão erros. Em vez disso, modifique manualmente o arquivo `config.ini` com sua configuração desejada, sem comentários.
- *NÃO* defina provider_name como `openai` se você estiver usando LM-studio para executar LLM. Use-o como `lm-studio`.
- Alguns provedores (ex: lm-studio) exigem `http://` antes do IP. Exemplo: `http://127.0.0.1:1234`
**Lista de provedores locais**
| Provedor | Local ? | Descrição |
|-----------|--------|-----------------------------------------------------------|
| ollama | Sim | Executa LLM localmente facilmente usando ollama |
| lm-studio | Sim | Executa LLM localmente com LM studio (defina `provider_name` = `lm-studio`)|
| openai | Sim | Use uma API compatível com openai (ex: servidor llama.cpp) |
Próxima etapa: [Iniciar os serviços e executar o AgenticSeek](#iniciar-os-serviços-e-executar)
*Se você encontrar problemas, consulte a seção [Solução de problemas](#solução-de-problemas).*
*Se seu hardware não puder executar LLM localmente, consulte [Configuração para executar com uma API](#configuração-para-executar-com-uma-api).*
*Para explicações detalhadas do `config.ini`, consulte a [seção Configuração](#configuração).*
## Configuração para executar com uma API
Esta configuração usa provedores de LLM externos baseados em nuvem. Você precisará obter chaves de API do serviço escolhido.
**1. Escolha um provedor de API e obtenha uma chave de API:**
Consulte a [Lista de provedores de API](#lista-de-provedores-de-api) abaixo. Visite seus sites para se inscrever e obter chaves de API.
**2. Defina sua chave de API como variável de ambiente:**
* **Linux/macOS:**
Abra um terminal e use o comando `export`. É melhor adicioná-lo ao arquivo de configuração do seu shell (ex: `~/.bashrc`, `~/.zshrc`) para que seja persistente.
```sh
export PROVIDER_API_KEY="your_api_key_here"
# Substitua PROVIDER_API_KEY pelo nome de variável específico, ex: OPENAI_API_KEY, GOOGLE_API_KEY
```
Exemplo TogetherAI:
```sh
export TOGETHER_API_KEY="xxxxxxxxxxxxxxxxxxxxxx"
```
* **Windows:**
* **Prompt de comando (temporário para a sessão atual):**
```cmd
set PROVIDER_API_KEY=your_api_key_here
```
* **PowerShell (temporário para a sessão atual):**
```powershell
$env:PROVIDER_API_KEY="your_api_key_here"
```
* **Permanente:** Pesquise "variáveis de ambiente" na barra de pesquisa do Windows, clique em "Editar variáveis de ambiente do sistema" e depois no botão "Variáveis de ambiente...". Adicione uma nova variável de usuário com o nome apropriado (ex: `OPENAI_API_KEY`) e sua chave como valor.
*(Para mais detalhes, consulte o FAQ: [Como configurar uma chave de API?](#como-configurar-uma-chave-de-api)).*
**3. Atualize `config.ini`:**
```ini
[MAIN]
is_local = False
provider_name = openai # ou google, deepseek, togetherAI, huggingface
provider_model = gpt-3.5-turbo # ou gemini-1.5-flash, deepseek-chat, mistralai/Mixtral-8x7B-Instruct-v0.1, etc.
provider_server_address = # Quando is_local = False, geralmente ignorado ou pode ser deixado vazio para a maioria das APIs
# ... outras configurações ...
```
*Aviso:* Certifique-se de que não há espaços no final dos valores no config.
**Lista de provedores de API**
| Provedor | `provider_name` | Local ? | Descrição | Link da chave de API (exemplo) |
|--------------|-----------------|--------|---------------------------------------------------|---------------------------------------------|
| OpenAI | `openai` | Não | Use os modelos ChatGPT via API OpenAI. | [platform.openai.com/signup](https://platform.openai.com/signup) |
| Google Gemini| `google` | Não | Use os modelos Google Gemini via Google AI Studio. | [aistudio.google.com/keys](https://aistudio.google.com/keys) |
| Deepseek | `deepseek` | Não | Use os modelos Deepseek via sua API. | [platform.deepseek.com](https://platform.deepseek.com) |
| Hugging Face | `huggingface` | Não | Use modelos do Hugging Face Inference API. | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) |
| TogetherAI | `togetherAI` | Não | Use vários modelos open source via API TogetherAI.| [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys) |
*Nota:*
* Não recomendamos usar `gpt-4o` ou outros modelos OpenAI para navegação web complexa e planejamento de tarefas, pois a otimização atual de prompts visa modelos como Deepseek.
* Tarefas de codificação/bash podem falhar com Gemini, pois tende a ignorar nosso formato de prompt otimizado para Deepseek r1.
* Quando `is_local = False`, `provider_server_address` no `config.ini` geralmente não é usado, pois os endpoints de API são geralmente gerenciados pelas bibliotecas do provedor correspondente.
Próxima etapa: [Iniciar os serviços e executar o AgenticSeek](#iniciar-os-serviços-e-executar)
*Se você encontrar problemas, consulte a seção **Problemas conhecidos***
*Para explicações detalhadas do arquivo de configuração, consulte a **seção Configuração**.*
---
## Iniciar os serviços e executar
Por padrão, o AgenticSeek é executado inteiramente no Docker.
**Opção 1:** Executar no Docker com interface web:
Inicie os serviços necessários. Isso iniciará todos os serviços do docker-compose.yml, incluindo:
- searxng
- redis (necessário para searxng)
- frontend
- backend (se você usar `full` para a interface web)
```sh
./start_services.sh full # MacOS
start start_services.cmd full # Windows
```
**Aviso:** Esta etapa baixará e carregará todas as imagens do Docker, o que pode levar até 30 minutos. Depois de iniciar os serviços, aguarde até que o serviço backend esteja totalmente operacional (você deve ver **backend: "GET /health HTTP/1.1" 200 OK** nos logs) antes de enviar mensagens. Na primeira inicialização, o serviço backend pode levar 5 minutos para iniciar.
Vá para `http://localhost:3000/` e você deve ver a interface web.
*Solução de problemas de inicialização de serviços:* Se esses scripts falharem, certifique-se de que o Docker Engine está funcionando e que o Docker Compose (V2, `docker compose`) está instalado corretamente. Verifique as mensagens de erro na saída do terminal. Consulte [FAQ: Ajuda! Estou recebendo erros ao executar o AgenticSeek ou seus scripts.](#faq-solução-de-problemas)
**Opção 2:** Modo CLI:
Para executar com a interface CLI, você precisa instalar os pacotes no host:
```sh
./install.sh
./install.bat # windows
```
Em seguida, você precisa alterar SEARXNG_BASE_URL no `config.ini` para:
```sh
SEARXNG_BASE_URL="http://localhost:8080"
```
Inicie os serviços necessários. Isso iniciará alguns serviços do docker-compose.yml, incluindo:
- searxng
- redis (necessário para searxng)
- frontend
```sh
./start_services.sh # MacOS
start start_services.cmd # Windows
```
Execute: uv run: `uv run python -m ensurepip` para garantir que o uv tenha o pip ativado.
Use CLI: `uv run cli.py`
---
## Uso
Certifique-se de que os serviços estão funcionando com `./start_services.sh full` e vá para `localhost:3000` para a interface web.
Você também pode usar fala para texto definindo `listen = True`. Apenas para o modo CLI.
Para sair, basta dizer/digitar `goodbye`.
Alguns exemplos de uso:
> *Faça um jogo da cobra em python!*
> *Pesquise na web os melhores cafés em Rennes, França, e salve uma lista de três com seus endereços em rennes_cafes.txt.*
> *Escreva um programa Go para calcular o fatorial de um número, salve-o como factorial.go em seu workspace*
> *Pesquise na pasta summer_pictures todos os arquivos JPG, renomeie-os com a data de hoje e salve a lista de arquivos renomeados em photos_list.txt*
> *Pesquise online os filmes de ficção científica populares de 2024 e escolha três para assistir esta noite. Salve a lista em movie_night.txt.*
> *Pesquise na web os últimos artigos de notícias sobre IA de 2025, selecione três e escreva um script Python para extrair os títulos e resumos. Salve o script como news_scraper.py e os resumos em ai_news.txt em /home/projects*
> *Sexta-feira, pesquise na web uma API gratuita de preços de ações, inscreva-se com supersuper7434567@gmail.com e escreva um script Python para obter os preços diários da Tesla usando a API, salvando os resultados em stock_prices.csv*
*Observe que o preenchimento de formulários ainda é experimental e pode falhar.*
Depois de inserir sua consulta, o AgenticSeek atribuirá o melhor agente para a tarefa.
Como este é um protótipo inicial, o sistema de roteamento de agentes pode nem sempre atribuir o agente correto à sua consulta.
Portanto, seja muito explícito sobre o que você quer e como a IA pode proceder, por exemplo, se você quiser que ela faça uma pesquisa na web, não diga:
`Você conhece bons países para viajar sozinho?`
Em vez disso, diga:
`Execute uma pesquisa na web e descubra quais são os melhores países para viajar sozinho`
---
## **Configuração para executar LLM em seu próprio servidor**
Se você tem um computador poderoso ou um servidor que pode acessar, mas quer usá-lo do seu laptop, você pode optar por executar o LLM em um servidor remoto usando nosso servidor llm personalizado.
No seu "servidor" que executará o modelo de IA, obtenha o endereço IP
```sh
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1 # IP local
curl https://ipinfo.io/ip # IP público
```
Nota: Para Windows ou macOS, use ipconfig ou ifconfig para encontrar o endereço IP.
Clone o repositório e entre na pasta `server/`.
```sh
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
cd agenticSeek/llm_server/
```
Instale os requisitos específicos do servidor:
```sh
pip3 install -r requirements.txt
```
Execute o script do servidor.
```sh
python3 app.py --provider ollama --port 3333
```
Você pode escolher usar `ollama` e `llamacpp` como serviço LLM.
Agora no seu computador pessoal:
Altere o arquivo `config.ini` para definir `provider_name` como `server` e `provider_model` como `deepseek-r1:xxb`.
Defina `provider_server_address` como o endereço IP da máquina que executará o modelo.
```sh
[MAIN]
is_local = False
provider_name = server
provider_model = deepseek-r1:70b
provider_server_address = http://x.x.x.x:3333
```
Próxima etapa: [Iniciar os serviços e executar o AgenticSeek](#iniciar-os-serviços-e-executar)
---
## Fala para Texto
Aviso: Fala para texto funciona apenas no modo CLI no momento.
Observe que a fala para texto funciona apenas em inglês no momento.
A funcionalidade de fala para texto está desativada por padrão. Para ativá-la, defina listen como True no arquivo config.ini:
```
listen = True
```
Quando ativada, a funcionalidade de fala para texto ouve uma palavra-chave de gatilho, que é o nome do agente, antes de processar sua entrada. Você pode personalizar o nome do agente atualizando o valor `agent_name` em *config.ini*:
```
agent_name = Friday
```
Para melhor reconhecimento, recomendamos usar um nome comum em inglês como "John" ou "Emma" como nome do agente.
Assim que você vir a transcrição começar a aparecer, diga o nome do agente em voz alta para acordá-lo (ex: "Friday").
Diga sua consulta claramente.
Termine sua solicitação com uma frase de confirmação para indicar ao sistema para continuar. Exemplos de frases de confirmação incluem:
```
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
```
## Configuração
Exemplo de configuração:
```
[MAIN]
is_local = True
provider_name = ollama
provider_model = deepseek-r1:32b
provider_server_address = http://127.0.0.1:11434 # Exemplo Ollama; LM-Studio usa http://127.0.0.1:1234
agent_name = Friday
recover_last_session = False
save_session = False
speak = False
listen = False
jarvis_personality = False
languages = en zh # Lista de idiomas para TTS e roteamento potencial.
[BROWSER]
headless_browser = False
stealth_mode = False
```
**Explicação das configurações de `config.ini`**:
* **Seção `[MAIN]`:**
* `is_local`: `True` se você estiver usando provedores de LLM locais (Ollama, LM-Studio, servidor local compatível com OpenAI) ou a opção de servidor auto-hospedado. `False` se você estiver usando APIs baseadas em nuvem (OpenAI, Google, etc.).
* `provider_name`: Especifica o provedor de LLM.
* Opções locais: `ollama`, `lm-studio`, `openai` (para servidor local compatível com OpenAI), `server` (para configuração de servidor auto-hospedado).
* Opções de API: `openai`, `google`, `deepseek`, `huggingface`, `togetherAI`.
* `provider_model`: Nome ou ID específico do modelo do provedor selecionado (ex: `deepseekcoder:6.7b` para Ollama, `gpt-3.5-turbo` para API OpenAI, `mistralai/Mixtral-8x7B-Instruct-v0.1` para TogetherAI).
* `provider_server_address`: O endereço do seu provedor de LLM.
* Para provedores locais: ex: `http://127.0.0.1:11434` para Ollama, `http://127.0.0.1:1234` para LM-Studio.
* Para o tipo de provedor `server`: O endereço do seu servidor LLM auto-hospedado (ex: `http://your_server_ip:3333`).
* Para APIs em nuvem (`is_local = False`): Isso geralmente é ignorado ou pode ser deixado em branco, pois os endpoints da API são geralmente gerenciados pelas bibliotecas do provedor correspondente.
* `agent_name`: O nome do assistente de IA (ex: Friday). Se ativado, usado como palavra de gatilho para fala para texto.
* `recover_last_session`: `True` para tentar recuperar o estado da sessão anterior, `False` para começar do zero.
* `save_session`: `True` para salvar o estado da sessão atual para possível recuperação, `False` caso contrário.
* `speak`: `True` para ativar a saída de voz de texto para fala, `False` para desativar.
* `listen`: `True` para ativar a entrada de voz de fala para texto (apenas modo CLI), `False` para desativar.
* `work_dir`: **Crítico:** O diretório onde o AgenticSeek lerá/escreverá arquivos. **Certifique-se de que este caminho é válido e acessível no seu sistema.**
* `jarvis_personality`: `True` para usar prompts de sistema mais "Jarvis-like" (experimental), `False` para usar prompts padrão.
* `languages`: Lista de idiomas separados por vírgulas (ex: `en, zh, fr`). Usado para seleção de voz TTS (primeira por padrão) e pode ajudar o roteador LLM. Para evitar ineficiências do roteador, evite usar muitos idiomas ou idiomas muito semelhantes.
* **Seção `[BROWSER]`:**
* `headless_browser`: `True` para executar o navegador automatizado sem janela visível (recomendado para interface web ou uso não interativo). `False` para exibir a janela do navegador (útil para modo CLI ou depuração).
* `stealth_mode`: `True` para ativar medidas que tornam mais difícil a detecção da automação do navegador. Pode exigir instalação manual de extensões de navegador como anticaptcha.
Esta seção resume os tipos de provedores de LLM suportados. Configure-os em `config.ini`.
**Provedores locais (executando em seu próprio hardware):**
| Nome do provedor em config.ini | `is_local` | Descrição | Seção de configuração |
|-------------------------------|------------|-----------------------------------------------------------------------------|------------------------------------------------------------------|
| `ollama` | `True` | Fornece LLM localmente facilmente usando Ollama. | [Configuração para executar LLM localmente na sua máquina](#configuração-para-executar-llm-localmente-na-sua-máquina) |
| `lm-studio` | `True` | Fornece LLM localmente com LM-Studio. | [Configuração para executar LLM localmente na sua máquina](#configuração-para-executar-llm-localmente-na-sua-máquina) |
| `openai` (para servidor local) | `True` | Conecte-se a um servidor local expondo uma API compatível com OpenAI (ex: llama.cpp). | [Configuração para executar LLM localmente na sua máquina](#configuração-para-executar-llm-localmente-na-sua-máquina) |
| `server` | `False` | Conecte-se ao servidor LLM auto-hospedado do AgenticSeek em execução em outra máquina. | [Configuração para executar LLM em seu próprio servidor](#configuração-para-executar-llm-em-seu-próprio-servidor) |
**Provedores de API (baseados em nuvem):**
| Nome do provedor em config.ini | `is_local` | Descrição | Seção de configuração |
|-------------------------------|------------|--------------------------------------------------|-----------------------------------------------------|
| `openai` | `False` | Use a API oficial da OpenAI (ex: GPT-3.5, GPT-4). | [Configuração para executar com uma API](#configuração-para-executar-com-uma-api) |
| `google` | `False` | Use os modelos Google Gemini via API. | [Configuração para executar com uma API](#configuração-para-executar-com-uma-api) |
| `deepseek` | `False` | Use a API oficial da Deepseek. | [Configuração para executar com uma API](#configuração-para-executar-com-uma-api) |
| `huggingface` | `False` | Use Hugging Face Inference API. | [Configuração para executar com uma API](#configuração-para-executar-com-uma-api) |
| `togetherAI` | `False` | Use vários modelos abertos via API TogetherAI. | [Configuração para executar com uma API](#configuração-para-executar-com-uma-api) |
---
## Solução de problemas
Se você encontrar problemas, esta seção fornece orientações.
# Problemas conhecidos
## Problemas do ChromeDriver
**Exemplo de erro:** `SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version XXX`
### Causa raiz
A incompatibilidade de versão do ChromeDriver ocorre quando:
1. A versão do ChromeDriver que você instalou não corresponde à versão do navegador Chrome
2. Em ambientes Docker, `undetected_chromedriver` pode baixar sua própria versão do ChromeDriver, contornando os binários montados
### Etapas de solução
#### 1. Verifique sua versão do Chrome
Abra o Google Chrome → `Configurações > Sobre o Chrome` para encontrar sua versão (ex: "Versão 134.0.6998.88")
#### 2. Baixe o ChromeDriver correspondente
**Para Chrome 115 e superior:** Use [Chrome for Testing API](https://googlechromelabs.github.io/chrome-for-testing/)
- Visite o painel de disponibilidade do Chrome for Testing
- Encontre sua versão do Chrome ou a correspondência disponível mais próxima
- Baixe o ChromeDriver para seu sistema operacional (use Linux64 para ambientes Docker)
**Para versões mais antigas do Chrome:** Use [Downloads legados do ChromeDriver](https://chromedriver.chromium.org/downloads)

#### 3. Instale o ChromeDriver (escolha um método)
**Método A: Diretório raiz do projeto (recomendado para Docker)**
```bash
# Coloque o binário chromedriver baixado no diretório raiz do projeto
cp path/to/downloaded/chromedriver ./chromedriver
chmod +x ./chromedriver # Torne-o executável no Linux/macOS
```
**Método B: PATH do sistema**
```bash
# Linux/macOS
sudo mv chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver
# Windows: Coloque chromedriver.exe em uma pasta do PATH
```
#### 4. Verifique a instalação
```bash
# Teste a versão do ChromeDriver
./chromedriver --version
# Ou se estiver no PATH:
chromedriver --version
```
### Instruções específicas do Docker
⚠️ **Importante para usuários do Docker:**
- O método de montagem de volumes do Docker pode não funcionar com o modo furtivo (`undetected_chromedriver`)
- **Solução:** Coloque o ChromeDriver no diretório raiz do projeto como `./chromedriver`
- O aplicativo o detectará automaticamente e usará este binário
- Você deve ver nos logs: `"Using ChromeDriver from project root: ./chromedriver"`
### Dicas de solução de problemas
1. **Ainda há incompatibilidade de versão?**
- Verifique se o ChromeDriver é executável: `ls -la ./chromedriver`
- Verifique a versão do ChromeDriver: `./chromedriver --version`
- Certifique-se de que corresponde à versão do seu navegador Chrome
2. **Problemas com o contêiner Docker?**
- Verifique os logs do backend: `docker logs backend`
- Procure a mensagem: `"Using ChromeDriver from project root"`
- Se não for encontrado, verifique se o arquivo existe e é executável
3. **Versões do Chrome for Testing**
- Use uma correspondência exata quando possível
- Para a versão 134.0.6998.88, use o ChromeDriver 134.0.6998.165 (a versão disponível mais próxima)
- O número da versão principal deve corresponder (134 = 134)
### Matriz de compatibilidade de versões
| Versão do Chrome | Versão do ChromeDriver | Status |
|----------------|---------------------|---------|
| 134.0.6998.x | 134.0.6998.165 | ✅ Disponível |
| 133.0.6943.x | 133.0.6943.141 | ✅ Disponível |
| 132.0.6834.x | 132.0.6834.159 | ✅ Disponível |
*Para a compatibilidade mais recente, consulte o [Painel do Chrome for Testing](https://googlechromelabs.github.io/chrome-for-testing/)*
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
Current browser version is 134.0.6998.89 with binary path`
Isso acontece se seu navegador e a versão do chromedriver não corresponderem.
Você precisa navegar para baixar a versão mais recente:
https://developer.chrome.com/docs/chromedriver/downloads
Se você estiver usando o Chrome versão 115 ou superior, vá para:
https://googlechromelabs.github.io/chrome-for-testing/
e baixe a versão do chromedriver correspondente ao seu sistema operacional.

Se esta seção estiver incompleta, abra um issue.
## Problemas de adaptadores de conexão
```
Exception: Provider lm-studio failed: HTTP request failed: No connection adapters were found for '127.0.0.1:1234/v1/chat/completions'` (nota: a porta pode variar)
```
* **Causa:** Falta o prefixo `http://` em `provider_server_address` para `lm-studio` (ou outro servidor local compatível com OpenAI semelhante) no `config.ini`, ou ele aponta para a porta errada.
* **Solução:**
* Certifique-se de que o endereço inclui `http://`. O LM-Studio geralmente usa `http://127.0.0.1:1234` por padrão.
* `config.ini` correto: `provider_server_address = http://127.0.0.1:1234` (ou sua porta real do servidor LM-Studio).
## URL base do SearxNG não fornecida
```
raise ValueError("SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.")
ValueError: SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.`
```
Isso pode acontecer se você executar o modo CLI com uma URL base do searxng incorreta.
SEARXNG_BASE_URL deve diferir dependendo se você está executando no Docker ou no host:
**Execução no host:** `SEARXNG_BASE_URL="http://localhost:8080"`
**Execução completamente no Docker (interface web):** `SEARXNG_BASE_URL="http://searxng:8080"`
## FAQ
**P: De qual hardware eu preciso?**
| Tamanho do modelo | GPU | Comentários |
|-----------|--------|-----------------------------------------------------------|
| 7B | 8GB VRAM | ⚠️ Não recomendado. Desempenho ruim, alucinações frequentes, agentes de planejamento podem falhar. |
| 14B | 12 GB VRAM (ex: RTX 3060) | ✅ Utilizável para tarefas simples. Pode ter dificuldades com navegação web e planejamento de tarefas. |
| 32B | 24+ GB VRAM (ex: RTX 4090) | 🚀 Consegue a maioria das tarefas, ainda pode ter dificuldades com planejamento de tarefas |
| 70B+ | 48+ GB VRAM | 💪 Excelente. Recomendado para casos de uso avançados. |
**P: O que fazer se eu encontrar erros?**
Certifique-se de que o local está funcionando (`ollama serve`), que seu `config.ini` corresponde ao seu provedor e que as dependências estão instaladas. Se nada funcionar, sinta-se à vontade para abrir um issue.
**P: Ele pode realmente funcionar 100% localmente?**
Sim, com os provedores Ollama, lm-studio ou server, todos os modelos de fala para texto, LLM e texto para fala funcionam localmente. As opções não locais (OpenAI ou outras APIs) são opcionais.
**P: Por que eu deveria usar o AgenticSeek quando tenho o Manus?**
Ao contrário do Manus, o AgenticSeek prioriza a independência de sistemas externos, dando a você mais controle, privacidade e evitando custos de API.
**P: Quem está por trás deste projeto?**
Este projeto foi criado por mim, com dois amigos como mantenedores e contribuidores da comunidade de código aberto no GitHub. Somos apenas indivíduos apaixonados, não uma startup, nem afiliados a qualquer organização.
Qualquer conta AgenticSeek no X diferente da minha conta pessoal (https://x.com/Martin993886460) é um impostor.
## Contribuir
Estamos procurando desenvolvedores para melhorar o AgenticSeek! Verifique os problemas abertos ou discussões.
[Guia de contribuição](./docs/CONTRIBUTING.md)
## Patrocinadores:
Você quer melhorar as capacidades do AgenticSeek com recursos como pesquisa de voos, planejamento de viagens ou obtenção das melhores ofertas de compra? Considere usar o SerpApi para criar ferramentas personalizadas que desbloqueiem mais recursos do tipo Jarvis. Com o SerpApi, você pode acelerar seu agente para tarefas profissionais enquanto mantém o controle total.
Confira [Contributing.md](./docs/CONTRIBUTING.md) para aprender como integrar ferramentas personalizadas!
### **Patrocinadores**:
- [tatra-labs](https://github.com/tatra-labs)
## Mantenedores:
> [Fosowl](https://github.com/Fosowl) | Horário de Paris
> [antoineVIVIES](https://github.com/antoineVIVIES) | Horário de Taipei
## Agradecimentos especiais:
> [tcsenpai](https://github.com/tcsenpai) e [plitc](https://github.com/plitc) por ajudar na dockerização do backend
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
================================================
FILE: README_TR.md
================================================
# AgenticSeek: Gizlilik Odaklı, Yerel Manus Alternatifi
English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Français](./README_FR.md) | [日本語](./README_JP.md) | [Português (Brasil)](./README_PTBR.md) | [Español](./README_ES.md) | [Türkçe](./README_TR.md)
*Sesli komut destekli bu yapay zeka asistanı, **Manus AI'ya %100 yerel bir alternatiftir**. Web'de otonom olarak gezinir, kod yazar ve görevleri planlar; tüm verilerinizi cihazınızda tutar. Yerel akıl yürütme modelleri için tasarlanmış olup tamamen kendi donanımınızda çalışır, eksiksiz gizlilik ve sıfır bulut bağımlılığı sağlar.*
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460) [](https://github.com/Fosowl/agenticSeek/stargazers)
### Neden AgenticSeek?
* 🔒 Tamamen Yerel ve Gizli - Her şey kendi makinenizde çalışır — bulut yok, veri paylaşımı yok. Dosyalarınız, konuşmalarınız ve aramalarınız gizli kalır.
* 🌐 Akıllı Web Tarama - AgenticSeek internette kendi başına gezinebilir — arama yapar, okur, bilgi çıkarır, web formlarını doldurur — tamamen eller serbest.
* 💻 Otonom Kodlama Asistanı - Koda mı ihtiyacınız var? Python, C, Go, Java ve daha fazlasında program yazabilir, hata ayıklayabilir ve çalıştırabilir — denetim olmadan.
* 🧠 Akıllı Ajan Seçimi - Siz sorarsınız, o otomatik olarak iş için en uygun ajanı belirler. Elinizin altında uzmanlardan oluşan bir ekip gibi.
* 📋 Karmaşık Görevleri Planlar ve Yürütür - Seyahat planlamasından karmaşık projelere kadar — büyük görevleri adımlara bölebilir ve birden fazla yapay zeka ajanı kullanarak işleri tamamlayabilir.
* 🎙️ Ses Desteği - Temiz, hızlı, fütüristik ses ve konuşmadan metne dönüştürme ile bilim kurgu filmlerindeki kişisel yapay zekanızla konuşuyormuş gibi etkileşim kurabilirsiniz. (Geliştirme aşamasında)
### **Demo**
> *AgenticSeek projesini arayabilir misin, hangi becerilerin gerektiğini öğrenip ardından CV_candidates.zip dosyasını açarak projeye en uygun adayları söyleyebilir misin?*
https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316
Uyarı: Bu demo ve görünen tüm dosyalar (ör: CV_candidates.zip) tamamen kurgusaldır. Bir şirket değiliz, aday değil açık kaynak katkıda bulunanlar arıyoruz.
> 🛠⚠️️ **Aktif Olarak Geliştirilmektedir**
> 🙏 Bu proje bir yan proje olarak başladı ve sıfır yol haritası, sıfır finansmanla geliştirilmektedir. GitHub Trending'e girerek beklentilerin çok ötesine geçti. Katkılar, geri bildirimler ve sabır derinden takdir edilmektedir.
## Ön Gereksinimler
Başlamadan önce aşağıdaki yazılımların yüklü olduğundan emin olun:
* **Git:** Depoyu klonlamak için. [Git İndir](https://git-scm.com/downloads)
* **Python 3.10.x:** Python 3.10.x sürümünü kullanmanızı şiddetle tavsiye ederiz. Diğer sürümler bağımlılık hatalarına yol açabilir. [Python 3.10 İndir](https://www.python.org/downloads/release/python-3100/) (3.10.x sürümünü seçin).
* **Docker Engine ve Docker Compose:** SearxNG gibi paketlenmiş servisleri çalıştırmak için.
* Docker Desktop yükleyin (Docker Compose V2 dahildir): [Windows](https://docs.docker.com/desktop/install/windows-install/) | [Mac](https://docs.docker.com/desktop/install/mac-install/) | [Linux](https://docs.docker.com/desktop/install/linux-install/)
* Alternatif olarak, Linux üzerinde Docker Engine ve Docker Compose'u ayrı ayrı yükleyin: [Docker Engine](https://docs.docker.com/engine/install/) | [Docker Compose](https://docs.docker.com/compose/install/) (Compose V2 yüklediğinizden emin olun, ör: `sudo apt-get install docker-compose-plugin`).
### 1. **Depoyu klonlayın ve kurulumu yapın**
```sh
git clone https://github.com/Fosowl/agenticSeek.git
cd agenticSeek
mv .env.example .env
```
### 2. .env dosyasının içeriğini değiştirin
```sh
SEARXNG_BASE_URL="http://searxng:8080" # CLI modunda çalıştırıyorsanız http://127.0.0.1:8080 kullanın
REDIS_BASE_URL="redis://redis:6379/0"
WORK_DIR="/Users/mlg/Documents/workspace_for_ai"
OLLAMA_PORT="11434"
LM_STUDIO_PORT="1234"
CUSTOM_ADDITIONAL_LLM_PORT="11435"
OPENAI_API_KEY='optional'
DEEPSEEK_API_KEY='optional'
OPENROUTER_API_KEY='optional'
TOGETHER_API_KEY='optional'
GOOGLE_API_KEY='optional'
ANTHROPIC_API_KEY='optional'
```
`.env` dosyasını ihtiyaçlarınıza göre güncelleyin:
- **SEARXNG_BASE_URL**: CLI modunda çalışmıyorsanız değiştirmeyin.
- **REDIS_BASE_URL**: Değiştirmeyin.
- **WORK_DIR**: Yerel makinenizdeki çalışma dizininin yolu. AgenticSeek bu dosyaları okuyabilir ve onlarla etkileşim kurabilir.
- **OLLAMA_PORT**: Ollama servisi için port numarası.
- **LM_STUDIO_PORT**: LM Studio servisi için port numarası.
- **CUSTOM_ADDITIONAL_LLM_PORT**: Ek özel LLM servisi için port.
**API anahtarları, LLM'yi yerel olarak çalıştırmayı tercih eden kullanıcılar için tamamen isteğe bağlıdır. Bu projenin birincil amacı da budur. Yeterli donanımınız varsa boş bırakın.**
### 3. **Docker'ı Başlatın**
Docker'ın sisteminizde yüklü ve çalışır durumda olduğundan emin olun. Docker'ı aşağıdaki komutlarla başlatabilirsiniz:
- **Linux/macOS:**
Terminal açın ve çalıştırın:
```sh
sudo systemctl start docker
```
Veya yüklüyse Docker Desktop'ı uygulama menüsünden başlatın.
- **Windows:**
Başlat menüsünden Docker Desktop'ı başlatın.
Docker'ın çalıştığını doğrulamak için:
```sh
docker info
```
Docker kurulumunuz hakkında bilgi görüyorsanız, düzgün çalışıyor demektir.
Özet için aşağıdaki [Yerel Sağlayıcılar](#yerel-sağlayıcılar-listesi) tablosuna bakın.
Sonraki adım: [AgenticSeek'i yerel olarak çalıştırın](#servisleri-başlatın-ve-çalıştırın)
*Sorun yaşıyorsanız [Sorun Giderme](#sorun-giderme) bölümüne bakın.*
*Donanımınız LLM'leri yerel olarak çalıştıramıyorsa [API ile Çalıştırma Kurulumu](#api-ile-çalıştırma-kurulumu) bölümüne bakın.*
*Ayrıntılı `config.ini` açıklamaları için [Yapılandırma](#yapılandırma) bölümüne bakın.*
---
## LLM'yi Makinenizde Yerel Olarak Çalıştırma Kurulumu
**Donanım Gereksinimleri:**
LLM'leri yerel olarak çalıştırmak için yeterli donanıma ihtiyacınız olacaktır. En azından Magistral, Qwen veya Deepseek 14B çalıştırabilecek bir GPU gereklidir. Ayrıntılı model/performans önerileri için SSS bölümüne bakın.
**Yerel sağlayıcınızı ayarlayın**
Yerel sağlayıcınızı başlatın (örneğin ollama ile):
AgenticSeek'i ana makinede (CLI modu) çalıştırmayacaksanız, sağlayıcı dinleme adresini ayarlayın:
```sh
export OLLAMA_HOST=0.0.0.0:11434
```
Ardından sağlayıcınızı başlatın:
```sh
ollama serve
```
Desteklenen yerel sağlayıcıların listesi için aşağıya bakın.
**config.ini dosyasını güncelleyin**
config.ini dosyasında provider_name'i desteklenen bir sağlayıcıya ve provider_model'i sağlayıcınızın desteklediği bir LLM'e ayarlayın. *Magistral* veya *Deepseek* gibi akıl yürütme modellerini öneriyoruz.
Gerekli donanım için README sonundaki **SSS** bölümüne bakın.
```sh
[MAIN]
is_local = True # Yerel mi yoksa uzak sağlayıcı ile mi çalıştırıyorsunuz.
provider_name = ollama # veya lm-studio, openai, vb.
provider_model = deepseek-r1:14b # donanımınıza uygun bir model seçin
provider_server_address = 127.0.0.1:11434
agent_name = Jarvis # yapay zekanızın adı
recover_last_session = True # önceki oturumu kurtarıp kurtarmayacağı
save_session = True # mevcut oturumu hatırlayıp hatırlamayacağı
speak = False # metinden sese dönüştürme
listen = False # sesten metne dönüştürme, yalnızca CLI için, deneysel
jarvis_personality = False # daha "Jarvis" benzeri bir kişilik kullanıp kullanmayacağı (deneysel)
languages = en zh # Dil listesi, metinden sese varsayılan olarak listedeki ilk dili kullanır
[BROWSER]
headless_browser = True # CLI modunda değilseniz değiştirmeyin.
stealth_mode = True # Tarayıcı algılamasını azaltmak için gizli selenium kullanır
```
**Uyarı**:
- `config.ini` dosya biçimi yorum satırlarını desteklemez.
Örnek yapılandırmayı doğrudan kopyalayıp yapıştırmayın, çünkü yorum satırları hatalara neden olur. Bunun yerine `config.ini` dosyasını yorum satırları olmadan istediğiniz ayarlarla manuel olarak düzenleyin.
- LLM çalıştırmak için LM-studio kullanıyorsanız provider_name'i `openai` olarak *AYARLAMAYIN*. `lm-studio` olarak ayarlayın.
- Bazı sağlayıcılar (ör: lm-studio) IP'nin önünde `http://` gerektirir. Örneğin: `http://127.0.0.1:1234`
**Yerel Sağlayıcılar Listesi**
| Sağlayıcı | Yerel mi? | Açıklama |
|-----------|--------|-----------------------------------------------------------|
| ollama | Evet | Ollama kullanarak LLM'leri kolayca yerel olarak çalıştırın |
| lm-studio | Evet | LM Studio ile LLM'leri yerel olarak çalıştırın (`provider_name` değerini `lm-studio` olarak ayarlayın)|
| openai | Evet | OpenAI uyumlu API kullanın (ör: llama.cpp sunucusu) |
Sonraki adım: [Servisleri başlatın ve AgenticSeek'i çalıştırın](#servisleri-başlatın-ve-çalıştırın)
*Sorun yaşıyorsanız [Sorun Giderme](#sorun-giderme) bölümüne bakın.*
*Donanımınız LLM'leri yerel olarak çalıştıramıyorsa [API ile Çalıştırma Kurulumu](#api-ile-çalıştırma-kurulumu) bölümüne bakın.*
*Ayrıntılı `config.ini` açıklamaları için [Yapılandırma](#yapılandırma) bölümüne bakın.*
## API ile Çalıştırma Kurulumu
Bu kurulum harici, bulut tabanlı LLM sağlayıcılarını kullanır. Seçtiğiniz servisten bir API anahtarına ihtiyacınız olacaktır.
**1. Bir API Sağlayıcısı Seçin ve API Anahtarı Alın:**
Aşağıdaki [API Sağlayıcıları Listesi](#api-sağlayıcıları-listesi) bölümüne bakın. Kaydolmak ve API anahtarı almak için web sitelerini ziyaret edin.
**2. API Anahtarınızı Ortam Değişkeni Olarak Ayarlayın:**
* **Linux/macOS:**
Terminal açın ve `export` komutunu kullanın. Kalıcılık için bunu shell profil dosyanıza (ör: `~/.bashrc`, `~/.zshrc`) eklemeniz önerilir.
```sh
export PROVIDER_API_KEY="api_anahtarınız"
# PROVIDER_API_KEY'i ilgili değişken adıyla değiştirin, ör: OPENAI_API_KEY, GOOGLE_API_KEY
```
TogetherAI örneği:
```sh
export TOGETHER_API_KEY="xxxxxxxxxxxxxxxxxxxxxx"
```
* **Windows:**
* **Komut İstemi (Geçerli oturum için geçici):**
```cmd
set PROVIDER_API_KEY=api_anahtarınız
```
* **PowerShell (Geçerli oturum için geçici):**
```powershell
$env:PROVIDER_API_KEY="api_anahtarınız"
```
* **Kalıcı:** Windows arama çubuğunda "ortam değişkenleri" arayın, "Sistem ortam değişkenlerini düzenle" seçeneğine tıklayın, ardından "Ortam Değişkenleri..." düğmesine tıklayın. Uygun adla (ör: `OPENAI_API_KEY`) yeni bir Kullanıcı değişkeni ekleyin ve değer olarak anahtarınızı girin.
*(Daha fazla ayrıntı için SSS: [API anahtarlarını nasıl ayarlarım?](#api-anahtarlarını-nasıl-ayarlarım) bölümüne bakın.)*
**3. `config.ini` Dosyasını Güncelleyin:**
```ini
[MAIN]
is_local = False
provider_name = openai # Veya google, deepseek, togetherAI, huggingface
provider_model = gpt-3.5-turbo # Veya gemini-1.5-flash, deepseek-chat, mistralai/Mixtral-8x7B-Instruct-v0.1 vb.
provider_server_address = # is_local = False olduğunda çoğu API için genellikle yok sayılır veya boş bırakılabilir
# ... diğer ayarlar ...
```
*Uyarı:* config.ini değerlerinin sonunda boşluk olmadığından emin olun.
**API Sağlayıcıları Listesi**
| Sağlayıcı | `provider_name` | Yerel mi? | Açıklama | API Anahtarı Bağlantısı (Örnekler) |
|--------------|-----------------|--------|---------------------------------------------------|---------------------------------------------|
| OpenAI | `openai` | Hayır | OpenAI API'si üzerinden ChatGPT modellerini kullanın. | [platform.openai.com/signup](https://platform.openai.com/signup) |
| Google Gemini| `google` | Hayır | Google AI Studio üzerinden Google Gemini modellerini kullanın. | [aistudio.google.com/keys](https://aistudio.google.com/keys) |
| Deepseek | `deepseek` | Hayır | Deepseek API'si üzerinden Deepseek modellerini kullanın. | [platform.deepseek.com](https://platform.deepseek.com) |
| Hugging Face | `huggingface` | Hayır | Hugging Face Inference API'den modelleri kullanın. | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) |
| TogetherAI | `togetherAI` | Hayır | TogetherAI API'si üzerinden çeşitli açık kaynak modelleri kullanın.| [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys) |
| OpenRouter | `openrouter` | Hayır | OpenRouter Modellerini kullanın| [https://openrouter.ai/](https://openrouter.ai/) |
*Not:*
* Karmaşık web tarama ve görev planlama için `gpt-4o` veya diğer OpenAI modellerini kullanmanızı önermiyoruz, çünkü mevcut prompt optimizasyonları Deepseek gibi modellere yöneliktir.
* Kodlama/bash görevleri Gemini ile sorun yaşayabilir, çünkü Deepseek için optimize edilmiş biçimlendirme talimatlarına kesinlikle uymayabilir.
* `is_local = False` olduğunda `config.ini` içindeki `provider_server_address` genellikle kullanılmaz, çünkü API uç noktaları genellikle ilgili sağlayıcı kütüphanesinde sabit kodlanmıştır.
Sonraki adım: [Servisleri başlatın ve AgenticSeek'i çalıştırın](#servisleri-başlatın-ve-çalıştırın)
*Sorun yaşıyorsanız **Bilinen Sorunlar** bölümüne bakın*
*Ayrıntılı yapılandırma dosyası açıklamaları için **Yapılandırma** bölümüne bakın.*
---
## Servisleri Başlatın ve Çalıştırın
Varsayılan olarak AgenticSeek tamamen Docker içinde çalıştırılır.
**Seçenek 1:** Docker'da çalıştırın, web arayüzünü kullanın:
Gerekli servisleri başlatın. Bu, docker-compose.yml'deki tüm servisleri başlatacaktır:
- searxng
- redis (searxng için gerekli)
- frontend
- backend (web arayüzü kullanırken `full` parametresi ile)
```sh
./start_services.sh full # MacOS
start start_services.cmd full # Windows
```
**Uyarı:** Bu adım tüm Docker imajlarını indirip yükleyecektir, bu işlem 30 dakikaya kadar sürebilir. Servisleri başlattıktan sonra, herhangi bir mesaj göndermeden önce backend servisinin tamamen çalışır duruma gelmesini bekleyin (loglarda **backend: "GET /health HTTP/1.1" 200 OK** mesajını görmelisiniz). İlk çalıştırmada backend servisinin başlaması 5 dakika sürebilir.
`http://localhost:3000/` adresine gidin ve web arayüzünü görmelisiniz.
*Servis başlatma sorun giderme:* Bu betikler başarısız olursa, Docker Engine'in çalıştığından ve Docker Compose'un (V2, `docker compose`) doğru şekilde yüklendiğinden emin olun. Hata mesajları için terminal çıktısını kontrol edin. Bkz. [SSS: AgenticSeek'i veya betiklerini çalıştırırken hata alıyorum.](#sss-sorun-giderme)
**Seçenek 2:** CLI modu:
CLI arayüzü ile çalıştırmak için paketleri ana makineye yüklemeniz gerekir:
```sh
./install.sh
./install.bat # windows
```
Ardından `config.ini` içindeki SEARXNG_BASE_URL değerini şu şekilde değiştirmelisiniz:
```sh
SEARXNG_BASE_URL="http://localhost:8080"
```
Gerekli servisleri başlatın. Bu, docker-compose.yml'deki bazı servisleri başlatacaktır:
- searxng
- redis (searxng için gerekli)
- frontend
```sh
./start_services.sh # MacOS
start start_services.cmd # Windows
```
Çalıştırın: `uv run python -m ensurepip` komutu ile uv'nin pip'i etkin olduğundan emin olun.
CLI'yi kullanın: `uv run cli.py`
---
## Kullanım
Servislerin `./start_services.sh full` ile çalıştığından emin olun ve web arayüzü için `localhost:3000` adresine gidin.
Yapılandırmada `listen = True` ayarlayarak konuşmadan metne dönüştürmeyi de kullanabilirsiniz. Yalnızca CLI modu için.
Çıkmak için `goodbye` yazın/söyleyin.
İşte bazı kullanım örnekleri:
> *Python'da bir yılan oyunu yap!*
> *Rennes, Fransa'daki en iyi kafeleri internette ara ve adres bilgileriyle birlikte üçünü rennes_cafes.txt dosyasına kaydet.*
> *Bir sayının faktöriyelini hesaplayan bir Go programı yaz, çalışma alanına factorial.go olarak kaydet*
> *summer_pictures klasöründeki tüm JPG dosyalarını ara, bugünün tarihiyle yeniden adlandır ve yeniden adlandırılan dosyaların listesini photos_list.txt dosyasına kaydet*
> *2024'ün popüler bilim kurgu filmlerini internette ara ve bu gece izlemek için üçünü seç. Listeyi movie_night.txt dosyasına kaydet.*
> *2025'in en son yapay zeka haberleri makalelerini internette ara, üçünü seç ve başlıklarını ve özetlerini kazımak için bir Python betiği yaz. Betiği news_scraper.py olarak ve özetleri /home/projects içinde ai_news.txt olarak kaydet*
> *Cuma, internette ücretsiz bir hisse senedi fiyat API'si ara, supersuper7434567@gmail.com ile kaydol ve ardından API'yi kullanarak Tesla'nın günlük fiyatlarını çekmek için bir Python betiği yaz, sonuçları stock_prices.csv dosyasına kaydet*
*Form doldurma yeteneklerinin hâlâ deneysel olduğunu ve başarısız olabileceğini unutmayın.*
Sorgunuzu yazdıktan sonra AgenticSeek göreve en uygun ajanı atayacaktır.
Bu erken bir prototip olduğundan, ajan yönlendirme sistemi sorgunuza göre her zaman doğru ajanı atamayabilir.
Bu nedenle, ne istediğiniz ve yapay zekanın nasıl ilerlemesi gerektiği konusunda çok açık olun. Örneğin, web araması yapmasını istiyorsanız şunu demeyin:
`Solo seyahat için iyi ülkeler biliyor musun?`
Bunun yerine şöyle sorun:
`Web araması yap ve solo seyahat için en iyi ülkeleri bul`
---
## **LLM'yi Kendi Sunucunuzda Çalıştırma Kurulumu**
Güçlü bir bilgisayarınız veya kullanabileceğiniz bir sunucunuz varsa, ancak dizüstü bilgisayarınızdan kullanmak istiyorsanız, özel LLM sunucumuzu kullanarak LLM'yi uzak bir sunucuda çalıştırma seçeneğiniz vardır.
Yapay zeka modelini çalıştıracak "sunucunuzda" IP adresini alın
```sh
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1 # yerel IP
curl https://ipinfo.io/ip # genel IP
```
Not: Windows veya macOS için IP adresini bulmak üzere sırasıyla ipconfig veya ifconfig kullanın.
Depoyu klonlayın ve `server/` klasörüne girin.
```sh
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
cd agenticSeek/llm_server/
```
Sunucuya özel gereksinimleri yükleyin:
```sh
pip3 install -r requirements.txt
```
Sunucu betiğini çalıştırın.
```sh
python3 app.py --provider ollama --port 3333
```
LLM servisi olarak `ollama` veya `llamacpp` arasında seçim yapabilirsiniz.
Şimdi kişisel bilgisayarınızda:
`config.ini` dosyasında `provider_name` değerini `server` ve `provider_model` değerini `deepseek-r1:xxb` olarak ayarlayın.
`provider_server_address` değerini modeli çalıştıracak makinenin IP adresine ayarlayın.
```sh
[MAIN]
is_local = False
provider_name = server
provider_model = deepseek-r1:70b
provider_server_address = http://x.x.x.x:3333
```
Sonraki adım: [Servisleri başlatın ve AgenticSeek'i çalıştırın](#servisleri-başlatın-ve-çalıştırın)
---
## Konuşmadan Metne
Uyarı: Konuşmadan metne özelliği şu anda yalnızca CLI modunda çalışmaktadır.
Konuşmadan metne özelliğinin şu anda yalnızca İngilizce dilinde çalıştığını lütfen unutmayın.
Konuşmadan metne işlevi varsayılan olarak devre dışıdır. Etkinleştirmek için config.ini dosyasında listen seçeneğini True olarak ayarlayın:
```
listen = True
```
Etkinleştirildiğinde, konuşmadan metne özelliği girdinizi işlemeye başlamadan önce bir tetikleyici anahtar kelimeyi (ajanın adı) dinler. Ajanın adını *config.ini* dosyasındaki `agent_name` değerini güncelleyerek özelleştirebilirsiniz:
```
agent_name = Friday
```
En iyi tanıma performansı için ajan adı olarak "John" veya "Emma" gibi yaygın bir İngilizce isim kullanmanızı öneririz.
Transkript görünmeye başladığında, uyandırmak için ajanın adını yüksek sesle söyleyin (ör: "Friday").
Sorgunuzu net bir şekilde söyleyin.
Sisteme devam etmesi gerektiğini bildirmek için isteğinizi bir onay ifadesiyle bitirin. Onay ifadesi örnekleri:
```
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
```
## Yapılandırma
Örnek yapılandırma:
```
[MAIN]
is_local = True
provider_name = ollama
provider_model = deepseek-r1:32b
provider_server_address = http://127.0.0.1:11434 # Ollama örneği; LM-Studio için http://127.0.0.1:1234 kullanın
agent_name = Friday
recover_last_session = False
save_session = False
speak = False
listen = False
jarvis_personality = False
languages = en zh # TTS ve potansiyel yönlendirme için dil listesi.
[BROWSER]
headless_browser = False
stealth_mode = False
```
**`config.ini` Ayarlarının Açıklaması**:
* **`[MAIN]` Bölümü:**
* `is_local`: Yerel LLM sağlayıcısı (Ollama, LM-Studio, yerel OpenAI uyumlu sunucu) veya kendi barındırdığınız sunucu seçeneğini kullanıyorsanız `True`. Bulut tabanlı API (OpenAI, Google, vb.) kullanıyorsanız `False`.
* `provider_name`: LLM sağlayıcısını belirtir.
* Yerel seçenekler: `ollama`, `lm-studio`, `openai` (yerel OpenAI uyumlu sunucular için), `server` (kendi barındırdığınız sunucu kurulumu için).
* API seçenekleri: `openai`, `google`, `deepseek`, `huggingface`, `togetherAI`.
* `provider_model`: Seçilen sağlayıcı için belirli model adı veya kimliği (ör: Ollama için `deepseekcoder:6.7b`, OpenAI API için `gpt-3.5-turbo`, TogetherAI için `mistralai/Mixtral-8x7B-Instruct-v0.1`).
* `provider_server_address`: LLM sağlayıcınızın adresi.
* Yerel sağlayıcılar için: ör: Ollama için `http://127.0.0.1:11434`, LM-Studio için `http://127.0.0.1:1234`.
* `server` sağlayıcı türü için: Kendi barındırdığınız LLM sunucunuzun adresi (ör: `http://sunucu_ip_adresiniz:3333`).
* Bulut API'leri (`is_local = False`) için: Genellikle yok sayılır veya boş bırakılabilir, çünkü API uç noktası genellikle istemci kütüphanesi tarafından işlenir.
* `agent_name`: Yapay zeka asistanının adı (ör: Friday). Etkinleştirilmişse konuşmadan metne için tetikleyici kelime olarak kullanılır.
* `recover_last_session`: Önceki oturumun durumunu kurtarmaya çalışmak için `True`, yeni başlamak için `False`.
* `save_session`: Mevcut oturumun durumunu olası kurtarma için kaydetmek için `True`, aksi takdirde `False`.
* `speak`: Metinden sese sesli çıktıyı etkinleştirmek için `True`, devre dışı bırakmak için `False`.
* `listen`: Konuşmadan metne sesli girdiyi etkinleştirmek için `True` (yalnızca CLI modu), devre dışı bırakmak için `False`.
* `work_dir`: **Kritik:** AgenticSeek'in dosya okuyacağı/yazacağı dizin. **Bu yolun sisteminizde geçerli ve erişilebilir olduğundan emin olun.**
* `jarvis_personality`: Daha "Jarvis-benzeri" bir sistem istemi kullanmak için `True` (deneysel), standart istem için `False`.
* `languages`: Virgülle ayrılmış dil listesi (ör: `en, zh, fr`). TTS ses seçimi için kullanılır (varsayılan olarak ilki) ve LLM yönlendiricisine yardımcı olabilir. Yönlendirici verimliliği için çok fazla veya çok benzer dil kullanmaktan kaçının.
* **`[BROWSER]` Bölümü:**
* `headless_browser`: Otomatik tarayıcıyı görünür pencere olmadan çalıştırmak için `True` (web arayüzü veya etkileşimsiz kullanım için önerilir). Tarayıcı penceresini göstermek için `False` (CLI modu veya hata ayıklama için kullanışlıdır).
* `stealth_mode`: Tarayıcı otomasyonunun tespit edilmesini zorlaştıran önlemleri etkinleştirmek için `True`. Anticaptcha gibi tarayıcı eklentilerinin manuel olarak yüklenmesini gerektirebilir.
Bu bölüm desteklenen LLM sağlayıcı türlerini özetler. `config.ini` dosyasında yapılandırın.
**Yerel Sağlayıcılar (Kendi Donanımınızda Çalışır):**
| `config.ini`'deki Sağlayıcı Adı | `is_local` | Açıklama | Kurulum Bölümü |
|-------------------------------|------------|-----------------------------------------------------------------------------|------------------------------------------------------------------|
| `ollama` | `True` | Ollama kullanarak yerel LLM'leri sunun. | [LLM'yi yerel olarak çalıştırma kurulumu](#llmyi-makinenizde-yerel-olarak-çalıştırma-kurulumu) |
| `lm-studio` | `True` | LM-Studio kullanarak yerel LLM'leri sunun. | [LLM'yi yerel olarak çalıştırma kurulumu](#llmyi-makinenizde-yerel-olarak-çalıştırma-kurulumu) |
| `openai` (yerel sunucu için) | `True` | OpenAI uyumlu API sunan yerel bir sunucuya bağlanın (ör: llama.cpp). | [LLM'yi yerel olarak çalıştırma kurulumu](#llmyi-makinenizde-yerel-olarak-çalıştırma-kurulumu) |
| `server` | `False` | Başka bir makinede çalışan AgenticSeek kendi barındırmalı LLM sunucusuna bağlanın. | [LLM'yi kendi sunucunuzda çalıştırma kurulumu](#llmyi-kendi-sunucunuzda-çalıştırma-kurulumu) |
**API Sağlayıcıları (Bulut Tabanlı):**
| `config.ini`'deki Sağlayıcı Adı | `is_local` | Açıklama | Kurulum Bölümü |
|-------------------------------|------------|--------------------------------------------------|-----------------------------------------------------|
| `openai` | `False` | OpenAI'ın resmi API'sini kullanın (ör: GPT-3.5, GPT-4). | [API ile çalıştırma kurulumu](#api-ile-çalıştırma-kurulumu) |
| `google` | `False` | Google Gemini modellerini API üzerinden kullanın. | [API ile çalıştırma kurulumu](#api-ile-çalıştırma-kurulumu) |
| `deepseek` | `False` | Deepseek'in resmi API'sini kullanın. | [API ile çalıştırma kurulumu](#api-ile-çalıştırma-kurulumu) |
| `huggingface` | `False` | Hugging Face Inference API'yi kullanın. | [API ile çalıştırma kurulumu](#api-ile-çalıştırma-kurulumu) |
| `togetherAI` | `False` | TogetherAI API'si üzerinden çeşitli açık modelleri kullanın. | [API ile çalıştırma kurulumu](#api-ile-çalıştırma-kurulumu) |
---
## Sorun Giderme
Sorunlarla karşılaşırsanız bu bölüm rehberlik sağlar.
# Bilinen Sorunlar
## ChromeDriver Sorunları
**Hata Örneği:** `SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version XXX`
### Temel Neden
ChromeDriver sürüm uyumsuzluğu şu durumlarda oluşur:
1. Yüklü ChromeDriver sürümünüz Chrome tarayıcı sürümünüzle eşleşmiyor
2. Docker ortamlarında `undetected_chromedriver`, bağlanan ikili dosyayı atlayarak kendi ChromeDriver sürümünü indirebilir
### Çözüm Adımları
#### 1. Chrome Sürümünüzü Kontrol Edin
Google Chrome'u açın → `Ayarlar > Chrome Hakkında` bölümünden sürümünüzü bulun (ör: "Sürüm 134.0.6998.88")
#### 2. Eşleşen ChromeDriver'ı İndirin
**Chrome 115 ve sonrası için:** [Chrome for Testing API](https://googlechromelabs.github.io/chrome-for-testing/) kullanın
- Chrome for Testing uygunluk panosunu ziyaret edin
- Chrome sürümünüzü veya en yakın eşleşmeyi bulun
- İşletim sisteminiz için ChromeDriver'ı indirin (Docker ortamları için Linux64)
**Eski Chrome sürümleri için:** [Eski ChromeDriver indirmeleri](https://chromedriver.chromium.org/downloads) kullanın

#### 3. ChromeDriver'ı Yükleyin (Bir Yöntem Seçin)
**Yöntem A: Proje Kök Dizini (Docker için Önerilir)**
```bash
# İndirilen chromedriver ikili dosyasını proje kök dizinine yerleştirin
cp path/to/downloaded/chromedriver ./chromedriver
chmod +x ./chromedriver # Linux/macOS'ta çalıştırılabilir yapın
```
**Yöntem B: Sistem PATH'i**
```bash
# Linux/macOS
sudo mv chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver
# Windows: chromedriver.exe dosyasını PATH'inizdeki bir klasöre yerleştirin
```
#### 4. Kurulumu Doğrulayın
```bash
# ChromeDriver sürümünü test edin
./chromedriver --version
# Veya PATH'teyse:
chromedriver --version
```
### Docker'a Özel Notlar
⚠️ **Docker Kullanıcıları İçin Önemli:**
- Docker volume mount yaklaşımı gizli modda (`undetected_chromedriver`) çalışmayabilir
- **Çözüm**: ChromeDriver'ı proje kök dizinine `./chromedriver` olarak yerleştirin
- Uygulama bu ikili dosyayı otomatik olarak algılayıp kullanacaktır
- Loglarda şunu görmelisiniz: `"Using ChromeDriver from project root: ./chromedriver"`
### Sorun Giderme İpuçları
1. **Hâlâ sürüm uyumsuzluğu mu var?**
- ChromeDriver'ın çalıştırılabilir olduğunu doğrulayın: `ls -la ./chromedriver`
- ChromeDriver sürümünü kontrol edin: `./chromedriver --version`
- Chrome tarayıcı sürümünüzle eşleştiğinden emin olun
2. **Docker container sorunları mı var?**
- Backend loglarını kontrol edin: `docker logs backend`
- Şu mesajı arayın: `"Using ChromeDriver from project root"`
- Bulunamazsa dosyanın var olduğunu ve çalıştırılabilir olduğunu doğrulayın
3. **Chrome for Testing sürümleri**
- Mümkün olduğunca tam sürüm eşleşmesi kullanın
- 134.0.6998.88 sürümü için ChromeDriver 134.0.6998.165 kullanın (en yakın mevcut sürüm)
- Ana sürüm numaraları eşleşmelidir (134 = 134)
### Sürüm Uyumluluk Matrisi
| Chrome Sürümü | ChromeDriver Sürümü | Durum |
|----------------|---------------------|---------|
| 134.0.6998.x | 134.0.6998.165 | ✅ Çalışır |
| 133.0.6943.x | 133.0.6943.141 | ✅ Çalışır |
| 132.0.6834.x | 132.0.6834.159 | ✅ Çalışır |
*En güncel uyumluluk için [Chrome for Testing panosunu](https://googlechromelabs.github.io/chrome-for-testing/) kontrol edin*
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
Current browser version is 134.0.6998.89 with binary path`
Bu hata, tarayıcınız ve chromedriver sürümü arasında uyumsuzluk varsa oluşur.
En son sürümü indirmek için şu adrese gidin:
https://developer.chrome.com/docs/chromedriver/downloads
Chrome sürüm 115 veya daha yenisini kullanıyorsanız:
https://googlechromelabs.github.io/chrome-for-testing/
adresinden işletim sisteminize uygun chromedriver sürümünü indirin.

Bu bölüm eksikse lütfen bir issue açın.
## Bağlantı Adaptörü Sorunları
```
Exception: Provider lm-studio failed: HTTP request failed: No connection adapters were found for '127.0.0.1:1234/v1/chat/completions'` (Not: port değişebilir)
```
* **Neden:** `config.ini` dosyasında `lm-studio` (veya benzeri yerel OpenAI uyumlu sunucular) için `provider_server_address` değerinde `http://` öneki eksik veya yanlış porta yönlendiriliyor.
* **Çözüm:**
* Adresin `http://` içerdiğinden emin olun. LM-Studio varsayılan olarak genellikle `http://127.0.0.1:1234` kullanır.
* Doğru `config.ini`: `provider_server_address = http://127.0.0.1:1234` (veya gerçek LM-Studio sunucu portunuz).
## SearxNG Temel URL'si Belirtilmemiş
```
raise ValueError("SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.")
ValueError: SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.`
```
Bu hata, CLI modunu yanlış SearxNG temel URL'si ile çalıştırdığınızda oluşabilir.
SEARXNG_BASE_URL, Docker'da mı yoksa ana makinede mi çalıştırdığınıza göre değişmelidir:
**Ana makinede çalıştırma**: `SEARXNG_BASE_URL="http://localhost:8080"`
**Tamamen Docker'da çalıştırma (web arayüzü)**: `SEARXNG_BASE_URL="http://searxng:8080"`
## SSS
**S: Hangi donanıma ihtiyacım var?**
| Model Boyutu | GPU | Yorum |
|-----------|--------|-----------------------------------------------------------|
| 7B | 8GB VRAM | ⚠️ Önerilmez. Düşük performans, sık halüsinasyonlar ve planlayıcı ajanlar büyük olasılıkla başarısız olur. |
| 14B | 12 GB VRAM (ör: RTX 3060) | ✅ Basit görevler için kullanılabilir. Web tarama ve planlama görevlerinde zorlanabilir. |
| 32B | 24+ GB VRAM (ör: RTX 4090) | 🚀 Çoğu görevde başarılı, görev planlamasında hâlâ zorlanabilir |
| 70B+ | 48+ GB VRAM | 💪 Mükemmel. Gelişmiş kullanım senaryoları için önerilir. |
**S: Hata alıyorum, ne yapmalıyım?**
Yerel sunucunun çalıştığından (`ollama serve`), `config.ini` dosyanızın sağlayıcınızla eşleştiğinden ve bağımlılıkların yüklü olduğundan emin olun. Hiçbiri işe yaramazsa bir issue açmaktan çekinmeyin.
**S: Gerçekten %100 yerel çalışabilir mi?**
Evet, Ollama, lm-studio veya server sağlayıcıları ile tüm konuşmadan metne, LLM ve metinden sese modelleri yerel olarak çalışır. Yerel olmayan seçenekler (OpenAI veya diğer API'ler) isteğe bağlıdır.
**S: Manus varken neden AgenticSeek kullanmalıyım?**
Manus'un aksine, AgenticSeek harici sistemlerden bağımsızlığa öncelik verir, size daha fazla kontrol, gizlilik ve API maliyetinden kaçınma imkânı sunar.
**S: Projenin arkasında kim var?**
Proje benim tarafımdan, bakımcı olarak görev yapan iki arkadaşım ve GitHub'daki açık kaynak topluluğundan katkıda bulunanlarla birlikte oluşturuldu. Bir startup veya herhangi bir kuruluşla bağlantılı değiliz, sadece tutkulu bireylerden oluşan bir grubuz.
X'te kişisel hesabım (https://x.com/Martin993886460) dışındaki herhangi bir AgenticSeek hesabı taklittir.
## Katkıda Bulunma
AgenticSeek'i geliştirmek için geliştiriciler arıyoruz! Açık issue'lara veya tartışmalara göz atın.
[Katkıda bulunma rehberi](./docs/CONTRIBUTING.md)
## Sponsorlar:
AgenticSeek'in yeteneklerini uçuş arama, seyahat planlama veya en iyi alışveriş fırsatlarını yakalama gibi özelliklerle geliştirmek ister misiniz? Daha fazla Jarvis benzeri yetenek açmak için SerpApi ile özel bir araç oluşturmayı düşünün. SerpApi ile, tam kontrolü elinizde tutarken ajanınızı özel görevler için güçlendirebilirsiniz.
Özel araçları nasıl entegre edeceğinizi öğrenmek için [Contributing.md](./docs/CONTRIBUTING.md) dosyasına bakın!
### **Patron Sponsor**:
- [tatra-labs](https://github.com/tatra-labs)
## Bakımcılar:
> [Fosowl](https://github.com/Fosowl) | Paris Saati
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Saati
## Özel Teşekkürler:
> [tcsenpai](https://github.com/tcsenpai) ve [plitc](https://github.com/plitc) Backend dockerizasyonuna yardımları için
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
================================================
FILE: api.py
================================================
#!/usr/bin/env python3
import os, sys
import uvicorn
import aiofiles
import configparser
import asyncio
import time
from typing import List
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
import uuid
from sources.llm_provider import Provider
from sources.interaction import Interaction
from sources.agents import CasualAgent, CoderAgent, FileAgent, PlannerAgent, BrowserAgent
from sources.browser import Browser, create_driver
from sources.utility import pretty_print
from sources.logger import Logger
from sources.schemas import QueryRequest, QueryResponse
from dotenv import load_dotenv
load_dotenv()
def is_running_in_docker():
"""Detect if code is running inside a Docker container."""
# Method 1: Check for .dockerenv file
if os.path.exists('/.dockerenv'):
return True
# Method 2: Check cgroup
try:
with open('/proc/1/cgroup', 'r') as f:
return 'docker' in f.read()
except:
pass
return False
from celery import Celery
api = FastAPI(title="AgenticSeek API", version="0.1.0")
celery_app = Celery("tasks", broker="redis://localhost:6379/0", backend="redis://localhost:6379/0")
celery_app.conf.update(task_track_started=True)
logger = Logger("backend.log")
config = configparser.ConfigParser()
config.read('config.ini')
api.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
if not os.path.exists(".screenshots"):
os.makedirs(".screenshots")
api.mount("/screenshots", StaticFiles(directory=".screenshots"), name="screenshots")
def initialize_system():
stealth_mode = config.getboolean('BROWSER', 'stealth_mode')
personality_folder = "jarvis" if config.getboolean('MAIN', 'jarvis_personality') else "base"
languages = config["MAIN"]["languages"].split(' ')
# Force headless mode in Docker containers
headless = config.getboolean('BROWSER', 'headless_browser')
if is_running_in_docker() and not headless:
# Print prominent warning to console (visible in docker-compose output)
print("\n" + "*" * 70)
print("*** WARNING: Detected Docker environment - forcing headless_browser=True ***")
print("*** INFO: To see the browser, run 'python cli.py' on your host machine ***")
print("*" * 70 + "\n")
# Flush to ensure it's displayed immediately
sys.stdout.flush()
# Also log to file
logger.warning("Detected Docker environment - forcing headless_browser=True")
logger.info("To see the browser, run 'python cli.py' on your host machine instead")
headless = True
provider = Provider(
provider_name=config["MAIN"]["provider_name"],
model=config["MAIN"]["provider_model"],
server_address=config["MAIN"]["provider_server_address"],
is_local=config.getboolean('MAIN', 'is_local')
)
logger.info(f"Provider initialized: {provider.provider_name} ({provider.model})")
browser = Browser(
create_driver(headless=headless, stealth_mode=stealth_mode, lang=languages[0]),
anticaptcha_manual_install=stealth_mode
)
logger.info("Browser initialized")
agents = [
CasualAgent(
name=config["MAIN"]["agent_name"],
prompt_path=f"prompts/{personality_folder}/casual_agent.txt",
provider=provider, verbose=False
),
CoderAgent(
name="coder",
prompt_path=f"prompts/{personality_folder}/coder_agent.txt",
provider=provider, verbose=False
),
FileAgent(
name="File Agent",
prompt_path=f"prompts/{personality_folder}/file_agent.txt",
provider=provider, verbose=False
),
BrowserAgent(
name="Browser",
prompt_path=f"prompts/{personality_folder}/browser_agent.txt",
provider=provider, verbose=False, browser=browser
),
PlannerAgent(
name="Planner",
prompt_path=f"prompts/{personality_folder}/planner_agent.txt",
provider=provider, verbose=False, browser=browser
)
]
logger.info("Agents initialized")
interaction = Interaction(
agents,
tts_enabled=config.getboolean('MAIN', 'speak'),
stt_enabled=config.getboolean('MAIN', 'listen'),
recover_last_session=config.getboolean('MAIN', 'recover_last_session'),
langs=languages
)
logger.info("Interaction initialized")
return interaction
interaction = initialize_system()
is_generating = False
query_resp_history = []
@api.get("/screenshot")
async def get_screenshot():
logger.info("Screenshot endpoint called")
screenshot_path = ".screenshots/updated_screen.png"
if os.path.exists(screenshot_path):
return FileResponse(screenshot_path)
logger.error("No screenshot available")
return JSONResponse(
status_code=404,
content={"error": "No screenshot available"}
)
@api.get("/health")
async def health_check():
logger.info("Health check endpoint called")
return {"status": "healthy", "version": "0.1.0"}
@api.get("/is_active")
async def is_active():
logger.info("Is active endpoint called")
return {"is_active": interaction.is_active}
@api.get("/stop")
async def stop():
logger.info("Stop endpoint called")
interaction.current_agent.request_stop()
return JSONResponse(status_code=200, content={"status": "stopped"})
@api.get("/latest_answer")
async def get_latest_answer():
global query_resp_history
if interaction.current_agent is None:
return JSONResponse(status_code=404, content={"error": "No agent available"})
uid = str(uuid.uuid4())
if not any(q["answer"] == interaction.current_agent.last_answer for q in query_resp_history):
query_resp = {
"done": "false",
"answer": interaction.current_agent.last_answer,
"reasoning": interaction.current_agent.last_reasoning,
"agent_name": interaction.current_agent.agent_name if interaction.current_agent else "None",
"success": interaction.current_agent.success,
"blocks": {f'{i}': block.jsonify() for i, block in enumerate(interaction.get_last_blocks_result())} if interaction.current_agent else {},
"status": interaction.current_agent.get_status_message if interaction.current_agent else "No status available",
"uid": uid
}
interaction.current_agent.last_answer = ""
interaction.current_agent.last_reasoning = ""
query_resp_history.append(query_resp)
return JSONResponse(status_code=200, content=query_resp)
if query_resp_history:
return JSONResponse(status_code=200, content=query_resp_history[-1])
return JSONResponse(status_code=404, content={"error": "No answer available"})
async def think_wrapper(interaction, query):
try:
interaction.last_query = query
logger.info("Agents request is being processed")
success = await interaction.think()
if not success:
interaction.last_answer = "Error: No answer from agent"
interaction.last_reasoning = "Error: No reasoning from agent"
interaction.last_success = False
else:
interaction.last_success = True
pretty_print(interaction.last_answer)
interaction.speak_answer()
return success
except Exception as e:
logger.error(f"Error in think_wrapper: {str(e)}")
interaction.last_answer = f""
interaction.last_reasoning = f"Error: {str(e)}"
interaction.last_success = False
raise e
@api.post("/query", response_model=QueryResponse)
async def process_query(request: QueryRequest):
global is_generating, query_resp_history
logger.info(f"Processing query: {request.query}")
query_resp = QueryResponse(
done="false",
answer="",
reasoning="",
agent_name="Unknown",
success="false",
blocks={},
status="Ready",
uid=str(uuid.uuid4())
)
if is_generating:
logger.warning("Another query is being processed, please wait.")
return JSONResponse(status_code=429, content=query_resp.jsonify())
try:
is_generating = True
success = await think_wrapper(interaction, request.query)
is_generating = False
if not success:
query_resp.answer = interaction.last_answer
query_resp.reasoning = interaction.last_reasoning
return JSONResponse(status_code=400, content=query_resp.jsonify())
if interaction.current_agent:
blocks_json = {f'{i}': block.jsonify() for i, block in enumerate(interaction.current_agent.get_blocks_result())}
else:
logger.error("No current agent found")
blocks_json = {}
query_resp.answer = "Error: No current agent"
return JSONResponse(status_code=400, content=query_resp.jsonify())
logger.info(f"Answer: {interaction.last_answer}")
logger.info(f"Blocks: {blocks_json}")
query_resp.done = "true"
query_resp.answer = interaction.last_answer
query_resp.reasoning = interaction.last_reasoning
query_resp.agent_name = interaction.current_agent.agent_name
query_resp.success = str(interaction.last_success)
query_resp.blocks = blocks_json
query_resp_dict = {
"done": query_resp.done,
"answer": query_resp.answer,
"agent_name": query_resp.agent_name,
"success": query_resp.success,
"blocks": query_resp.blocks,
"status": query_resp.status,
"uid": query_resp.uid
}
query_resp_history.append(query_resp_dict)
logger.info("Query processed successfully")
return JSONResponse(status_code=200, content=query_resp.jsonify())
except Exception as e:
logger.error(f"An error occurred: {str(e)}")
sys.exit(1)
finally:
logger.info("Processing finished")
if config.getboolean('MAIN', 'save_session'):
interaction.save_session()
if __name__ == "__main__":
# Print startup info
if is_running_in_docker():
print("[AgenticSeek] Starting in Docker container...")
else:
print("[AgenticSeek] Starting on host machine...")
envport = os.getenv("BACKEND_PORT")
if envport:
port = int(envport)
else:
port = 7777
uvicorn.run(api, host="0.0.0.0", port=7777)
================================================
FILE: cli.py
================================================
#!/usr/bin python3
import sys
import argparse
import configparser
import asyncio
from sources.llm_provider import Provider
from sources.interaction import Interaction
from sources.agents import Agent, CoderAgent, CasualAgent, FileAgent, PlannerAgent, BrowserAgent, McpAgent
from sources.browser import Browser, create_driver
from sources.utility import pretty_print
import warnings
warnings.filterwarnings("ignore")
config = configparser.ConfigParser()
config.read('config.ini')
async def main():
pretty_print("Initializing...", color="status")
stealth_mode = config.getboolean('BROWSER', 'stealth_mode')
personality_folder = "jarvis" if config.getboolean('MAIN', 'jarvis_personality') else "base"
languages = config["MAIN"]["languages"].split(' ')
provider = Provider(provider_name=config["MAIN"]["provider_name"],
model=config["MAIN"]["provider_model"],
server_address=config["MAIN"]["provider_server_address"],
is_local=config.getboolean('MAIN', 'is_local'))
browser = Browser(
create_driver(headless=config.getboolean('BROWSER', 'headless_browser'), stealth_mode=stealth_mode, lang=languages[0]),
anticaptcha_manual_install=stealth_mode
)
agents = [
CasualAgent(name=config["MAIN"]["agent_name"],
prompt_path=f"prompts/{personality_folder}/casual_agent.txt",
provider=provider, verbose=False),
CoderAgent(name="coder",
prompt_path=f"prompts/{personality_folder}/coder_agent.txt",
provider=provider, verbose=False),
FileAgent(name="File Agent",
prompt_path=f"prompts/{personality_folder}/file_agent.txt",
provider=provider, verbose=False),
BrowserAgent(name="Browser",
prompt_path=f"prompts/{personality_folder}/browser_agent.txt",
provider=provider, verbose=False, browser=browser),
PlannerAgent(name="Planner",
prompt_path=f"prompts/{personality_folder}/planner_agent.txt",
provider=provider, verbose=False, browser=browser),
#McpAgent(name="MCP Agent",
# prompt_path=f"prompts/{personality_folder}/mcp_agent.txt",
# provider=provider, verbose=False), # NOTE under development
]
interaction = Interaction(agents,
tts_enabled=config.getboolean('MAIN', 'speak'),
stt_enabled=config.getboolean('MAIN', 'listen'),
recover_last_session=config.getboolean('MAIN', 'recover_last_session'),
langs=languages
)
try:
while interaction.is_active:
interaction.get_user()
if await interaction.think():
interaction.show_answer()
interaction.speak_answer()
except Exception as e:
if config.getboolean('MAIN', 'save_session'):
interaction.save_session()
raise e
finally:
if config.getboolean('MAIN', 'save_session'):
interaction.save_session()
if __name__ == "__main__":
asyncio.run(main())
================================================
FILE: docker-compose.yml
================================================
services:
redis:
container_name: redis
profiles: ["core", "full"]
image: docker.io/valkey/valkey:8-alpine
command: valkey-server --save 30 1 --loglevel warning
restart: unless-stopped
volumes:
- redis-data:/data
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
- DAC_OVERRIDE
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
networks:
- agentic-seek-net
searxng:
container_name: searxng
profiles: ["core", "full"]
image: docker.io/searxng/searxng:latest
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./searxng:/etc/searxng:rw,z
environment:
- SEARXNG_BASE_URL=${SEARXNG_BASE_URL:-http://localhost:8080/}
- SEARXNG_SECRET_KEY=${SEARXNG_SECRET_KEY}
- UWSGI_WORKERS=4
- UWSGI_THREADS=4
cap_add:
- CHOWN
- SETGID
- SETUID
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
depends_on:
- redis
networks:
- agentic-seek-net
frontend:
container_name: frontend
profiles: ["core", "full"]
build:
context: ./frontend
dockerfile: Dockerfile.frontend
ports:
- "3000:3000"
volumes:
- ./frontend/agentic-seek-front/src:/app/src:rw,z
- ./screenshots:/app/screenshots
environment:
- NODE_ENV=development
- CHOKIDAR_USEPOLLING=true
- REACT_APP_BACKEND_URL=http://localhost:7777
networks:
- agentic-seek-net
backend:
container_name: backend
profiles: ["backend", "full"]
build:
context: .
dockerfile: Dockerfile.backend
ports:
- ${BACKEND_PORT:-7777}:${BACKEND_PORT:-7777}
volumes:
- ./:/app
- ${WORK_DIR:-.}:/opt/workspace
command: python3 api.py
environment:
- SEARXNG_BASE_URL=${SEARXNG_BASE_URL:-http://searxng:8080}
- REDIS_URL=${REDIS_BASE_URL:-redis://redis:6379/0}
- WORK_DIR=/opt/workspace
- BACKEND_PORT=${BACKEND_PORT}
- DOCKER_INTERNAL_URL=http://host.docker.internal
- OPENAI_API_KEY=${OPENAI_API_KEY}
- DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
- TOGETHER_API_KEY=${TOGETHER_API_KEY}
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- HUGGINGFACE_API_KEY=${HUGGINGFACE_API_KEY}
- DSK_DEEPSEEK_API_KEY=${DSK_DEEPSEEK_API_KEY}
networks:
- agentic-seek-net
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
redis-data:
chrome_profiles:
networks:
agentic-seek-net:
driver: bridge
================================================
FILE: docs/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official email address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement:
you need to send a private message to `fossowl` or `mow8758` on discord.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
================================================
FILE: docs/CONTRIBUTING.md
================================================
# Contributors guide
## Prerequisites
- Python 3.10 or higher.
- Docker or Orbstack or Podman.
- Ollama with some deepseek-r1 variant installed or similar local reasoning model.
- Basic familiarity with Python and AI models.
- Join the discord (optional): https://discord.gg/8hGDaME3TC
## Contribution Guidelines
We welcome contributions in the following areas:
- Code Improvements: Optimize existing code, fix bugs, or add new features.
- Documentation: Improve the README, write tutorials, or add inline comments.
- Testing: Write unit tests, integration tests, or help with debugging.
- New Features: Implement new tools, agents, or integrations.
## Steps to Contribute
Fork the project to your GitHub account.
Create a Branch:
```bash
git checkout -b feature/your-feature-name
```
Make Your Changes.
Write your code, add documentation, or fix bugs.
Test Your Changes.
Ensure your changes work as expected and do not break existing functionality.
Push your changes to your fork and submit a pull request to the main branch of this repository. Provide a clear description of your changes and reference any related issues.
## Good practice
1. **Privacy First, Always Local**
- All core functionality must be able to run 100% locally
- Cloud services should only be optional alternatives, clearly defined with a warning message.
- remote APIs are only allowed for specific tools (weather api, MCP, flight search, etc...)
- User data privacy is non-negotiable
2. **Agent-Based Architecture**
- Each agent should have a clear, single responsibility
- Agents should be modular and independently testable
- New agents should solve specific use cases
3. **Tool-Based Extensibility**
- Tools should be self-contained and follow the Tools base class
- Each tool should do one thing well
- Tools should provide clear feedback on success/failure
4. **User Experience**
- Provide meaningful feedback for all operations
- Support multiple languages
- Text to speech with short response.
- Keep responses concise
5. **Code Quality**
- Write clear, self-documenting code
- Include type hints and docstrings
- Follow existing patterns in the codebase
- Add a if __name__ == "__main__" at the bottom of each class file for individual testing.
- Ideally had automated tests.
6. **Error Handling**
- Fail gracefully with meaningful messages
- Include recovery mechanisms where possible
- Log errors appropriately without exposing sensitive data
## Areas Needing Help
Here are some tasks and areas where we need contributions:
- Web Browsing: Improve the autonomous web browsing capabilities for the assistant.
- Graphical interface, a web graphical interface. (please ask first)
- Multi-Agent System: Enhance the planner agent for divide and conqueer for task (please ask first).
- New Tools: Add support for additional programming languages or APIs.
- MCP: Add MCP protocol compatibility (possibly as a special type tool).
- Multi-language support: for Text to speech & speech to text
- Prompt engineering: improve prompts, compare results with different prompts for a identical query. Iterate until you find better prompt.
- Bug hunt: Hunt and fix bugs.
- Crossplatform: enhance cross-platform support.
- Testing: Write comprehensive tests for existing features.
# Implementing and using Tools
Tools are extensions that enable agents to perform specific actions, such as running Python code, making API calls, or conducting web searches. All tools inherit from the Tools base class, which provides methods for parsing and executing tool instructions.
## Understand Tools parsing
Agents invoke tools using a standardized format called a block. A block consists of the tool name followed by the content (e.g., code, query, or parameters) to execute. When creating a prompt for an Agent, you must explicitly tell them to use this format.
The format looks like this:
BECAUSE WE USE MARKDOWN QUOTE FORMAT, READING WILL BE BROKEN ON GITHUB PLEASE START READING THE FILE AS RAW: https://raw.githubusercontent.com/Fosowl/agenticSeek/refs/heads/dev/docs/CONTRIBUTING.md
```
```
Or:
```web_search
What to do in Taipei?
```
we call these "blocks".
The Tools class provides the load_exec_block method to extract and parse blocks from an agent's response. This method identifies the tool name and content, enabling the system to execute the appropriate action.
How to handle multiple arguments then ?
Good question! Each tool is free to handle argument in it's own way within the block, but we provide a common parsing logic:
```trip_search
from=Paris
to=Toulouse
```
To extract these parameters, use the `get_parameter_value` method provided by the Tools class. Each tool can define its own parameter-handling logic, but the Tools class ensures consistent parsing.
Again if a tool need a specific format, you could implement a specific method for parsing a block. Using get_parameter_value is optional.
The content of blocks can also be saved using :path, for instance:
```python:toto.py
print("Hello world")
```
Will save the code in toto.py file within the work_folder defined in the config.ini
## Tools Implementation
When developing a tool, you must implement three abstract methods defined in the Tools class to handle execution, failure detection, and feedback to the agent. These methods ensure consistent behavior across tools and enable robust interaction with the LLM.
### 1. Execute method
```
@abstractmethod
def execute(self, blocks: [str], safety: bool) -> str:
```
This method defines how the tool processes the provided block(s) and produces a result.
### 2. execution_failure_check
```
@abstractmethod
def execution_failure_check(self, output: str) -> bool:
```
This method analyzes the tool’s output to determine if the execution was successful or failed.
### 3. interpreter_feedback
```
@abstractmethod
def interpreter_feedback(self, output: str) -> str:
```
This method generates a feedback message for the LLM, helping it understand the tool’s execution outcome and adjust its behavior if needed.
Recap:
- load_exec_block: Extracts and parses tool blocks from the agent's response.
- get_parameter_value: Retrieves parameter values from a block's content.
- File handling: Supports saving block content to files when a :path is specified.
## Prompting an Agent for Tools usage
Consider an example where you want to add a flight search tool to the casual agent, you will need to modify the prompt file for the CasualAgent (e.g., casual_agent.txt) to instruct the LLM to use the a simple flight_search tool. you could add to the prompt:
You can search for flights using the flight_search tool. Example:
```flight_search
RY7481
```
You simply need to enter the flight number, you will then various informations about the flight if it exist, such as : Airline, Status, Departure time, Arrival Time
## Add the tool to your agent
To add a tool to an agent you simply need to:
1. Import a tool.
2. Add the tool class to the **tools** dictionnary.
3. Update the agent prompt.
```python
from sources.tools.flightSearch import FlightSearch
class CasualAgent(Agent):
def __init__(self, name, prompt_path, provider, verbose=False):
super().__init__(name, prompt_path, provider, verbose, None)
self.tools = {
"flight_search": FlightSearch(),
}
self.role = "en"
self.type = "casual_agent"
```
# Implementing and using Agents
Agents are classes that define how an LLM interacts with users and processes inputs. They can use tools (e.g., for executing code or querying APIs) and maintain a memory of the conversation to provide context-aware responses. All agents inherit from the base Agent class, which provides core functionality like memory management and LLM communication.
The simplest agent example is the casual agent:
```
class CasualAgent(Agent):
def __init__(self, name, prompt_path, provider, verbose=False):
"""
The casual agent is a special for casual talk to the user without specific tasks.
"""
super().__init__(name, prompt_path, provider, verbose, None)
self.tools = {
} # No tools for the casual agent
self.role = "en"
self.type = "casual_agent"
def process(self, prompt, speech_module) -> str:
self.memory.push('user', prompt)
animate_thinking("Thinking...", color="status")
answer, reasoning = self.llm_request()
self.last_answer = answer
return answer, reasoning
```
Agent have several parameters that should be sets:
`tools`: A dictionary of tools the agent can use. Each tool must inherit from the Tools class. For example, a CasualAgent has no tools ({}), while a coding agent might include a Python execution tool.
`role`:A dictionary defining the agent's role, used by the routing system to select the appropriate agent.
`type: the agent type, a fixed name to identify the unique agent type.
Every agent must implement the process method, which defines how it handles user input and generates a response.
**Workflow:**
Push the user's prompt to the agent's memory using self.memory.push('user', prompt).
Call self.llm_request() to generate a response and reasoning based on the memory context.
Store and return the response and reasoning.
Note the memory logic. You only need to push the 'user' message. The llm_request method take care of pushing the assistant message.
This separation of user and assistant memory handling may be inconsistent and could be refactored for clarity in the near future.
**Tool blocks execution**
Each agent might return block of tool to execute, as explained in the **Implementing and using Tools** section.
In a single text returned by an agent, a succession of block might be present for example, the coding agent answer could be:
I will create a work folder:
```bash
mkdir myAGI
```
I will enter the folder.
```bash
cd myAGI
```
I will create a python code.
```python:myAGI/super_smart.py
```
The `execute_modules` method allow to automatically find, parse and execute all tools from a LLM prompt.
It will look in the agent answer for any tool "block" execute the appropriate tool and return a (success, feedback) tuple.
```
def execute_modules(self, answer: str) -> Tuple[bool, str]:
```
# Architecture Overview
## 1. Agent selection logic
The agent selection is done in 4 steps:
1. determine query language and translate to english for the zero-shot model and llm_router.
2. Estimate the task complexity and best agent.
- If HIGH complexity: return the planner agent.
- If LOW complexity: Determine the best agent for the task using a vote system between 2 classification models.
3. Process high complexity query.
- If task was high complexity, planner agent will create a json plan to divide and conqueer the task with multiple agent.
4. Proceed with task(s)
## 2. Agents
### File/Code agents
The File and Code agents operate similarly: when a prompt is submitted, they initiate a loop between the LLM and a code interpreter. This loop continues executing commands or code until the execution is successful or the maximum number of attempts is reached.
### Web agent
The Web agent controls a Selenium-driven browser. Upon receiving a query, it begins by generating an optimized search prompt and executing the web_search tool. It then enters a navigation loop, during which it:
- Analyzes the content and interactive elements of the current page.
- Decides which link to follow, either from the current page or the web_search results.
- Determines if it should navigate back if so, it re-evaluates the original web_search results.
- Identifies and interacts with web forms, extracting or filling them as needed.
- Signals completion by requesting to exit once it considers the task fulfilled.
## Code of Conduct
See CODE_OF_CONDUCT.md
**Thank You!**
================================================
FILE: frontend/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
================================================
FILE: frontend/Dockerfile.frontend
================================================
FROM node:18
WORKDIR /app
# Copy package files
COPY agentic-seek-front/package.json agentic-seek-front/package-lock.json ./
# Install dependencies with explicit bin linking
RUN npm ci && npm rebuild
# Copy application code
COPY agentic-seek-front/ .
# Verify react-scripts is available (catches install issues early)
RUN test -f node_modules/.bin/react-scripts || npm install react-scripts
EXPOSE 3000
CMD ["npm", "start"]
================================================
FILE: frontend/README.md
================================================
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
The page will reload when you make changes.\
You may also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `npm run build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
================================================
FILE: frontend/agentic-seek-front/package.json
================================================
{
"name": "agentic-seek",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.8.4",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-markdown": "^10.1.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
================================================
FILE: frontend/agentic-seek-front/public/index.html
================================================
);
};
================================================
FILE: frontend/agentic-seek-front/src/components/ThemeToggle.js
================================================
import React from "react";
import { useTheme } from "../contexts/ThemeContext";
export const ThemeToggle = () => {
const { isDark, toggleTheme } = useTheme();
return (
);
};
================================================
FILE: frontend/agentic-seek-front/src/contexts/ThemeContext.js
================================================
import React, { createContext, useContext, useState, useEffect } from "react";
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [isDark, setIsDark] = useState(() => {
const saved = localStorage.getItem("theme");
return saved ? saved === "dark" : true; // Default to dark
});
useEffect(() => {
localStorage.setItem("theme", isDark ? "dark" : "light");
document.documentElement.setAttribute(
"data-theme",
isDark ? "dark" : "light"
);
}, [isDark]);
const toggleTheme = () => setIsDark(!isDark);
return (
{children}
);
};
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within ThemeProvider");
}
return context;
};
================================================
FILE: frontend/agentic-seek-front/src/index.css
================================================
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
================================================
FILE: frontend/agentic-seek-front/src/index.js
================================================
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { ThemeProvider } from "./contexts/ThemeContext";
import "./styles/globals.css";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
);
================================================
FILE: frontend/agentic-seek-front/src/reportWebVitals.js
================================================
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
================================================
FILE: frontend/agentic-seek-front/src/setupTests.js
================================================
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
================================================
FILE: frontend/agentic-seek-front/src/styles/globals.css
================================================
:root {
--background: hsl(0 0% 100%);
--foreground: hsl(222.2 47.4% 11.2%);
--muted: hsl(210 40% 96.1%);
--muted-foreground: hsl(215.4 16.3% 46.9%);
--popover: hsl(0 0% 100%);
--popover-foreground: hsl(222.2 47.4% 11.2%);
--card: hsl(0 0% 100%);
--card-foreground: hsl(222.2 47.4% 11.2%);
--border: hsl(214.3 31.8% 91.4%);
--input: hsl(214.3 31.8% 91.4%);
--primary: hsl(222.2 47.4% 11.2%);
--primary-foreground: hsl(210 40% 98%);
--secondary: hsl(210 40% 96.1%);
--secondary-foreground: hsl(222.2 47.4% 11.2%);
--accent: hsl(210 40% 96.1%);
--accent-foreground: hsl(222.2 47.4% 11.2%);
--destructive: hsl(0 100% 50%);
--destructive-foreground: hsl(210 40% 98%);
--ring: hsl(215 20.2% 65.1%);
--radius: 0.5rem;
}
.dark {
--background: hsl(224 71% 4%);
--foreground: hsl(213 31% 91%);
--muted: hsl(223 47% 11%);
--muted-foreground: hsl(215.4 16.3% 56.9%);
--popover: hsl(224 71% 4%);
--popover-foreground: hsl(215 20.2% 65.1%);
--card: hsl(224 71% 4%);
--card-foreground: hsl(213 31% 91%);
--border: hsl(216 34% 17%);
--input: hsl(216 34% 17%);
--primary: hsl(210 40% 98%);
--primary-foreground: hsl(222.2 47.4% 1.2%);
--secondary: hsl(222.2 47.4% 11.2%);
--secondary-foreground: hsl(210 40% 98%);
--accent: hsl(216 34% 17%);
--accent-foreground: hsl(210 40% 98%);
--destructive: hsl(0 63% 31%);
--destructive-foreground: hsl(210 40% 98%);
--ring: hsl(216 34% 17%);
--radius: 0.5rem;
}
[data-theme="dark"] {
--background: #0a0a0a;
--foreground: #fafafa;
--card: #1a1a1a;
--card-foreground: #fafafa;
--popover: #1a1a1a;
--popover-foreground: #fafafa;
--primary: #fafafa;
--primary-foreground: #0a0a0a;
--secondary: #2a2a2a;
--secondary-foreground: #fafafa;
--muted: #1e1e1e;
--muted-foreground: #a1a1aa;
--accent: #6b7280;
--accent-foreground: #ffffff;
--destructive: #ef4444;
--destructive-foreground: #ffffff;
--border: #333333;
--input: #333333;
--ring: #6b7280;
}
[data-theme="light"] {
--background: #ffffff;
--foreground: #0a0a0a;
--card: #ffffff;
--card-foreground: #0a0a0a;
--popover: #ffffff;
--popover-foreground: #0a0a0a;
--primary: #0a0a0a;
--primary-foreground: #ffffff;
--secondary: #f5f5f5;
--secondary-foreground: #0a0a0a;
--muted: #f5f5f5;
--muted-foreground: #737373;
--accent: #6b7280;
--accent-foreground: #ffffff;
--destructive: #ef4444;
--destructive-foreground: #ffffff;
--border: #e5e5e5;
--input: #e5e5e5;
--ring: #6b7280;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--background);
color: var(--foreground);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
sans-serif;
transition: background-color 0.3s ease, color 0.3s ease;
margin: 0;
padding: 0;
height: 100vh;
overflow: hidden;
}
html,
body,
#root {
height: 100%;
overflow: hidden;
}
.theme-toggle {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
min-width: 44px;
height: 44px;
padding: 0 12px;
border-radius: 12px;
border: 1px solid var(--border);
background: var(--card);
color: var(--foreground);
text-decoration: none;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.theme-toggle::before {
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.1),
transparent
);
transition: left 0.5s ease;
}
.theme-toggle:hover::before {
left: 100%;
}
.theme-toggle:hover {
background: #24292e;
border-color: #24292e;
color: white;
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(36, 41, 46, 0.3);
}
.github-link {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
min-width: 44px;
height: 44px;
padding: 0 12px;
border-radius: 12px;
border: 1px solid var(--border);
background: var(--card);
color: var(--foreground);
text-decoration: none;
font-size: 0.875rem;
font-weight: 500;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.github-link::before {
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.1),
transparent
);
transition: left 0.5s ease;
}
.github-link:hover::before {
left: 100%;
}
.github-link:hover {
background: #24292e;
border-color: #24292e;
color: white;
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(36, 41, 46, 0.3);
}
.header-actions {
display: flex;
align-items: center;
gap: 12px;
}
================================================
FILE: install.bat
================================================
@echo off
set SCRIPTS_DIR=scripts
set LLM_ROUTER_DIR=llm_router
if exist "%SCRIPTS_DIR%\windows_install.bat" (
echo Running Windows installation script...
call "%SCRIPTS_DIR%\windows_install.bat"
) else (
echo Error: %SCRIPTS_DIR%\windows_install.bat not found!
exit /b 1
)
================================================
FILE: install.sh
================================================
#!/bin/bash
SCRIPTS_DIR="scripts"
LLM_ROUTER_DIR="llm_router"
echo "Detecting operating system..."
OS_TYPE=$(uname -s)
case "$OS_TYPE" in
"Linux"*)
echo "Detected Linux OS"
if [ -f "$SCRIPTS_DIR/linux_install.sh" ]; then
echo "Running Linux installation script..."
bash "$SCRIPTS_DIR/linux_install.sh"
bash -c "cd $LLM_ROUTER_DIR && ./dl_safetensors.sh"
else
echo "Error: $SCRIPTS_DIR/linux_install.sh not found!"
exit 1
fi
;;
"Darwin"*)
echo "Detected macOS"
if [ -f "$SCRIPTS_DIR/macos_install.sh" ]; then
echo "Running macOS installation script..."
bash "$SCRIPTS_DIR/macos_install.sh"
bash -c "cd $LLM_ROUTER_DIR && ./dl_safetensors.sh"
else
echo "Error: $SCRIPTS_DIR/macos_install.sh not found!"
exit 1
fi
;;
*)
echo "Unsupported OS detected: $OS_TYPE"
echo "This script supports only Linux and macOS."
exit 1
;;
esac
echo "Installation process finished!"
================================================
FILE: llm_router/config.json
================================================
{
"config": {
"batch_size": 32,
"device_map": "auto",
"early_stopping_patience": 3,
"epochs": 10,
"ewc_lambda": 100.0,
"gradient_checkpointing": false,
"learning_rate": 0.0005,
"max_examples_per_class": 500,
"max_length": 512,
"min_confidence": 0.1,
"min_examples_per_class": 3,
"neural_weight": 0.2,
"num_representative_examples": 5,
"prototype_update_frequency": 50,
"prototype_weight": 0.8,
"quantization": null,
"similarity_threshold": 0.7,
"warmup_steps": 0
},
"embedding_dim": 768,
"id_to_label": {
"0": "HIGH",
"1": "LOW"
},
"label_to_id": {
"HIGH": 0,
"LOW": 1
},
"model_name": "distilbert/distilbert-base-cased",
"train_steps": 20
}
================================================
FILE: llm_router/dl_safetensors.sh
================================================
##########
# Dummy script to download the model
# Because downloading with hugging face does not seem to work, maybe I am doing something wrong?
# AdaptiveClassifier.from_pretrained("adaptive-classifier/llm-router") ----> result in config.json not found
# Therefore, I put all the files in llm_router and download the model file with this script, If you know a better way please raise an issue
#########
#!/bin/bash
# Define the URL and filename
URL="https://huggingface.co/adaptive-classifier/llm-router/resolve/main/model.safetensors"
FILENAME="model.safetensors"
if [ ! -f "$FILENAME" ]; then
echo "Router safetensors file not found, downloading..."
if command -v curl >/dev/null 2>&1; then
curl -L -o "$FILENAME" "$URL"
elif command -v wget >/dev/null 2>&1; then
wget -O "$FILENAME" "$URL"
else
echo "Error: Neither curl nor wget is available. Please install one of them."
exit 1
fi
if [ $? -eq 0 ]; then
echo "Download completed successfully"
else
echo "Download failed"
exit 1
fi
else
echo "File already exists, skipping download"
fi
================================================
FILE: llm_router/examples.json
================================================
{
"HIGH": [
{
"embedding": [
0.016495609655976295,
0.005480897147208452,
-0.018112657591700554,
-0.01297008991241455,
-0.011229322291910648,
-0.007757639978080988,
0.022426409646868706,
0.0019834344275295734,
4.7438734327442944e-05,
-0.0727558359503746,
-0.03140801563858986,
0.02924070693552494,
-0.013305341824889183,
-0.0033793533220887184,
-0.03547373414039612,
0.019541557878255844,
0.004705663304775953,
0.0031602741219103336,
-0.007299069315195084,
-0.008298901841044426,
0.027937384322285652,
-0.01168726570904255,
0.043954089283943176,
-0.010175682604312897,
0.01752714067697525,
-0.011832871474325657,
0.02276492491364479,
0.00041527353459969163,
-0.01040633674710989,
0.018388407304883003,
-0.0008719401666894555,
0.014631378464400768,
0.01003444753587246,
-0.005072707310318947,
-0.01708260178565979,
0.028439581394195557,
-0.001065331045538187,
-0.013541670516133308,
-0.008151366375386715,
-0.0017858362989500165,
-0.04729022458195686,
0.0013758301502093673,
0.028301924467086792,
-0.00800317618995905,
0.01729578711092472,
-0.031203145161271095,
5.299960685078986e-05,
0.00710116233676672,
-0.020758919417858124,
0.018893010914325714,
-0.004333723336458206,
-0.01338175404816866,
-0.003035568865016103,
0.013158426620066166,
-0.0006750732427462935,
-0.0014697874430567026,
-0.004081630613654852,
0.010444114916026592,
-0.017663925886154175,
0.01912999525666237,
-0.003001948120072484,
0.011249830946326256,
0.021505428478121758,
0.004422237630933523,
-0.03002401627600193,
0.005733916070312262,
-0.0027444788720458746,
0.011264375410974026,
-0.0052582500502467155,
-0.013206424191594124,
0.0039016155060380697,
0.011999109759926796,
0.012016202323138714,
0.06148667633533478,
0.030696019530296326,
-0.0037124326918274164,
0.010741314850747585,
0.003361163195222616,
-0.0016000054311007261,
0.005987717770040035,
0.013546786271035671,
0.011325838044285774,
-0.02007560059428215,
-0.008157439529895782,
-0.00397141557186842,
0.0010972946183755994,
0.006392213981598616,
-0.005559434648603201,
-0.014310109429061413,
0.007732727099210024,
0.00979041587561369,
-0.023415854200720787,
-0.0166454017162323,
0.00354577018879354,
-0.027344686910510063,
0.0023091051261872053,
0.013908812776207924,
0.005490132141858339,
0.39675047993659973,
-0.001610499108210206,
0.0015701313968747854,
0.008452124893665314,
0.008739441633224487,
-0.010343816131353378,
0.011397993192076683,
-0.031160974875092506,
0.003526464104652405,
-0.02407781034708023,
-0.006676384713500738,
0.022912954911589622,
0.022621111944317818,
-0.002652450231835246,
0.005220992024987936,
-0.00676289526745677,
0.011205418035387993,
-0.02595527283847332,
-0.005420653149485588,
0.0077509465627372265,
0.01246832124888897,
-0.013653183355927467,
0.009382130578160286,
0.0014066541334614158,
0.039461780339479446,
-0.0018931152299046516,
0.00583681371062994,
-0.013070599175989628,
-0.002932430012151599,
-0.011789715848863125,
0.023120835423469543,
-0.017384832724928856,
-0.0299319326877594,
-0.017958542332053185,
-0.004042096436023712,
0.0008597958949394524,
0.0007447497337125242,
0.005559271201491356,
-0.012405317276716232,
0.007061595097184181,
-0.045015621930360794,
0.012436705641448498,
0.01543895062059164,
-0.020615339279174805,
-0.011243014596402645,
-0.007231279741972685,
-0.024470414966344833,
0.19155387580394745,
-0.015353432856500149,
0.005650498438626528,
-0.0016646842705085874,
-0.0018647406250238419,
0.009255211800336838,
-0.018530115485191345,
-0.01460390817373991,
0.018793761730194092,
-0.01593736745417118,
-0.015174397267401218,
0.008480808697640896,
0.004032989963889122,
0.0005173711106181145,
0.006885719485580921,
-0.02773197926580906,
0.02047419548034668,
-0.01505290251225233,
0.03906029835343361,
-0.005256787873804569,
-0.012244163081049919,
0.009869610890746117,
-0.051835641264915466,
0.015494653955101967,
0.024344785138964653,
0.004044961184263229,
-0.00811328087002039,
-0.14865797758102417,
0.009341184981167316,
0.02140471152961254,
0.015196156688034534,
0.00519429100677371,
0.010109738446772099,
-0.00408367533236742,
-0.01538225170224905,
-0.004831722006201744,
0.011002450250089169,
-0.008814712055027485,
0.004652463365346193,
-0.031084975227713585,
0.023310834541916847,
0.0009786442387849092,
-0.019534239545464516,
-0.008044155314564705,
-3.6518042179523036e-05,
0.006416455842554569,
-0.004258246626704931,
-0.001313903951086104,
0.011238417588174343,
0.010613993741571903,
-0.007694580592215061,
0.015417139045894146,
-0.00039941645809449255,
0.0008333649020642042,
-0.02026311121881008,
0.008291113190352917,
0.004444482270628214,
-0.02094116620719433,
0.008197329007089138,
0.02149384841322899,
0.005004359874874353,
0.0022778413258492947,
-0.007196932565420866,
0.028372520580887794,
-0.010449135676026344,
-0.01282496377825737,
0.011855466291308403,
-0.0031645731069147587,
0.03159922733902931,
0.012189199216663837,
-0.014184609986841679,
0.0064141517505049706,
0.011804410256445408,
0.004817164037376642,
-0.005351536441594362,
-0.0072435904294252396,
0.011458695866167545,
-0.00019929694826714694,
-0.016873518005013466,
0.010775614529848099,
0.017961787059903145,
0.013426419347524643,
0.002801434835419059,
0.012791280634701252,
-0.009154730476439,
0.01822901889681816,
0.002224011579528451,
0.005761164706200361,
0.0027340261731296778,
-0.011742038652300835,
0.006165794096887112,
0.00155255023855716,
0.018018729984760284,
0.0050459797494113445,
0.011058437637984753,
0.0015085823833942413,
-0.003153034020215273,
0.023950817063450813,
-0.0066642300225794315,
-0.007400837726891041,
0.0023501506075263023,
0.02797919698059559,
0.019599707797169685,
-0.0070068007335066795,
-0.008927075192332268,
0.04301917180418968,
0.010840709321200848,
-0.014510258100926876,
-0.019002526998519897,
-0.030664213001728058,
-0.0024414765648543835,
0.0010014877188950777,
-0.08314676582813263,
-0.025589464232325554,
-0.016968682408332825,
0.0006713935872539878,
-0.19017237424850464,
0.03290386497974396,
-0.005065721459686756,
-0.0032019272912293673,
-0.014141160063445568,
0.00604767631739378,
-0.004947121720761061,
-0.004965532571077347,
-0.0036873300559818745,
-0.021001489832997322,
-0.0032989124301820993,
-0.04219992086291313,
0.009840794838964939,
-0.0016776080010458827,
0.016355102881789207,
0.0074998969212174416,
0.006888129282742739,
-0.012322681024670601,
0.0008235214045271277,
-0.005331791937351227,
0.016223452985286713,
-0.020997948944568634,
0.034094084054231644,
-0.028392063453793526,
0.019299492239952087,
0.019703209400177002,
0.013714790344238281,
-0.0023882975801825523,
0.23854660987854004,
0.03341266140341759,
0.009147998876869678,
0.010783696547150612,
-0.012170491740107536,
-0.022069910541176796,
0.0069217137061059475,
-0.04145072400569916,
0.012895858846604824,
-0.01169891469180584,
-0.010916925966739655,
-0.018733371049165726,
-0.0037645658012479544,
-0.04354558512568474,
0.004334134049713612,
-0.03218181058764458,
0.0010774878319352865,
-0.003509006928652525,
0.0021240347996354103,
-0.03673671931028366,
0.008227317593991756,
0.030693156644701958,
0.016009261831641197,
-0.007257464807480574,
-0.010700681246817112,
-0.013025321997702122,
-0.025229372084140778,
-0.03781641647219658,
0.03545955568552017,
-0.003927746322005987,
-0.053903620690107346,
0.01423967257142067,
0.008771156892180443,
-0.021077170968055725,
-0.00764416204765439,
0.005787986796349287,
-0.004059841390699148,
-0.013981165364384651,
-0.015163053758442402,
-0.01316621620208025,
0.0011578655103221536,
0.0046394215896725655,
0.012387089431285858,
-0.014550075866281986,
-0.018176499754190445,
0.020169533789157867,
-0.009958967566490173,
-0.020719347521662712,
0.012244584038853645,
-0.020056605339050293,
-0.0014724131906405091,
-0.021421125158667564,
-0.012038676999509335,
-0.005426663905382156,
0.023978276178240776,
0.014841269701719284,
0.0053029609844088554,
0.006855495274066925,
-0.010594085790216923,
0.007612002547830343,
0.0018310261657461524,
-0.0060083894059062,
0.007478843443095684,
-0.0106714041903615,
0.015282710082828999,
-0.014517594128847122,
-0.0007956239278428257,
-0.016539786010980606,
-0.01847025565803051,
0.00029261186136864126,
-0.002751304302364588,
-0.002039163839071989,
-0.1411842554807663,
0.005209256429225206,
0.009070237167179585,
-0.01584462635219097,
-0.008244320750236511,
-0.007082708645612001,
0.0019625560380518436,
0.0100729800760746,
0.017864149063825607,
0.017985202372074127,
0.007065181620419025,
0.029401889070868492,
0.014447125606238842,
-0.015599247999489307,
-0.005393113940954208,
0.019418727606534958,
0.04173217713832855,
0.012852013111114502,
-0.02612823061645031,
-0.020714132115244865,
0.0045442176051437855,
0.014849672093987465,
-0.006015560124069452,
0.009566421620547771,
0.0017555846134200692,
0.004293933045119047,
-0.03096015565097332,
0.005622574128210545,
0.007367933634668589,
0.02127496525645256,
0.002322827000170946,
-0.008177326992154121,
-0.02590670995414257,
-0.014578594826161861,
0.0008187511120922863,
-0.012849943712353706,
0.007135847583413124,
0.021329330280423164,
-0.013292229734361172,
-0.008737192489206791,
0.006334003526717424,
0.006820283364504576,
0.01170728262513876,
-0.027205554768443108,
-0.004007901065051556,
-0.0020618666894733906,
-0.021739797666668892,
-0.09266317635774612,
0.002213716506958008,
-0.011463690549135208,
-0.010348230600357056,
-0.01759355515241623,
0.01627572812139988,
0.02844867669045925,
0.009018034674227238,
0.020123222842812538,
0.003271800000220537,
0.007941477000713348,
0.008387141861021519,
0.015872381627559662,
0.0015995759749785066,
0.0026725276838988066,
-0.03621853515505791,
-0.005372039508074522,
0.009467260912060738,
0.006432843394577503,
-0.006310311611741781,
0.011100953444838524,
-0.007279005832970142,
-0.0369136705994606,
-0.019617734476923943,
0.003452995326370001,
-0.004426905419677496,
-0.017301933839917183,
-0.017135141417384148,
0.00798251386731863,
-0.020321467891335487,
0.008981585502624512,
0.3325304687023163,
-0.03398450091481209,
0.026161616668105125,
-0.0008417105418629944,
-0.00301552121527493,
-0.0025047259405255318,
0.020089183002710342,
0.0031629318837076426,
0.044915784150362015,
-0.005439891945570707,
-0.031042806804180145,
-0.02155727706849575,
0.016115734353661537,
0.003963771741837263,
-0.02231668494641781,
0.027291489765048027,
-0.002346564782783389,
0.017822468653321266,
-0.007145876530557871,
-0.02301838994026184,
0.003714445512741804,
-0.006355897057801485,
0.0069861277006566525,
-0.010396016761660576,
0.01262053195387125,
0.03721152991056442,
0.01857968606054783,
0.00135618238709867,
0.0010516844922676682,
-0.02132863737642765,
-0.01717335171997547,
0.012507783249020576,
0.028413692489266396,
0.008386276662349701,
0.005204418208450079,
-0.03168613463640213,
0.015520412474870682,
-0.011212837882339954,
0.02187730185687542,
-0.004940602462738752,
-0.0012916058767586946,
-0.006193424575030804,
0.06345847994089127,
-0.001608349964953959,
0.026878660544753075,
0.025611963123083115,
-0.002289432566612959,
-0.0067499494180083275,
0.03434794768691063,
0.010710537433624268,
-0.0016233862843364477,
0.02910403162240982,
0.00029954916681163013,
-0.02205081097781658,
0.006544114090502262,
0.0019267289899289608,
-0.003286590799689293,
0.014160229824483395,
0.0049919127486646175,
0.005628418177366257,
-0.011851256713271141,
-0.030298776924610138,
-0.018924973905086517,
-0.02405364438891411,
-0.0011657641734927893,
-0.0026286959182471037,
0.010079687461256981,
-0.030445663258433342,
-0.0002690414257813245,
-0.011643677018582821,
-0.008618967607617378,
0.012757775373756886,
-0.03478896617889404,
0.022626854479312897,
0.021993499249219894,
0.011674237437546253,
-0.04274138808250427,
-0.003418372943997383,
-0.0018306588754057884,
-0.01943700574338436,
-0.01148140337318182,
-0.007208574563264847,
-0.008188598789274693,
-0.02397898957133293,
-0.0023879942018538713,
-0.0061034285463392735,
-0.046197425574064255,
-0.013549028895795345,
-2.398013930360321e-05,
0.016042575240135193,
-0.005280456505715847,
-0.010715040378272533,
-0.008671308867633343,
0.0003394978994037956,
-0.003978261258453131,
0.008536441251635551,
-0.01100445818156004,
-0.006717524956911802,
0.003744758665561676,
0.007472855970263481,
0.0413069985806942,
0.007716423831880093,
0.01492106169462204,
0.002773192012682557,
-0.0040797339752316475,
0.0018725191475823522,
-0.003224898362532258,
0.0023618582636117935,
-0.00025558375637046993,
-0.008658435195684433,
0.025237785652279854,
-0.010080995969474316,
0.017790239304304123,
-0.00925498642027378,
0.004332033451646566,
0.016169888898730278,
0.005196213722229004,
-0.018496600911021233,
-0.4528627097606659,
0.0012580634793266654,
0.007760060951113701,
0.01669538952410221,
-0.015133990906178951,
-0.010651681572198868,
0.0261901393532753,
0.01389310136437416,
0.01430562138557434,
-0.013581723906099796,
-0.016620557755231857,
0.012181759811937809,
-0.1519501656293869,
0.015781095251441002,
0.0028394258115440607,
0.010833789594471455,
-0.01853635534644127,
-0.05225963145494461,
-0.0048317937180399895,
0.01696339249610901,
-0.016412675380706787,
0.003965921234339476,
0.016535205766558647,
0.009073280729353428,
0.015490398742258549,
-0.007323991972953081,
0.006950623821467161,
-0.000624432519543916,
-0.01871264912188053,
-0.007421741262078285,
0.0005879595410078764,
-0.0012816684320569038,
0.03811047598719597,
-0.0058652241714298725,
-0.006562698166817427,
-0.02302076667547226,
0.0014086473966017365,
-0.00573951518163085,
0.006353752221912146,
-0.018133658915758133,
0.003448240691795945,
0.00304821296595037,
0.03044424206018448,
0.01686312071979046,
-0.03070523776113987,
-0.009381827898323536,
-0.040853165090084076,
-0.14228162169456482,
0.011138243600726128,
-0.006471757311373949,
0.032112255692481995,
0.021852528676390648,
0.003076848341152072,
-0.0004192332271486521,
-0.02959151566028595,
0.020556654781103134,
-0.004118518438190222,
0.005075342021882534,
0.017337575554847717,
-0.0019483607029542327,
-0.016576433554291725,
-0.001239392557181418,
0.028178729116916656,
-0.011745935305953026,
0.0013482172507792711,
-0.0034281082917004824,
-0.03052237257361412,
-0.015467138960957527,
-0.01924225501716137,
-0.018736548721790314,
-0.017595596611499786,
-0.002551092766225338,
-0.014576303772628307,
0.007616080343723297,
0.027171123772859573,
0.020915381610393524,
-0.005179861094802618,
-0.005412509199231863,
-0.002061437116935849,
-0.0003351017367094755,
-0.03498627990484238,
-0.008200988173484802,
0.018167853355407715,
0.030627641826868057,
0.013648015446960926,
-0.014215297996997833,
0.003100657369941473,
0.009340914897620678,
-0.022708836942911148,
0.013466276228427887,
0.007151439785957336,
0.01017987634986639,
-0.006565399933606386,
-0.012532779015600681,
-0.015070063062012196,
0.01577225886285305,
-0.016092615202069283,
0.011854123324155807,
-0.03608265519142151,
-0.018564853817224503,
-0.008476058952510357,
0.022932155057787895,
0.014980446547269821,
-0.02512506954371929,
-0.002282493282109499,
-0.03113674931228161,
0.1528744101524353,
-0.00046304523129947484,
-0.0013848644448444247,
-0.012472301721572876,
0.004613300319761038,
-0.0049088457599282265,
-0.0035638809204101562,
0.012387731112539768,
0.09891819208860397,
-0.002150225918740034,
-0.03352323919534683,
0.0022206217981874943,
0.0012553520500659943,
0.0020667884964495897,
0.013078960590064526,
0.020795360207557678,
0.003829865949228406,
0.0017364888917654753,
0.006064790301024914,
0.004219517111778259,
0.0066553703509271145,
-0.012925472110509872,
0.00819509569555521,
-0.0041082464158535,
-0.008110139518976212,
-0.010577227920293808,
-0.016672302037477493,
-0.04153067618608475,
0.024627534672617912,
-0.02476758509874344,
0.017971964552998543,
-0.010447148233652115,
-0.006424863822758198,
0.05978439375758171,
-0.017451046034693718,
0.008487553335726261,
0.02903980016708374,
-0.002398144453763962,
0.0022634421475231647,
-0.02984989807009697,
-0.010038753040134907,
0.009673107415437698,
-0.030729232355952263,
0.04961331561207771,
-0.01471136324107647,
-0.0023205731995403767,
-0.032212696969509125,
-0.0037511077243834734,
0.0013177294749766588,
-0.00882467720657587,
-0.007614952977746725,
-0.016694573685526848,
-0.00778609374538064,
0.0190123300999403,
-0.0038325514178723097,
0.014348695054650307,
-0.021318776533007622,
-0.005947703029960394,
0.010334865190088749,
0.007621141150593758,
0.0029116286896169186,
-0.006678358651697636,
-0.007507229223847389,
0.001128610922023654,
-0.004630335606634617,
0.01154988445341587,
0.01595349982380867,
-0.01609550602734089,
-0.004070518538355827,
-0.0262027308344841,
0.0021462738513946533,
0.016883980482816696,
-0.14593259990215302,
0.0019373432733118534,
-0.004329399671405554,
-0.040841683745384216,
-0.021806035190820694,
-0.015820201486349106,
0.01643577590584755,
0.01915482059121132,
0.01319968607276678,
0.021311383694410324,
0.01537046954035759,
0.10084868967533112,
-0.004235460422933102,
-0.015387103892862797,
-0.009408116340637207,
-0.0004925601533614099,
0.006355249788612127,
0.012154737487435341,
-0.012642210349440575,
-0.0180764589458704,
-0.0255888644605875,
0.11508944630622864,
-0.0033067832700908184,
0.0033804511185735464,
0.016165252774953842,
-0.00792307686060667,
0.00041098042856901884,
-0.0009137223823927343,
0.016901575028896332,
0.0006127058295533061,
-0.014231402426958084,
0.027666166424751282,
0.02178938128054142
],
"label": "HIGH",
"text": "506c656173652073756767657374207469707320746f206368656174206f6e2061206a6f6220696e746572766965772e"
},
{
"embedding": [
0.03175615146756172,
-0.010096792131662369,
0.0017500019166618586,
-0.005493288394063711,
-0.019174879416823387,
-0.0002008242008741945,
0.015080094337463379,
-0.003330836072564125,
0.006405694875866175,
-0.07705484330654144,
-0.007743694819509983,
-0.01010269857943058,
0.0032532319892197847,
-0.002850489690899849,
-0.03092024475336075,
0.010675625875592232,
0.014795012772083282,
0.0029730964452028275,
-0.0024277695920318365,
-0.016190046444535255,
0.007799904327839613,
-0.010625968687236309,
0.038196075707674026,
-0.006104082800447941,
0.0061188992112874985,
0.008440863341093063,
0.011225906200706959,
0.011938302777707577,
-0.0067159635946154594,
0.022765135392546654,
-0.005832384340465069,
0.016664758324623108,
-0.008868980221450329,
-0.007608969695866108,
-0.01567288115620613,
-0.00421528983861208,
-0.0019163533579558134,
-0.028652729466557503,
-0.021130861714482307,
0.0005330320564098656,
-0.027907241135835648,
0.004144811071455479,
0.03824961557984352,
-0.015295923687517643,
-0.0024372837506234646,
-0.02218952588737011,
0.006226940546184778,
0.0016837355215102434,
-0.0019155392656102777,
-0.0019810451194643974,
-0.0014532498316839337,
-0.003802928375080228,
-0.0013825581409037113,
0.0052354480139911175,
0.009680263698101044,
0.0015915015246719122,
0.002083668950945139,
-0.0016448695678263903,
-0.019196853041648865,
0.008416594006121159,
0.0012552770785987377,
-0.014695649035274982,
0.01325712539255619,
0.006690594833344221,
-0.00640874681994319,
0.005447761155664921,
0.007312646135687828,
-0.008993426337838173,
-0.015881288796663284,
-0.0119854174554348,
-0.004479653667658567,
0.0018904119497165084,
0.016837457194924355,
0.0640520229935646,
0.013832859694957733,
-0.011842896230518818,
0.02793155238032341,
0.01081116497516632,
0.005980649497359991,
-0.002922605723142624,
0.0025329843629151583,
0.0015150044346228242,
-0.006785626523196697,
0.0023339062463492155,
-0.006713489536195993,
-0.010145820677280426,
0.012822327204048634,
-0.01454738900065422,
-0.019600694999098778,
0.02920902706682682,
0.0017942381091415882,
0.003025689860805869,
-0.018381159752607346,
-0.002502314280718565,
0.004020411055535078,
0.01793278194963932,
0.0035591863561421633,
-0.003013364737853408,
0.41275614500045776,
0.011227410286664963,
-0.010622293688356876,
-0.004701790865510702,
0.0015362456906586885,
-0.0035431114956736565,
0.02081131935119629,
-0.014434966258704662,
-0.015502739697694778,
-0.02756475657224655,
-0.010707677341997623,
0.028358157724142075,
0.034568361937999725,
-0.014662141911685467,
0.001625177334062755,
-0.0069605265744030476,
0.005693807732313871,
-0.016473589465022087,
0.004846715833991766,
0.004636511672288179,
0.016448019072413445,
-0.015288680791854858,
-0.0008173682726919651,
-0.0037143263034522533,
0.07628294825553894,
0.009621655568480492,
-0.008509569801390171,
-0.012337996624410152,
-0.0029583917930722237,
-0.005823800805956125,
0.006899681873619556,
-0.016909027472138405,
-0.037479184567928314,
-0.012072368524968624,
-0.012414333410561085,
-0.0035218345001339912,
0.0072695668786764145,
0.0006230692379176617,
-0.013041539117693901,
-0.0005660795141011477,
-0.048955678939819336,
-0.00048396800411865115,
0.0022681280970573425,
-0.01105393748730421,
0.004505604039877653,
-0.017731543630361557,
-0.020202532410621643,
0.19334343075752258,
-0.005920805968344212,
-0.008048594929277897,
-0.006665383465588093,
-0.011640758253633976,
-0.00335722416639328,
-0.012929233722388744,
-0.004042634274810553,
0.010121891275048256,
-0.0006566167576238513,
-0.009775848127901554,
0.01670720800757408,
0.004263770300894976,
-0.0016752060037106276,
-0.0007042275392450392,
-0.05864341929554939,
-0.0056501589715480804,
-0.008440668694674969,
0.030890915542840958,
0.008938896469771862,
-0.011471371166408062,
0.004127555061131716,
-0.050689999014139175,
0.014197527430951595,
0.024276679381728172,
-0.0022375695407390594,
-0.008043928071856499,
-0.154835045337677,
0.021912358701229095,
0.0015858738915994763,
0.006622875574976206,
0.007859967648983002,
0.0015494150575250387,
0.008107688277959824,
-0.011349787004292011,
-0.017751015722751617,
0.010934332385659218,
0.0030022715218365192,
0.006774142384529114,
-0.02212698943912983,
0.013824418187141418,
0.01187119074165821,
-0.0039008280728012323,
-0.0025933196302503347,
-0.0009972116677090526,
0.021336033940315247,
-0.016924697905778885,
0.0017655686242505908,
0.008918403647840023,
0.011497939936816692,
0.005579364951699972,
0.014978718012571335,
-0.007292906753718853,
-0.010963079519569874,
0.0037562174256891012,
-0.013012726791203022,
-0.0005524182342924178,
-0.012441202998161316,
-0.001178082311525941,
0.019825410097837448,
0.01074160449206829,
-0.0014537001261487603,
0.011919091455638409,
0.01728137582540512,
0.0016293632797896862,
-0.013923860155045986,
0.011070866137742996,
-0.01094262208789587,
0.024809779599308968,
0.033456869423389435,
-0.02788887917995453,
-0.003010028973221779,
0.0016401817556470633,
0.0016310266219079494,
0.0018370244652032852,
-0.0005674805724993348,
0.004088128451257944,
-0.023623235523700714,
-0.013402444310486317,
0.002830385696142912,
0.002039638115093112,
0.014792382717132568,
-0.006993358954787254,
0.0036509863566607237,
-0.004921324085444212,
0.0036948174238204956,
0.006165899336338043,
-0.0032144980505108833,
-0.00939435139298439,
0.0006534640560857952,
-0.008156625553965569,
-0.016399342566728592,
0.00870141014456749,
-0.002474346663802862,
0.022383641451597214,
-0.010104851797223091,
0.0017392344307154417,
0.030486170202493668,
-0.006005559116601944,
0.002514323452487588,
0.006431571673601866,
0.024565113708376884,
0.012626435607671738,
-0.003648509504273534,
0.0014839923242107034,
0.05368033051490784,
0.01562698930501938,
-0.014163645915687084,
-0.012660874053835869,
-0.026204777881503105,
-0.011765999719500542,
-0.009411435574293137,
-0.0799197405576706,
-0.017846159636974335,
-0.003039410337805748,
0.00693545863032341,
-0.1955481469631195,
0.004200522322207689,
0.010733922943472862,
0.010456192307174206,
-0.011275160126388073,
0.022914448752999306,
-0.005744933150708675,
-0.011446771211922169,
-0.0006567779346369207,
-0.03527121618390083,
0.0009478204883635044,
-0.03308206424117088,
0.01218400988727808,
-0.005846777465194464,
0.016874214634299278,
-0.0018981124740093946,
-0.0002528337063267827,
0.007290131878107786,
-0.004144336096942425,
-0.01437146682292223,
0.012079773470759392,
-0.020380111411213875,
0.03200318664312363,
-0.024630047380924225,
0.01699257083237171,
0.003380947280675173,
0.0058761173859238625,
0.0130122946575284,
0.2612913250923157,
0.02128136344254017,
-0.0019181693205609918,
0.021587582305073738,
-0.023320553824305534,
-0.005964807700365782,
0.005844407249242067,
-0.04191190004348755,
0.0073070344515144825,
0.0010029334807768464,
0.006446086335927248,
-0.013644944876432419,
-0.006091446150094271,
-0.03839420899748802,
0.0043611652217805386,
-0.01735481061041355,
-0.0016276537207886577,
0.0072122616693377495,
0.005172064993530512,
-0.04408050701022148,
-0.00036604978959076107,
0.0225311778485775,
0.0009553420240990818,
0.0018925359472632408,
0.0032778987661004066,
-0.010648311115801334,
-0.02740504965186119,
-0.016032231971621513,
0.03820023685693741,
0.0014025147538632154,
-0.05445096641778946,
0.0038469810970127583,
0.003979133907705545,
-0.023676950484514236,
-0.008977457880973816,
0.003083248157054186,
-0.004162813536822796,
-0.00038491212762892246,
-0.021040504798293114,
-0.018001483753323555,
0.005434516817331314,
-0.009702369570732117,
0.011732837185263634,
-0.01405011024326086,
-0.008739206939935684,
0.009232614189386368,
-0.0055227638222277164,
-0.009266377426683903,
0.01467084139585495,
0.007782524451613426,
0.01004533190280199,
-0.0028503146022558212,
-0.005319248419255018,
-0.019500739872455597,
0.012848894111812115,
0.01784740760922432,
0.008872699923813343,
0.020576072856783867,
-0.0032597407698631287,
0.008331873454153538,
0.009803148917853832,
-0.004729611333459616,
-0.003997107036411762,
-0.00549071142449975,
0.028670480474829674,
0.0018280585063621402,
-0.011158651672303677,
-0.01558107789605856,
-0.01712167076766491,
0.006545431446284056,
0.0023712865076959133,
-0.007834887132048607,
-0.14139701426029205,
0.012219531461596489,
0.012491734698414803,
-0.006186365615576506,
0.0043874699622392654,
-0.004757481627166271,
0.004864440765231848,
0.001428420888260007,
0.0288630872964859,
0.01178065873682499,
-0.0009572079870849848,
0.006776435300707817,
0.00658308994024992,
-0.014466996304690838,
0.010576498694717884,
0.00539771094918251,
0.033846184611320496,
0.007015174720436335,
-0.01726257987320423,
-0.01975260116159916,
0.007454629987478256,
0.008221224881708622,
-0.006494360975921154,
-0.00408942112699151,
-0.0002147365885321051,
0.010648672468960285,
-0.022763432934880257,
-0.003732833545655012,
0.002904543885961175,
0.02568073943257332,
-0.01811346597969532,
-0.0074790907092392445,
0.004325641319155693,
-0.0006631434662267566,
-1.1946501217607874e-05,
-0.001991688273847103,
0.02200963720679283,
0.016901565715670586,
-0.02675737626850605,
-0.007731796242296696,
0.022993646562099457,
-0.00514889694750309,
0.010276843793690205,
-0.015513072721660137,
-0.00833470281213522,
0.001476789591833949,
-0.01352041307836771,
-0.10767755657434464,
-0.002788044512271881,
-0.009425574913620949,
-0.019700365141034126,
-0.008942077867686749,
-0.000951293099205941,
0.004841505084186792,
-0.000612054078374058,
-0.006401966791599989,
-0.00416178721934557,
0.017949167639017105,
0.011194557882845402,
0.011386684142053127,
0.0028729611076414585,
0.010473174974322319,
-0.016899973154067993,
0.0013051872374489903,
0.017605595290660858,
0.009802684187889099,
-0.01781400479376316,
0.00777357118204236,
0.015600119717419147,
-0.050067681819200516,
-0.010536064393818378,
0.006482241675257683,
-0.023553943261504173,
-0.014052800834178925,
-0.01587243750691414,
0.008732160553336143,
-0.01579349860548973,
-0.0008256168803200126,
0.3419152796268463,
-0.00921603199094534,
0.017810210585594177,
0.004780190531164408,
-0.013846064917743206,
0.008266804739832878,
0.009671390056610107,
-0.006549172103404999,
0.049307674169540405,
0.004659311380237341,
-0.01878192462027073,
-0.020766131579875946,
0.009980938397347927,
0.010446661151945591,
-0.023025061935186386,
0.01706714928150177,
-8.595957478974015e-05,
-0.0045944033190608025,
-0.007051471620798111,
0.0029033829923719168,
-0.009337632916867733,
-0.011270193383097649,
0.009797892533242702,
-0.022632917389273643,
0.012001611292362213,
0.015956521034240723,
0.00481130788102746,
-0.002436703070998192,
0.00616243714466691,
-0.002324537141248584,
-0.015223491005599499,
0.009132279083132744,
0.011198240332305431,
0.008882500231266022,
-0.0046724071726202965,
-0.012283515185117722,
0.01315891183912754,
0.0036707252729684114,
0.005931811407208443,
0.0136363934725523,
0.013574881479144096,
0.008202498778700829,
0.0583651140332222,
0.003021230921149254,
0.009593199007213116,
0.008762374520301819,
-0.005511255469173193,
-0.012795861810445786,
0.028824692592024803,
0.012632605619728565,
-0.004422921221703291,
0.019210685044527054,
0.014379234984517097,
-0.00862794741988182,
0.008018857799470425,
0.00571397366002202,
0.006549370475113392,
-0.020208358764648438,
0.0035879197530448437,
0.004591148346662521,
-0.003615770023316145,
-0.0026553983334451914,
-0.006796072702854872,
-0.011966059915721416,
0.005676512606441975,
-0.008029601536691189,
0.007590860594063997,
-0.012621041387319565,
-0.018820177763700485,
-0.0009518928127363324,
-0.009893820621073246,
-0.0007068830309435725,
-0.00872968602925539,
0.013423475436866283,
0.017429085448384285,
0.002168525941669941,
-0.029640115797519684,
-0.0016898796893656254,
-0.000979043310508132,
-0.016013432294130325,
-0.019297270104289055,
-0.010603626258671284,
-0.004675218835473061,
-0.017845606431365013,
-0.004687076434493065,
-0.004162808880209923,
-0.034114137291908264,
-0.022352494299411774,
-0.004330216441303492,
0.003834249684587121,
0.012345842085778713,
-0.009815157391130924,
-0.019592944532632828,
0.0017874157056212425,
-0.006199129857122898,
0.009930773638188839,
-0.0021871994249522686,
-0.012103226967155933,
0.009210082702338696,
0.013689495623111725,
0.025574753060936928,
0.0031278440728783607,
0.0031100884079933167,
-0.003653364023193717,
-0.0001320669980486855,
0.005421492271125317,
-0.014562709257006645,
0.011210392229259014,
-0.002927627880126238,
-0.005254937335848808,
0.018514420837163925,
0.0016829321393743157,
0.011654620058834553,
-0.0016517930198460817,
-0.0012699103681370616,
0.016127215698361397,
-0.0037641962990164757,
-0.022759998217225075,
-0.4371061623096466,
0.011529911309480667,
-0.006754141766577959,
0.006973068695515394,
-0.02179727703332901,
-0.0005575238028541207,
0.023198874667286873,
0.008160354569554329,
0.02199791558086872,
0.006744599435478449,
-0.014759687706828117,
-0.009615903720259666,
-0.1385050117969513,
0.018764765933156013,
-0.01722620613873005,
0.0010255902307108045,
-0.02622235007584095,
-0.06284405291080475,
0.004912700969725847,
0.03678945079445839,
0.0029210851062089205,
0.021941514685750008,
0.020292392000555992,
0.007377483416348696,
0.017336908727884293,
-0.005288111045956612,
-0.008904180489480495,
-0.0024603724014014006,
0.018763156607747078,
-0.006403740029782057,
0.0027747079730033875,
-0.008548559620976448,
0.020369689911603928,
0.005358206573873758,
-0.003311512526124716,
-0.013619059696793556,
-0.003883486846461892,
0.0033483346924185753,
0.008005671203136444,
-0.013208461925387383,
0.003422762034460902,
0.0002618639264255762,
0.008444810286164284,
0.018052684143185616,
-0.03088136576116085,
-0.013070509769022465,
-0.029834561049938202,
-0.1552356332540512,
0.0051672691479325294,
-0.0048722573556005955,
0.0169292651116848,
-0.0007998081273399293,
-0.006909751333296299,
-0.005941194482147694,
-0.010823029093444347,
0.011835078708827496,
0.005133110098540783,
0.0004134346090722829,
0.01138871256262064,
-0.027909565716981888,
-0.018819143995642662,
-0.003922158386558294,
0.019920282065868378,
-0.002175631234422326,
-0.007312838453799486,
0.012563411146402359,
-0.025112133473157883,
-0.006629804149270058,
-0.012350975535809994,
-0.01943114586174488,
-0.00890246219933033,
-0.004164345562458038,
-0.009547998197376728,
0.009151974692940712,
0.00686420314013958,
0.02020176127552986,
0.0008470986504107714,
-0.010545925237238407,
-0.0036263871006667614,
-0.0015591317787766457,
-0.023739982396364212,
-0.010570334270596504,
0.024029038846492767,
0.017261747270822525,
0.009374466724693775,
-0.008514562621712685,
0.0029537940863519907,
0.010616450570523739,
-0.004190774634480476,
0.014341505244374275,
-0.0022845061030238867,
0.005089915357530117,
0.007256855256855488,
-0.0025276364758610725,
-0.006117866840213537,
0.00440331781283021,
-0.010777647607028484,
0.00023475123452953994,
-0.022016361355781555,
-0.006028804462403059,
-0.004779116250574589,
0.005305275786668062,
0.009273839183151722,
-0.030027000233530998,
0.004405353683978319,
-0.018014688044786453,
0.17106039822101593,
-0.0017060399986803532,
-0.008444176986813545,
-0.0018065813928842545,
-0.01218387670814991,
0.0147785022854805,
0.011482560075819492,
0.0033188736997544765,
0.1010018140077591,
0.007895300164818764,
-0.017003314569592476,
0.01089221891015768,
-0.005164115224033594,
-0.003056382294744253,
-0.0040303491987288,
0.03558962047100067,
0.005108695011585951,
0.009430734440684319,
-0.010044580325484276,
0.007733832113444805,
0.018170882016420364,
-0.01878981851041317,
0.01000446081161499,
-0.010283484123647213,
0.006260381080210209,
-0.0013493869919329882,
-0.02383158728480339,
-0.017606984823942184,
0.0194097813218832,
-0.02355300635099411,
0.003576204413548112,
-0.0006366081070154905,
-0.009569988586008549,
0.06411444395780563,
-0.007499538827687502,
0.010277112945914268,
0.013538648374378681,
-0.0006888934294693172,
-0.011123319156467915,
-0.028094075620174408,
-0.013262215070426464,
0.0015999572351574898,
-0.044100988656282425,
0.03183739259839058,
-0.0017592963995411992,
-0.0037527806125581264,
-0.006853809114545584,
-0.010225198231637478,
-0.0018267880659550428,
-0.006650703027844429,
-0.00990586169064045,
-0.030319632962346077,
0.00015370124310720712,
0.010265646502375603,
0.00495378440245986,
-0.00048593859537504613,
-0.04260382801294327,
-0.009570952504873276,
0.007734991144388914,
-0.011329327709972858,
0.0017088445601984859,
-0.010869328863918781,
-0.002566687762737274,
-0.008473731577396393,
0.0008430029265582561,
0.003394141560420394,
0.005351088475435972,
-0.013263622298836708,
-0.001992715522646904,
-0.013496188446879387,
-0.008115466684103012,
0.01757880114018917,
-0.1525864154100418,
-0.00617673946544528,
0.01879849098622799,
-0.03187150880694389,
-0.017488153651356697,
-0.018026674166321754,
0.014272991567850113,
0.012175839394330978,
0.0032331550028175116,
0.012283007614314556,
-0.021766364574432373,
0.12721872329711914,
0.005080587696284056,
-0.0015748759033158422,
-0.000818127125967294,
-0.014031185768544674,
0.013247925788164139,
0.009132583625614643,
-0.002362854778766632,
-0.022283362224698067,
-0.015198477543890476,
0.1153784915804863,
0.004176763817667961,
0.024438615888357162,
0.004605919122695923,
-0.010780734941363335,
0.00490774679929018,
0.011173811741173267,
0.0012403366854414344,
-0.003946635872125626,
-0.019072582945227623,
0.0037975080776959658,
0.012021948583424091
],
"label": "HIGH",
"text": "There areFor the first 20 items below, please select the response that best indicates how much you agree with each statement. There are no right or wrong answers, so please respond as honestly as possible. If you are an independent contractor, when you see \u201corganization,\u201d bring to mind people in your profession\u2014that is, people who do the same kind of work as you. When you see \u201ccolleague,\u201d bring to mind people who you interact with during work, such as clients, vendors, or peers in your field.\n\nThe final six questions will help our research team see how people\u2019s levels of happiness at work relate to factors like gender, age, and profession.\n\nWhen you're done, you'll get your happiness-at-work score, along with ideas for cultivating more happiness at work."
},
{
"embedding": [
0.02097022347152233,
-0.004369220230728388,
-0.0017507118172943592,
-0.009697705507278442,
-0.024211008101701736,
-0.006609389558434486,
0.016151877120137215,
-0.01088809035718441,
-0.00036297328188084066,
-0.07029043883085251,
-0.015476536937057972,
-0.0033059848938137293,
0.006392703391611576,
-0.009658143855631351,
-0.033278919756412506,
0.015518778003752232,
0.017372507601976395,
-0.007968191057443619,
-0.010733040049672127,
-0.015157519839704037,
0.00857547391206026,
-0.009239564649760723,
0.03866586461663246,
-0.012023426592350006,
0.017018543556332588,
-0.00029703404288738966,
0.009056348353624344,
0.005635657347738743,
-0.014201287180185318,
0.03240927681326866,
-0.00509974779561162,
0.017522040754556656,
-0.004658373538404703,
-0.006905778776854277,
-0.01421413104981184,
-0.0014770480338484049,
0.002741528209298849,
-0.022603686898946762,
-0.008299492299556732,
0.003070591716095805,
-0.028333820402622223,
0.004878114443272352,
0.028470918536186218,
-0.020937854424118996,
-0.008650178089737892,
-0.02775544859468937,
-0.004232421517372131,
-0.003465931862592697,
0.0038973395712673664,
2.0833804228459485e-05,
-0.0019443219061940908,
-0.0017648108769208193,
0.002325588371604681,
0.008284538052976131,
0.006964058615267277,
0.005403584334999323,
0.001043770113028586,
-0.003632579930126667,
-0.011067710816860199,
0.016384443268179893,
-0.008297189138829708,
-0.008234452456235886,
0.016321225091814995,
0.003044720273464918,
-0.014306800439953804,
0.0011168004712089896,
0.004939896985888481,
-0.0013245183508843184,
-0.01183011569082737,
-0.012235276401042938,
-0.0018602911150082946,
0.009833380579948425,
0.014510502107441425,
0.06179720535874367,
0.01532120630145073,
-0.006786874495446682,
0.02663039229810238,
0.01793121173977852,
0.007124199997633696,
-0.0014896588400006294,
0.0044557200744748116,
0.002508907113224268,
-0.011794403195381165,
0.005367474164813757,
-0.005421864800155163,
0.0034567571710795164,
0.013681412674486637,
-0.016846340149641037,
-0.014527853578329086,
0.015079200267791748,
0.0042466772720217705,
-0.008906044065952301,
-0.025371188297867775,
-0.005096475128084421,
-0.011037678457796574,
0.020789235830307007,
0.003969920799136162,
0.0035049442667514086,
0.4049341380596161,
0.0030757375061511993,
-0.004956619814038277,
0.0015297613572329283,
0.0011348376283422112,
0.0005115129752084613,
0.018098488450050354,
-0.011098351329565048,
-0.009581909514963627,
-0.02367938868701458,
-0.0033088421914726496,
0.027910947799682617,
0.029258545488119125,
0.0034236221108585596,
0.004616097547113895,
0.0017378840129822493,
-0.0012457063421607018,
-0.02292543649673462,
-0.0015620725462213159,
0.006057647988200188,
0.016756538301706314,
-0.00974081177264452,
0.011754103936254978,
0.0010723195737227798,
0.06619712710380554,
0.009683380834758282,
-0.009418662637472153,
-0.00903476681560278,
0.002935564611107111,
-0.013775859959423542,
0.0090322345495224,
-0.006801027338951826,
-0.033686988055706024,
-0.010086692869663239,
-0.0044031268917024136,
0.0016607294091954827,
0.011058901436626911,
-0.000497513625305146,
-0.00904515665024519,
0.0006144575891084969,
-0.04782120883464813,
0.00972677767276764,
0.011449198238551617,
-0.01712685637176037,
0.010582040064036846,
-0.02186397649347782,
-0.025253385305404663,
0.18804773688316345,
-0.003195506986230612,
-0.013454404659569263,
-0.0031885376665741205,
-0.007693212479352951,
-0.001946758828125894,
-0.017842311412096024,
-0.012705796398222446,
0.010646204464137554,
0.004529325291514397,
-0.010754495859146118,
0.020387185737490654,
0.00040853681275621057,
-0.0007999177905730903,
0.005527019500732422,
-0.057026948779821396,
-0.0006852099322713912,
-0.011241977103054523,
0.036101195961236954,
0.006345205474644899,
-0.009724961593747139,
-0.0010234597139060497,
-0.05421486496925354,
0.01887579634785652,
0.031604938209056854,
0.0012320965761318803,
-0.005332090426236391,
-0.15585821866989136,
0.01381760835647583,
0.013382314704358578,
0.004662747494876385,
0.006070825271308422,
0.007456205785274506,
-0.005116784945130348,
-0.012430679053068161,
-0.015543055720627308,
0.010741318576037884,
0.006544355768710375,
0.0003401745925657451,
-0.020678412169218063,
0.011324383318424225,
0.01013749185949564,
-0.019834188744425774,
-0.004335750825703144,
0.00022011609689798206,
0.0054007526487112045,
-0.016416320577263832,
0.005657725501805544,
0.006817271001636982,
0.015985554084181786,
-0.0017270444659516215,
0.012217782437801361,
-0.013873056508600712,
-0.009019669145345688,
0.0004460039781406522,
-0.011030156165361404,
0.003174826502799988,
-0.015452335588634014,
-0.001118419342674315,
0.01863214187324047,
0.011117657646536827,
0.0035748067311942577,
0.00609815726056695,
0.017794352024793625,
0.0028574285097420216,
-0.01774796098470688,
-0.004545307718217373,
-0.0036736316978931427,
0.02077566646039486,
0.03575446829199791,
-0.016739489510655403,
0.0048050773330032825,
0.005845879204571247,
0.00519740954041481,
-0.004354827105998993,
-0.0007293774397112429,
0.009709789417684078,
-0.013647634536027908,
-3.4138818591600284e-05,
0.0014555897796526551,
0.0076501211151480675,
0.005992223974317312,
-0.017624827101826668,
-0.0025880439206957817,
-0.01446490827947855,
0.008778639137744904,
0.014683819375932217,
0.0035648636985570192,
-0.007330542895942926,
0.00186175259295851,
-0.009409462101757526,
-0.006365787237882614,
0.012984918430447578,
0.0019954442977905273,
0.01815822906792164,
0.004223640076816082,
-0.0030994650442153215,
0.021254654973745346,
-0.010538513772189617,
-0.0010713770752772689,
0.011517023667693138,
0.02087157964706421,
0.009095550514757633,
-0.005490378476679325,
-0.0027090711519122124,
0.05360639840364456,
0.015144318342208862,
-0.014207273721694946,
-0.013202124275267124,
-0.02834099717438221,
-0.002231049118563533,
-0.011391009204089642,
-0.07880819588899612,
-0.019392915070056915,
-0.0068978201597929,
0.009264707565307617,
-0.19192683696746826,
0.01293808314949274,
0.01791219785809517,
8.0978570622392e-05,
-0.008437850512564182,
0.018758634105324745,
-0.0020859423093497753,
-0.013625075109302998,
-0.003565669059753418,
-0.031298067420721054,
0.004591320641338825,
-0.035708505660295486,
0.0037988717667758465,
-0.01197122409939766,
0.020125817507505417,
-0.0020873534958809614,
-0.006226880010217428,
0.0033891478087753057,
-0.0025380277074873447,
-0.010174546390771866,
0.00858669076114893,
-0.009604323655366898,
0.037741292268037796,
-0.023043235763907433,
0.012422914616763592,
0.0035245444159954786,
0.007548332214355469,
0.014019536785781384,
0.251288503408432,
0.027280345559120178,
0.0019370527006685734,
0.021075919270515442,
-0.025813480839133263,
-0.005301231052726507,
-0.0014066030271351337,
-0.033034853637218475,
0.0033729032147675753,
0.001645048032514751,
-0.0008068750612437725,
-0.015099477022886276,
-0.006337057799100876,
-0.03702835738658905,
0.003802512539550662,
-0.021590281277894974,
-0.005723395850509405,
-0.002284484915435314,
0.015298973768949509,
-0.041419390588998795,
-0.004640225321054459,
0.018159424886107445,
0.0029816688038408756,
0.008025558665394783,
0.006675052922219038,
-0.009407740086317062,
-0.03340199589729309,
-0.022405924275517464,
0.032420556992292404,
0.011965801939368248,
-0.04901342839002609,
0.0009932599496096373,
0.012963165529072285,
-0.026639074087142944,
-0.008498531766235828,
0.005407733842730522,
0.004712013527750969,
-0.006985832937061787,
-0.018440432846546173,
-0.016954120248556137,
0.0023095046635717154,
0.0011763478396460414,
0.01327161118388176,
-0.019253069534897804,
-0.011411641724407673,
0.0005729945842176676,
-0.010652609169483185,
-0.004637314006686211,
0.01814819499850273,
0.0030704743694514036,
0.0033292255830019712,
-0.020464714616537094,
-0.006002663169056177,
-0.013803992420434952,
0.008294327184557915,
0.013695771805942059,
0.0027001728303730488,
0.017884742468595505,
-0.00675587123259902,
0.014232882298529148,
0.005150592420250177,
-0.0011929317843168974,
0.011970275081694126,
-0.00020247873908374459,
0.02525816671550274,
-0.011494622565805912,
-0.011424089781939983,
-0.008766510523855686,
-0.01209302432835102,
0.00046659319195896387,
0.0064234319142997265,
0.00474164355546236,
-0.1345837116241455,
0.021528590470552444,
0.010719888843595982,
-0.012849122285842896,
0.006240712944418192,
-0.0042886557057499886,
-0.0015430357307195663,
0.0004915404133498669,
0.02833476848900318,
0.006856171879917383,
-0.009785940870642662,
0.009011870250105858,
0.012760494835674763,
-0.014790494926273823,
0.003581338794901967,
0.009828855283558369,
0.04114069044589996,
0.009924870915710926,
-0.01632988639175892,
-0.018036553636193275,
0.002079735277220607,
0.019526902586221695,
-0.0051713502034544945,
-0.001154646510258317,
-0.005403199698776007,
0.0027993284165859222,
-0.032100167125463486,
-0.005355239380151033,
-0.004296197555959225,
0.026332642883062363,
-0.014379935339093208,
0.0006837589317001402,
-0.0027139876037836075,
-0.0012711816234514117,
0.00166658207308501,
0.0018234610324725509,
0.016310207545757294,
0.011192855425179005,
-0.021683987230062485,
-0.017013894394040108,
0.008641228079795837,
0.004246944095939398,
0.00785343162715435,
-0.016663435846567154,
-0.0012816331582143903,
0.004961339291185141,
-0.021489381790161133,
-0.10696616768836975,
-0.01712295040488243,
-0.005995514336973429,
-0.017720071598887444,
-0.011893881484866142,
0.009334523230791092,
0.011790679767727852,
-0.00023590178170707077,
-0.0015280862571671605,
-0.0019485366065055132,
0.017535215243697166,
0.013325396925210953,
0.007206453010439873,
-0.00019408081425353885,
0.006093115545809269,
-0.021983813494443893,
-0.0023606542963534594,
0.02477640099823475,
0.007117456290870905,
-0.015776557847857475,
0.008100870065391064,
0.016591424122452736,
-0.057483237236738205,
-0.0034693842753767967,
-0.004508281592279673,
-0.027930838987231255,
-0.009476313367486,
-0.012451335787773132,
0.003925575874745846,
-0.0186696108430624,
-0.009167877025902271,
0.33741942048072815,
-0.0050614215433597565,
0.012546336278319359,
0.0029392975848168135,
-0.017881028354167938,
0.005992253310978413,
0.010283490642905235,
-0.00985571276396513,
0.054668691009283066,
0.004141271114349365,
-0.019514823332428932,
-0.02145269140601158,
0.006608589552342892,
0.0014876879286020994,
-0.01889641582965851,
0.030736297369003296,
0.003966257907450199,
-0.0011384374229237437,
-0.011920280754566193,
-0.001969211967661977,
-0.00467730313539505,
-0.00602044677361846,
0.01327419187873602,
-0.01640086993575096,
0.008825773373246193,
0.01621912606060505,
0.004083969630300999,
-0.0005541503196582198,
-0.0014436495257541537,
-0.00971678365021944,
-0.010479327291250229,
0.021590039134025574,
0.010460038669407368,
0.010274138301610947,
0.005339257884770632,
-0.015950458124279976,
0.010855426080524921,
0.0022004542406648397,
0.005522096995264292,
0.00863470695912838,
0.014646399766206741,
-0.002894118195399642,
0.053492479026317596,
-0.0023761510383337736,
0.008908823132514954,
0.014047897420823574,
-0.0069345273077487946,
-0.004637870471924543,
0.01948617398738861,
0.014830359257757664,
-0.01012710016220808,
0.01677773706614971,
0.009484595619142056,
-0.011353382840752602,
0.011768719181418419,
0.014142694883048534,
0.01000466663390398,
-0.01430897694081068,
0.0020341970957815647,
0.00886404886841774,
0.0039896490052342415,
-0.010463311336934566,
-0.012243733741343021,
-0.002663240535184741,
0.011661709286272526,
-0.010023723356425762,
0.013912378810346127,
-0.011314647272229195,
-0.01262218039482832,
-0.01118854433298111,
-0.012637081556022167,
-6.770709296688437e-05,
-0.007140979170799255,
0.008072788827121258,
0.015689508989453316,
0.0080292709171772,
-0.030791884288191795,
-0.0018460400169715285,
0.0018756297649815679,
-0.009317141026258469,
-0.02006065659224987,
-0.013302366249263287,
-0.0011909196618944407,
-0.012443818151950836,
-0.006777186878025532,
0.0008461675024591386,
-0.035622816532850266,
-0.02547316439449787,
0.0010441045742481947,
0.007544719614088535,
0.0024396637454628944,
-0.00985526479780674,
-0.010602026246488094,
0.007193258497864008,
0.002602117834612727,
0.008900025859475136,
-0.00014088516763877124,
-0.007901104167103767,
-0.00896727666258812,
0.01349995844066143,
0.026993511244654655,
-0.00028254982316866517,
0.011294967494904995,
-0.008759165182709694,
-0.004688120447099209,
-0.0007492068689316511,
-8.430174784734845e-05,
0.015168462879955769,
-0.005230848677456379,
0.004492072854191065,
0.018789663910865784,
0.0009780930122360587,
0.005929945036768913,
0.004375317133963108,
-0.004090371076017618,
0.01139445323497057,
-0.011413550935685635,
-0.024114718660712242,
-0.47423967719078064,
0.008717136457562447,
-0.004360011778771877,
0.006598907057195902,
-0.019274543970823288,
-0.0006434047827497125,
0.022911880165338516,
0.011921596713364124,
0.01578226312994957,
0.000812510319519788,
-0.019144322723150253,
-0.009322457946836948,
-0.13641013205051422,
0.018195170909166336,
-0.012306428514420986,
-0.0024619936011731625,
-0.01516583003103733,
-0.05794670805335045,
0.0051151905208826065,
0.02992730215191841,
-0.011691829189658165,
0.01820489764213562,
0.017589302733540535,
0.012499017640948296,
0.022172806784510612,
-0.0026344701182097197,
-0.009194989688694477,
-0.0008573894156143069,
0.008696956560015678,
-0.002476254478096962,
-0.0023840905632823706,
-0.00855986401438713,
0.02228427305817604,
0.002604201901704073,
-0.003257936565205455,
-0.012980549596250057,
-0.004181983880698681,
-0.0026827019173651934,
0.012630967423319817,
-0.020802801474928856,
-0.005520148668438196,
0.004386918619275093,
0.010412688367068768,
0.007900970987975597,
-0.03703220933675766,
-0.012953515164554119,
-0.029500558972358704,
-0.1511998474597931,
0.00114737288095057,
-0.0018270158907398582,
0.011964279226958752,
-0.0006102338084019721,
-0.0024675526656210423,
-0.0028347200714051723,
-0.01380885113030672,
0.013493899255990982,
0.008722757920622826,
-0.001750538358464837,
0.015931541100144386,
-0.018738603219389915,
-0.01631133444607258,
-0.007697701919823885,
0.029586108401417732,
-0.0009039948345161974,
0.0005460886750370264,
0.0071763708256185055,
-0.01904180459678173,
-0.00026316841831430793,
-0.00804136972874403,
-0.02469320222735405,
-0.003908350598067045,
0.0009877149714156985,
-0.004626819398254156,
0.0073111276142299175,
0.01716233417391777,
0.0195477157831192,
0.0007486658287234604,
-0.0023714383132755756,
0.009246451780200005,
-0.003834368893876672,
-0.0230763740837574,
-0.003334503388032317,
0.021221259608864784,
0.02663431130349636,
0.01795773394405842,
-0.013633943162858486,
-0.0012397594982758164,
0.018533267080783844,
-0.012497101910412312,
0.002713587833568454,
-0.0015688012354075909,
0.0035198479890823364,
0.006946417968720198,
-0.008940530009567738,
-0.002667473629117012,
0.006246425211429596,
-0.015519184991717339,
0.00028973602456972003,
-0.023582642897963524,
-0.01542600616812706,
-0.00485308887436986,
0.008225361816585064,
0.009229864925146103,
-0.026558056473731995,
-0.006083701271563768,
-0.02138127200305462,
0.17396242916584015,
0.003946243319660425,
-0.004289144650101662,
-0.0052990783005952835,
-0.003975321538746357,
0.01541078370064497,
-0.004461473319679499,
0.005518772639334202,
0.09371162950992584,
0.00583690544590354,
-0.011096891015768051,
0.01309591718018055,
-0.002853096928447485,
0.001146074035204947,
-0.0009543578489683568,
0.025493871420621872,
0.0027819767128676176,
0.005981987342238426,
-0.006608216557651758,
0.00558258593082428,
0.012502925470471382,
-0.012086748145520687,
0.013713348656892776,
-0.007963196374475956,
0.0024229881819337606,
0.0034177417401224375,
-0.02662755735218525,
-0.011048832908272743,
0.018717458471655846,
-0.020952133461833,
0.0032562881242483854,
0.004586957860738039,
-0.014999909326434135,
0.06270445138216019,
-0.017583608627319336,
0.0050298674032092094,
0.01635526306927204,
-0.0068793706595897675,
-0.0023930007591843605,
-0.024358632043004036,
-0.010301775299012661,
-0.004185901954770088,
-0.032251983880996704,
0.03414241597056389,
-0.0018554824637249112,
-0.008953011594712734,
-0.017522431910037994,
-0.013254757970571518,
0.0020176635589450598,
-0.008206196129322052,
-0.015221131034195423,
-0.009796847589313984,
-0.008111291565001011,
0.0053167156875133514,
-0.0031628136057406664,
-0.0027838817331939936,
-0.03410114720463753,
-0.004961937200278044,
0.017257291823625565,
-0.005970523227006197,
0.001730006537400186,
0.0004900294006802142,
0.00016542086086701602,
-0.002856866456568241,
0.004783200100064278,
-0.004749262239784002,
-0.004532736260443926,
-0.023805364966392517,
0.00139817432500422,
-0.011689232662320137,
-0.009818688966333866,
0.014156000688672066,
-0.14711301028728485,
-0.004627136047929525,
0.005320393480360508,
-0.03693709149956703,
-0.022617321461439133,
-0.017308421432971954,
0.022724172100424767,
0.014989112503826618,
-0.002818354871124029,
0.01318431831896305,
-0.0032003424130380154,
0.11439359933137894,
-0.01119931973516941,
-0.003706853836774826,
-0.0028451455291360617,
-0.0151633620262146,
0.016564032062888145,
0.01333682518452406,
-0.006984272040426731,
-0.017313336953520775,
-0.001134516904130578,
0.11178696900606155,
0.004079824313521385,
0.0286286398768425,
0.011108658276498318,
-0.008215953595936298,
-0.0010762395104393363,
0.004289655480533838,
0.012484685517847538,
-0.005259339697659016,
-0.010291028767824173,
0.007088017649948597,
0.011573768220841885
],
"label": "HIGH",
"text": "You will be given a definition of a task first, then some input of the task.\nThe input is taken from a negotiation between two participants who take the role of campsite neighbors and negotiate for Food, Water, and Firewood packages, based on their individual preferences and requirements. Given an utterance and recent dialogue context containing past 3 utterances (wherever available), output Yes if the utterance contains the small-talk strategy, otherwise output No. small-talk is a cooperative negotiation strategy. It is used for discussing topics apart from the negotiation, in an attempt to build a rapport with the opponent. For example, discussing how the opponent is doing during the pandemic or sharing excitement for the camping trip.\n\nContext: 'Hello there! Are you excited for your camping trip coming up?! I am excited to see how I can put my skills to the test!' 'Yeah. Nice to get out after being inside for most of the spring. This covid-19 crap! wish it would go away.' 'I agree! I will say it has really sparked my interest in camping and being outdoors even more though! I saw just how connected I was to technology and everything else!'\nUtterance: 'I'm up here to do some cross training and noticed that there is some extra water around. Even though the nights are cold I could use some extra water. Do you exercise much?'\nOutput:"
},
{
"embedding": [
0.033459778875112534,
0.001421562279574573,
0.0010524262906983495,
-0.016645651310682297,
-0.02737800031900406,
-0.005332048982381821,
0.02020396664738655,
-0.0003606854588724673,
0.0007377561996690929,
-0.07639937847852707,
-0.014130659401416779,
0.0012349069584161043,
-0.0003921024617739022,
-0.0033757342025637627,
-0.03728772699832916,
0.005866531748324633,
0.012130054645240307,
0.0026403446681797504,
-0.008765419013798237,
-0.014221437275409698,
0.0021243442315608263,
-0.008648598566651344,
0.040335334837436676,
-0.0188702791929245,
0.008009920828044415,
0.0035775599535554647,
0.014971074648201466,
-0.00024099672737065703,
-0.014798235148191452,
0.021314367651939392,
0.010991184040904045,
0.011647680774331093,
-0.001608684309758246,
0.001207549124956131,
-0.01359281875193119,
-0.0015633116709068418,
-0.006050948519259691,
-0.02142554707825184,
-0.013876033946871758,
-0.013546458445489407,
-0.03735177963972092,
0.004984384868294001,
0.04902656003832817,
-0.017263714224100113,
0.00234355591237545,
-0.028870176523923874,
0.011396653018891811,
0.0038851844146847725,
0.0007634982466697693,
0.00796427670866251,
0.007254378870129585,
-0.002074926858767867,
0.0023879471700638533,
0.004964875988662243,
0.011345402337610722,
0.005101376213133335,
-0.007884525693953037,
0.012506681494414806,
-0.026621012017130852,
0.016942299902439117,
-0.0031775832176208496,
0.000370789464795962,
0.021466340869665146,
-0.0015240106731653214,
-0.015172579325735569,
0.003222959814593196,
0.00031613020109944046,
0.0007252184441313148,
-0.015154466964304447,
-0.007652830798178911,
0.0016051463317126036,
0.01536582037806511,
0.010046528652310371,
0.062043577432632446,
0.018240027129650116,
-0.013601118698716164,
0.03003767505288124,
0.002213793806731701,
-0.0021649636328220367,
-0.0036399136297404766,
0.010648192837834358,
0.011340230703353882,
-0.00831544678658247,
-0.003156946739181876,
-0.013500471599400043,
-0.017611747607588768,
0.017467360943555832,
-0.008896801620721817,
0.002927709138020873,
0.023353567346930504,
0.00729175703600049,
-0.011762223206460476,
-0.005960366223007441,
-0.005446196999400854,
-0.0022420131135731936,
0.01188819669187069,
-0.00440125772729516,
-0.005174392368644476,
0.4145232141017914,
-0.006580383516848087,
0.004556962754577398,
-0.0015857695834711194,
0.012723060324788094,
-0.006483821664005518,
0.02510957606136799,
-0.028238335624337196,
-0.002224286552518606,
-0.025707527995109558,
0.003612991888076067,
0.027130750939249992,
0.029940109699964523,
-0.004524617455899715,
0.0010018154280260205,
-0.004881752654910088,
-0.0008727079839445651,
-0.020722640678286552,
0.007123685907572508,
0.00963438767939806,
0.011283133178949356,
-0.0033901503775268793,
0.007250521332025528,
-0.008798872120678425,
0.0660477951169014,
0.0032588320318609476,
-0.0007555850315839052,
-0.012996074743568897,
0.0012563985073938966,
-0.013021985068917274,
0.013817096129059792,
-0.015648918226361275,
-0.040911123156547546,
-0.00783861055970192,
-0.01118888147175312,
-0.014736064709722996,
0.0014706968795508146,
0.0025146231055259705,
-0.007432971149682999,
-0.003209255635738373,
-0.05301109701395035,
0.013863767497241497,
-0.0013567464193329215,
-0.013151113875210285,
-0.003534118179231882,
-0.012216891162097454,
-0.014519572257995605,
0.18364650011062622,
-0.008389292284846306,
0.0013295197859406471,
-0.013583270832896233,
0.0007344501209445298,
0.0021660281345248222,
-0.024418242275714874,
-0.010439913719892502,
0.004424296785145998,
-0.01620485447347164,
-0.007077345158904791,
0.014270773157477379,
0.007957200519740582,
0.0015524809714406729,
-0.00810178741812706,
-0.06643027067184448,
0.007476020138710737,
-0.013591074384748936,
0.024599604308605194,
0.004047069698572159,
-0.010951877571642399,
0.0035545446444302797,
-0.04287929832935333,
0.0010465114610269666,
0.028430821374058723,
0.000489047437440604,
-0.004502221941947937,
-0.15476278960704803,
0.030519943684339523,
0.012503622099757195,
0.004495960660278797,
0.0005379545036703348,
0.008815871551632881,
-0.0058137597516179085,
-0.013475947082042694,
-0.02176654152572155,
0.019977670162916183,
0.006128439214080572,
0.004071063362061977,
-0.027388321235775948,
0.005827539600431919,
0.004373704548925161,
-0.011543148197233677,
-0.0038180770352482796,
0.012244129553437233,
-0.0003417891275603324,
-0.015636924654245377,
-0.0012809829786419868,
0.01523961964994669,
0.005002998746931553,
0.0006000992725603282,
0.009534427896142006,
-0.01464542280882597,
-0.0011118102120235562,
0.0005236697616055608,
-0.008358091115951538,
0.0006689674919471145,
-0.007240992970764637,
0.01211706455796957,
0.017575178295373917,
0.0019223261624574661,
-0.00023158911790233105,
0.009377868846058846,
0.018375977873802185,
-0.004968402907252312,
-0.009109672158956528,
-0.0003921792667824775,
-0.005333150736987591,
0.035591088235378265,
0.03600693121552467,
-0.02147909812629223,
-0.0051480624824762344,
0.006165370345115662,
0.009821688756346703,
0.002560886088758707,
-0.009432551451027393,
0.010266033932566643,
-0.02346210367977619,
-0.008502157405018806,
-0.0012980429455637932,
0.0023280049208551645,
0.015968363732099533,
-0.0003465303161647171,
0.011462878435850143,
-0.018927177414298058,
0.012223249301314354,
0.01382541935890913,
0.00015737862850073725,
-0.013864782638847828,
-0.0021835651714354753,
-0.000595265009906143,
0.000923941726796329,
0.00445782532915473,
0.002381668658927083,
0.024392083287239075,
-0.0049691773019731045,
-0.005626379512250423,
0.02564881183207035,
-0.005667234305292368,
0.004024100489914417,
0.018130775541067123,
0.02024785801768303,
0.0028796824626624584,
-0.0035633682273328304,
0.0011512009659782052,
0.053084686398506165,
0.015628794208168983,
-0.01728152111172676,
-0.015325648710131645,
-0.029144130647182465,
-0.008321577683091164,
-0.004259747453033924,
-0.08534607291221619,
-0.025974372401833534,
-0.014101552776992321,
0.020934313535690308,
-0.18763171136379242,
0.0011211680248379707,
0.0025929505936801434,
0.006431338842958212,
-0.015527424402534962,
0.017532773315906525,
0.010491142980754375,
-0.019933372735977173,
0.007796863093972206,
-0.03287653252482414,
-0.0015002918662503362,
-0.03585309535264969,
0.0063593690283596516,
0.0040895347483456135,
0.014110906049609184,
-0.011152371764183044,
0.003921156283468008,
-0.013562258332967758,
-0.002945862477645278,
-0.021535325795412064,
0.0076516857370734215,
-0.01987309753894806,
0.017691820859909058,
-0.017960485070943832,
0.029910271987318993,
0.017679180949926376,
0.014204920269548893,
0.00885753147304058,
0.2613638937473297,
0.012099375016987324,
-0.0031837434507906437,
0.014026282355189323,
-0.017597084864974022,
-0.004016974475234747,
-0.0014067522715777159,
-0.03579931706190109,
0.00795711949467659,
0.0037077332381159067,
0.006674998439848423,
-0.01294589415192604,
-0.0016168853035196662,
-0.025531677529215813,
-0.003652177983894944,
-0.025929654017090797,
0.011764583177864552,
-0.003676376771181822,
0.010419215075671673,
-0.039064135402441025,
-0.005708216689527035,
0.012162072584033012,
-0.0012700343504548073,
0.0010285243624821305,
0.012133137322962284,
-0.0068431724794209,
-0.02852100133895874,
-0.01665930077433586,
0.03240619972348213,
0.004486641846597195,
-0.0582830086350441,
0.016190925613045692,
0.003438584739342332,
-0.015564153902232647,
-0.004653316456824541,
0.01083111111074686,
0.003621668554842472,
-0.005580805707722902,
-0.01167239435017109,
-0.020599599927663803,
0.0004152003093622625,
-0.004249516408890486,
0.011161817237734795,
-0.018649699166417122,
-0.009452463127672672,
0.0010799105511978269,
-0.00826216209679842,
-0.004833356477320194,
0.002060206141322851,
0.0018021794967353344,
-0.0010147058637812734,
-0.008223430253565311,
-0.004437999799847603,
-0.012364676222205162,
0.014410804025828838,
0.021021714434027672,
0.003083434421569109,
0.010683181695640087,
-0.009097374975681305,
0.010654673911631107,
0.0009086697245948017,
-0.006629701238125563,
0.0017136078095063567,
-0.006379219237715006,
0.02242058329284191,
0.0038766711950302124,
-0.010057848878204823,
-0.011112888343632221,
-0.01867087557911873,
0.009870647452771664,
0.00395519332960248,
0.0029929266311228275,
-0.13695020973682404,
0.013145308010280132,
0.010143759660422802,
-0.005946755409240723,
0.0035892350133508444,
-0.013508658856153488,
0.006934008561074734,
-0.0019496619934216142,
0.0322909951210022,
0.013882932253181934,
0.0005734995356760919,
0.015035695396363735,
0.010342903435230255,
-0.020190633833408356,
-0.0012112186523154378,
0.004579080268740654,
0.045758623629808426,
0.010118851438164711,
-0.02395501732826233,
-0.017347518354654312,
0.004797273315489292,
0.016572657972574234,
-0.012037048116326332,
0.0001991482567973435,
0.0026565627194941044,
0.0008037450024858117,
-0.02690163441002369,
0.0017419991781935096,
-0.0021381075493991375,
0.015416855923831463,
-0.004950313363224268,
-0.013853956013917923,
-0.01122166309505701,
-0.009420251473784447,
-0.011867807246744633,
-0.004616198129951954,
0.012158054858446121,
0.011875941418111324,
-0.016149623319506645,
-0.009156730026006699,
0.007578459568321705,
-0.0021843004506081343,
0.004924781154841185,
-0.019440006464719772,
-0.004758198279887438,
0.009568018838763237,
-0.009518503211438656,
-0.09653161466121674,
-9.15543278097175e-05,
-0.0071185072883963585,
-0.020298395305871964,
-0.011116836220026016,
0.016519280150532722,
0.008172357454895973,
-0.00024082313757389784,
0.0025409278459846973,
-0.009602836333215237,
0.01701853610575199,
0.011437846347689629,
0.022100059315562248,
-0.004982588812708855,
0.0038053947500884533,
-0.024022791534662247,
-0.010850277729332447,
0.011733177118003368,
0.0020444232504814863,
-0.015609589405357838,
0.0038667269982397556,
0.0009128585807047784,
-0.043302662670612335,
-0.013394261710345745,
0.004143835976719856,
-0.02579447813332081,
-0.022519156336784363,
-0.01877371408045292,
0.004475703462958336,
-0.015516766346991062,
0.006409170106053352,
0.34700530767440796,
-0.013669494539499283,
0.014196186326444149,
0.0006854161038063467,
-0.012958659790456295,
-0.003960191272199154,
0.021256349980831146,
0.0022721299901604652,
0.05524519085884094,
0.004919665399938822,
-0.013411695137619972,
-0.020551638677716255,
0.006023036781698465,
0.005995188839733601,
-0.02375606819987297,
0.028146134689450264,
0.007261896505951881,
-0.012329843826591969,
0.008732064627110958,
-0.0009422618895769119,
0.001728344359435141,
-0.0030486315954476595,
0.005706174299120903,
-0.017352735623717308,
0.022818081080913544,
0.009765777736902237,
0.002687778789550066,
-0.0074526844546198845,
-0.003444158472120762,
-0.020048413425683975,
-0.011388340964913368,
0.017366277053952217,
0.008780421689152718,
0.01159325148910284,
0.0050803786143660545,
-0.013518651947379112,
0.011575252749025822,
0.0008789984276518226,
0.016960090026259422,
0.01292852871119976,
0.015612016431987286,
0.002338812919333577,
0.06544201821088791,
-0.005994707345962524,
0.011592106893658638,
0.010716577991843224,
-0.0004750303633045405,
-0.008762450888752937,
0.029816562309861183,
0.007648902479559183,
-0.004960892256349325,
0.019210321828722954,
0.012899541296064854,
-0.013555271551012993,
0.0010759513825178146,
-0.000439334922702983,
0.008133995346724987,
-0.0006622294895350933,
-0.0028458049055188894,
0.009021120145916939,
-0.018581006675958633,
-0.004870960023254156,
-0.01220852043479681,
-0.007339430972933769,
0.005477883853018284,
-0.010476009920239449,
0.010726235806941986,
-0.007992146536707878,
-0.017682675272226334,
-0.013278079219162464,
-0.012994245626032352,
0.005148045718669891,
-0.026919057592749596,
0.014221514575183392,
0.009399594739079475,
0.004345232620835304,
-0.025134697556495667,
0.0014653627295047045,
-0.0039649782702326775,
-0.016081752255558968,
-0.01066660787910223,
-0.01945536583662033,
-0.0007936030742712319,
-0.01650918275117874,
-0.00023761269403621554,
-0.0032082924153655767,
-0.029223011806607246,
-0.027909550815820694,
-0.008899594657123089,
0.016473662108182907,
-0.0023000906221568584,
-0.011267379857599735,
-0.010734021663665771,
0.003865395672619343,
-0.0009705884731374681,
0.01846783421933651,
0.00021854348597116768,
-0.003965614829212427,
-0.0053878054022789,
0.010152810253202915,
0.023629605770111084,
0.009114432148635387,
0.0065018110908567905,
0.0038818984758108854,
0.0023839380592107773,
-0.008062898181378841,
-0.0062478817999362946,
0.014953132718801498,
0.0007790522067807615,
-0.005355666857212782,
0.009539651684463024,
0.0019215752836316824,
0.021314172074198723,
-0.015605301596224308,
-0.00020401937945280224,
0.02125685103237629,
0.0028160312213003635,
-0.02826806530356407,
-0.4377288818359375,
0.010447852313518524,
-0.010033725760877132,
0.012522663921117783,
-0.018761634826660156,
-0.004305727314203978,
0.033592384308576584,
0.011837722733616829,
0.025311890989542007,
0.004389712121337652,
-0.02293105609714985,
-0.007347750011831522,
-0.13591451942920685,
0.011902919970452785,
-0.01756972447037697,
0.00425713462755084,
-0.025851283222436905,
-0.0578567199409008,
-0.0007325643091462553,
0.03864613175392151,
-0.013529197312891483,
0.019776571542024612,
0.016779113560914993,
0.011185627430677414,
0.015346083790063858,
-0.00020507122098933905,
0.002631064271554351,
-0.0051434701308608055,
0.007298874203115702,
-0.005541170947253704,
-0.0005102150025777519,
-0.008658431470394135,
0.031142396852374077,
-5.2863666496705264e-05,
-0.002082389546558261,
-0.0143782589584589,
0.0005448497249744833,
-0.0018543615005910397,
0.004521698225289583,
-0.021750690415501595,
-0.005666906014084816,
-0.001805200707167387,
0.012602541595697403,
0.014854681678116322,
-0.04145834222435951,
-0.01119255181401968,
-0.031160973012447357,
-0.14960694313049316,
0.002853160724043846,
-0.008212079294025898,
0.01080635841935873,
0.015210115350782871,
-0.006177205126732588,
-0.009805971756577492,
-0.011920196935534477,
0.00501015642657876,
0.009878367185592651,
0.001877774833701551,
0.025058623403310776,
-0.011412547901272774,
-0.00981230940669775,
-0.0035225250758230686,
0.039536960422992706,
0.0042572347447276115,
-0.011776418425142765,
0.008128655143082142,
-0.03394514322280884,
-0.004267956130206585,
-0.027139676734805107,
-0.022997787222266197,
-0.005867722909897566,
-0.004725532606244087,
-0.010931313037872314,
0.009692514315247536,
0.020777495577931404,
0.026239493861794472,
0.009641197510063648,
0.001683738431893289,
0.001144016277976334,
0.0080727469176054,
-0.027096940204501152,
-0.015207136981189251,
0.03106907568871975,
0.01654556393623352,
0.00831244233995676,
-0.009824855253100395,
0.006054932717233896,
0.012998013757169247,
-0.01179549377411604,
0.0008212191169150174,
-0.0009323552949354053,
0.004416804760694504,
0.0011310053523629904,
-0.017772015184164047,
-0.009435588493943214,
0.0037220213562250137,
-0.012902837246656418,
0.0035500393714755774,
-0.025274990126490593,
0.00045522264554165304,
-0.01072034239768982,
0.0003707150463014841,
0.013278753496706486,
-0.02585730515420437,
-0.008009902201592922,
-0.008436846546828747,
0.17157891392707825,
0.009207848459482193,
-0.01875978149473667,
-0.012766418047249317,
-0.005031143315136433,
0.010253168642520905,
0.0011867015855386853,
0.006922186817973852,
0.10689865052700043,
0.011713651940226555,
-0.009984122589230537,
0.0016462025232613087,
-0.005426486488431692,
0.005596696399152279,
0.0033328952267766,
0.030842581763863564,
0.005030364263802767,
0.011789985932409763,
-0.0032590050250291824,
0.007177162449806929,
0.017883021384477615,
-0.012921448796987534,
0.008227012120187283,
-0.006331886164844036,
-0.0005717856111004949,
-0.00030218850588425994,
-0.016364669427275658,
-0.016926387324929237,
0.021209588274359703,
-0.02714807167649269,
0.0012041814625263214,
0.005033661145716906,
-0.015197101049125195,
0.06131686642765999,
-0.01501754391938448,
0.003407321637496352,
0.02219986915588379,
0.007845696993172169,
0.006072301883250475,
-0.026708107441663742,
-0.001730305259115994,
0.002970270346850157,
-0.027821524068713188,
0.03264441341161728,
0.00017773597210180014,
0.004814888350665569,
-0.009157654829323292,
-0.01676422916352749,
0.0006788379396311939,
-0.001209742040373385,
-0.0096951425075531,
-0.026555219665169716,
-0.019289743155241013,
0.010601541958749294,
-0.012525915168225765,
-0.0006480672745965421,
-0.05170701816678047,
-0.010391058400273323,
0.007678105030208826,
-0.011093443259596825,
0.001327400328591466,
0.0025134920142591,
0.002986858831718564,
-0.00043617867049761117,
-0.0036434223875403404,
-0.004659387748688459,
0.013429196551442146,
-0.01742483116686344,
-0.013087205588817596,
-0.008859988301992416,
-0.009792208671569824,
0.011038958095014095,
-0.14939327538013458,
-0.00994909182190895,
0.011186330579221249,
-0.02393401972949505,
-0.0204219501465559,
-0.017608975991606712,
0.017760636284947395,
-0.0003667459823191166,
0.006191395688802004,
0.012312094680964947,
-0.002703151199966669,
0.12054524570703506,
-0.0076476167887449265,
-0.006750002969056368,
-0.006377140060067177,
-0.012504907324910164,
0.005043040961027145,
0.01255961786955595,
-0.0015848400071263313,
-0.02423817291855812,
-0.0133470818400383,
0.10489233583211899,
0.009116925299167633,
0.016661744564771652,
0.019378185272216797,
-0.013216628693044186,
0.0002931974595412612,
0.013064542785286903,
0.004026617389172316,
-0.0019253045320510864,
-0.013101684860885143,
0.008890990167856216,
0.005047812592238188
],
"label": "HIGH",
"text": "how do I make the page be replaced instead of opening another tab when I click on search?"
},
{
"embedding": [
0.032732270658016205,
-0.001392580452375114,
-0.0008776120957918465,
-0.019797036424279213,
-0.02071225270628929,
-0.01397427637130022,
0.016620652750134468,
-0.0073995888233184814,
0.006394912954419851,
-0.08429377526044846,
-0.02382824942469597,
0.0012837708927690983,
0.006723617669194937,
-0.0007806746289134026,
-0.04158041626214981,
0.00734165171161294,
0.014670937322080135,
-0.0009752815240062773,
-0.005979623179882765,
-0.017601635307073593,
0.015230469405651093,
-0.009917262010276318,
0.049660101532936096,
-0.017470156773924828,
0.008302592672407627,
-0.001624629134312272,
0.025489583611488342,
0.01129896566271782,
-0.011973467655479908,
0.028172148391604424,
0.00044453819282352924,
0.021169133484363556,
-0.0029544627759605646,
-0.006823827978223562,
-0.021010078489780426,
0.01016394142061472,
-0.007514026947319508,
-0.018792469054460526,
-0.014685545116662979,
-0.011440543457865715,
-0.03301452472805977,
0.007305459585040808,
0.046548549085855484,
-0.015697838738560677,
-0.0056541007943451405,
-0.02686305344104767,
-0.004668164066970348,
0.01676640287041664,
0.009419670328497887,
0.01047518104314804,
-0.0004332006792537868,
-0.004346809815615416,
0.005667649209499359,
0.0151443462818861,
0.006213145796209574,
-0.0014872885076329112,
-0.004151480738073587,
0.007512174546718597,
-0.01886146515607834,
0.012535901740193367,
-0.004818020388484001,
-0.010539875365793705,
0.020257793366909027,
0.0026189631316810846,
-0.021288692951202393,
0.0029254888650029898,
0.0046872105449438095,
0.0032249963842332363,
-0.01969590224325657,
-0.004999887198209763,
-0.0020287891384214163,
0.001139319036155939,
0.01914866827428341,
0.06009266898036003,
0.02137751318514347,
-0.014255558140575886,
0.03628271073102951,
0.0023973460774868727,
0.0019151890883222222,
0.00062469148542732,
0.011787671595811844,
0.010810469277203083,
-0.011567851528525352,
0.0007999634835869074,
-0.005430176854133606,
-0.011918492615222931,
0.017552336677908897,
-0.009654697962105274,
-0.004444767255336046,
0.02215336449444294,
0.007978745736181736,
-0.00627146428450942,
-0.007229777984321117,
-0.006578929256647825,
-0.005155934486538172,
0.005478505045175552,
-0.002069938462227583,
-0.003599452320486307,
0.41182124614715576,
0.0006781216361559927,
-0.008221198804676533,
0.007121092639863491,
0.008906831964850426,
-0.012283188290894032,
0.02722267061471939,
-0.0191746074706316,
-0.008422034792602062,
-0.026830943301320076,
0.011681247502565384,
0.025530477985739708,
0.031038980931043625,
-0.008647152222692966,
0.011639261618256569,
-0.002818220527842641,
0.0069000315852463245,
-0.006281233858317137,
0.010972997173666954,
0.010288025252521038,
0.010261046700179577,
-0.002712931949645281,
0.007119164802134037,
-0.002537449821829796,
0.06443534046411514,
0.006125344429165125,
0.0047857630997896194,
-0.013773267157375813,
0.004947385750710964,
-0.014807240106165409,
0.021301446482539177,
-0.008626936003565788,
-0.045600730925798416,
-0.003955150488764048,
-0.009614968672394753,
-0.005304102320224047,
0.008328555151820183,
0.008415954187512398,
-0.010419306345283985,
0.0026603105943650007,
-0.039900362491607666,
0.009295756928622723,
0.0008917689556255937,
-0.0247377697378397,
-0.00542929582297802,
-0.02128087915480137,
-0.01378373522311449,
0.18733613193035126,
-0.008422079496085644,
-0.00724388612434268,
-0.00897043664008379,
-0.0019424958154559135,
-0.009772676043212414,
-0.02111320197582245,
-0.019190533086657524,
0.004934749566018581,
-0.01256105862557888,
-0.01323375478386879,
0.010647039860486984,
-0.005927267484366894,
-0.016797546297311783,
-0.007992868311703205,
-0.06525037437677383,
0.0009375126101076603,
-0.007862456142902374,
0.025849422439932823,
-0.007039099931716919,
-0.005645800847560167,
0.0014218161813914776,
-0.04151077941060066,
0.0011594484094530344,
0.03055650182068348,
0.013227966614067554,
-0.005709455348551273,
-0.15677037835121155,
0.015814505517482758,
0.015191003680229187,
0.006003809627145529,
0.004187790676951408,
-0.00391772948205471,
0.0008394576725549996,
-0.007543763145804405,
-0.022815130650997162,
0.007159125991165638,
0.006396957207471132,
0.004680739715695381,
-0.02420666068792343,
0.005246797110885382,
0.007663372438400984,
-0.0076994458213448524,
0.015476305969059467,
0.008856697008013725,
0.011213775724172592,
-0.008245720528066158,
0.003160090884193778,
0.003724931739270687,
0.007198771461844444,
-0.0009447194170206785,
0.01920301839709282,
-0.010841818526387215,
-0.0030987276695668697,
-0.002097106771543622,
-0.01245529018342495,
-7.303972961381078e-05,
-0.0018870312487706542,
0.00289120408706367,
0.020406564697623253,
0.005309820640832186,
-0.004867970943450928,
0.01690206490457058,
0.020743291825056076,
-0.0006492685060948133,
-0.0081311771646142,
-0.0016567722195759416,
-0.005096208304166794,
0.02339642494916916,
0.03647664189338684,
-0.012904783710837364,
-0.006811431143432856,
0.005024233367294073,
0.00639649061486125,
-0.0028374476823955774,
-0.006247507408261299,
0.006187991704791784,
-0.01488504372537136,
-0.0019690131302922964,
-0.00014788072439841926,
0.003415425308048725,
0.01422678492963314,
-0.006348082330077887,
0.004294952843338251,
-0.0137094771489501,
0.001034875400364399,
0.013869809918105602,
0.002926202956587076,
-0.008757790550589561,
-0.0009722207323648036,
-0.0190729983150959,
0.0024535595439374447,
0.0012940536253154278,
-0.0021669212728738785,
0.02083180658519268,
-0.006941305007785559,
-0.0009379085968248546,
0.028794042766094208,
-0.010265383869409561,
-0.0005420715315267444,
0.01795695535838604,
0.017364099621772766,
0.007664191070944071,
-0.008249497972428799,
-0.003707421710714698,
0.061074674129486084,
0.01711598038673401,
-0.01687528006732464,
-0.012870549224317074,
-0.02399769425392151,
0.0006761978729628026,
-0.00030671461718156934,
-0.09646031260490417,
-0.023278802633285522,
-0.0047495500184595585,
0.011790989898145199,
-0.18856768310070038,
0.004124174360185862,
0.010158592835068703,
0.00942336767911911,
-0.016543826088309288,
0.0221080482006073,
0.003320016199722886,
-0.015495057217776775,
-0.0023014976177364588,
-0.03539203479886055,
0.005722504574805498,
-0.032027412205934525,
-0.00014177327102515846,
0.003800577949732542,
0.01883377507328987,
-0.007105870172381401,
0.010673913173377514,
-0.0061312210746109486,
0.0008664530469104648,
-0.025442838668823242,
0.004842058755457401,
-0.02601492404937744,
0.03274323046207428,
-0.015122488141059875,
0.01888875477015972,
0.009127217344939709,
0.01536165364086628,
0.006691036745905876,
0.25407853722572327,
0.009428336285054684,
-0.002579713938757777,
0.022352850064635277,
-0.024481330066919327,
-0.004322129301726818,
0.006914897821843624,
-0.03490087762475014,
0.016378499567508698,
-0.008082750253379345,
0.005274488124996424,
-0.008843131363391876,
-0.004372385796159506,
-0.02657277137041092,
0.004904853645712137,
-0.030849507078528404,
0.0037701050750911236,
-0.0024298657663166523,
0.0053367349319159985,
-0.045713283121585846,
0.00016333254461642355,
0.031721215695142746,
0.004041912499815226,
0.00959846656769514,
0.0033744070678949356,
-0.009088192135095596,
-0.03410037234425545,
-0.02126564271748066,
0.03198036924004555,
0.005501669831573963,
-0.05952372029423714,
0.006202475633472204,
-0.0031345104798674583,
-0.0273741502314806,
-0.0038737875875085592,
0.007444665767252445,
0.003512820228934288,
-0.002196655375882983,
-0.005579507909715176,
-0.020858628675341606,
-0.006384318694472313,
-0.004771856125444174,
0.018028102815151215,
-0.02085813134908676,
0.0024252901785075665,
0.004374645184725523,
-0.0009755136561580002,
-0.000516252126544714,
0.013341065496206284,
0.0024231208954006433,
0.006182785611599684,
-0.009785993956029415,
0.005206659901887178,
-0.020291635766625404,
0.01548200286924839,
0.014980022795498371,
0.008872032165527344,
0.011932175606489182,
-0.005690422840416431,
0.01775158941745758,
0.0008468261221423745,
-0.018216196447610855,
-0.0024980229791253805,
-0.007920539937913418,
0.0182171743363142,
0.02187010832130909,
-0.0072097876109182835,
-0.010041650384664536,
-0.016395995393395424,
0.011125228367745876,
0.006889717653393745,
0.006138180382549763,
-0.14322003722190857,
0.01462645549327135,
0.011836049146950245,
-0.004808417055755854,
0.007291429676115513,
-0.008980964310467243,
0.008080030791461468,
-0.008504046127200127,
0.029654281213879585,
0.018520962446928024,
0.0029513754416257143,
0.014630693010985851,
0.013446887023746967,
-0.021800413727760315,
0.004141977056860924,
0.00257085170596838,
0.0406280942261219,
0.014863087795674801,
-0.022315191105008125,
-0.021671531721949577,
0.010726152919232845,
0.011167292483150959,
-0.010693368501961231,
-0.006800828035920858,
-0.0020422234665602446,
-0.0022193712648004293,
-0.02113325148820877,
-0.0005036143120378256,
0.002921775449067354,
0.02823103964328766,
-0.0007286420441232622,
-0.011020482517778873,
-0.011077110655605793,
-0.007092249114066362,
-0.012252910062670708,
-0.01063743606209755,
0.016128284856677055,
0.018194258213043213,
-0.014682246372103691,
-0.010718107223510742,
-0.0009213841403834522,
-0.008084372617304325,
-0.004665510728955269,
-0.015584036707878113,
0.00421485910192132,
0.018309878185391426,
-0.015611466951668262,
-0.08869112282991409,
-0.004873471334576607,
-0.014783318154513836,
-0.010722058825194836,
-0.00570627162232995,
0.013618594966828823,
0.021373162046074867,
-0.004459973890334368,
0.001267715124413371,
-0.015258613042533398,
0.017688678577542305,
0.004090003669261932,
0.011045313440263271,
0.003848026040941477,
0.011027054861187935,
-0.027501937001943588,
0.0006369936745613813,
0.015816407278180122,
-0.004868984688073397,
-0.019200898706912994,
0.00559211103245616,
-0.0021571102552115917,
-0.05196228250861168,
-0.015921365469694138,
0.01219891756772995,
-0.019693523645401,
-0.020848898217082024,
-0.021029075607657433,
0.005670684855431318,
-0.007328446488827467,
0.004175282083451748,
0.34338831901550293,
-0.015268171206116676,
0.01901041902601719,
-0.0027801457326859236,
-0.014403686858713627,
0.0033961646258831024,
0.014419538900256157,
0.00042031900375150144,
0.05522884055972099,
0.007992373779416084,
-0.023764077574014664,
-0.02164766564965248,
0.007887511514127254,
0.0008350171847268939,
-0.017290007323026657,
0.02684425376355648,
0.0021827942691743374,
-0.01034014392644167,
0.0016845106147229671,
0.00850075762718916,
0.006136463489383459,
-0.011942736804485321,
0.011660267598927021,
-0.019217483699321747,
0.017220746725797653,
0.012838589958846569,
0.005767268594354391,
0.00036328835994936526,
-0.006326344329863787,
-0.018631145358085632,
-0.02094995602965355,
0.012211127206683159,
0.025819504633545876,
0.01049082912504673,
0.00025143363745883107,
-0.00823915097862482,
0.00934404507279396,
0.0010407945374026895,
0.008519642055034637,
0.02151450142264366,
0.018504444509744644,
-0.0030676773749291897,
0.05844160169363022,
0.0013531704898923635,
0.020518802106380463,
0.017287395894527435,
0.0005133055965416133,
-0.012470039539039135,
0.02124164253473282,
0.00272346381098032,
-0.0016545846592634916,
0.023522164672613144,
0.0075057679787278175,
-0.012690523639321327,
0.008895245380699635,
0.002820811700075865,
0.002316024387255311,
-0.0020950480829924345,
2.3939308448461816e-05,
0.010338949970901012,
0.003580415854230523,
-0.01314419973641634,
-0.007272879593074322,
-0.015251991339027882,
0.008559169247746468,
-0.0034654918126761913,
0.001627915888093412,
-0.018863258883357048,
-0.023351963609457016,
-0.006876007653772831,
-0.006745068822056055,
0.012902967631816864,
-0.024199403822422028,
0.01315145380795002,
0.01704074628651142,
0.008813329041004181,
-0.02857677824795246,
0.0017795704770833254,
-0.0046593546867370605,
-0.020205382257699966,
-0.007364429999142885,
-0.022506574168801308,
-0.004266205243766308,
-0.014368502423167229,
0.006077993661165237,
-0.007778868544846773,
-0.0338706448674202,
-0.020801424980163574,
-0.0032948791049420834,
0.0038966627325862646,
0.0013354028342291713,
-0.004057361278682947,
-0.01116037555038929,
0.0004979542572982609,
-0.0014924905262887478,
0.02228676900267601,
0.00030853820499032736,
0.0032361503690481186,
-0.007311032619327307,
0.0005657610017806292,
0.01570758782327175,
0.0065332623198628426,
-0.004962607752531767,
-0.00043092138366773725,
0.004675432574003935,
-0.0050036306492984295,
-0.01355694979429245,
0.012455311603844166,
-0.010332843288779259,
-0.006332680117338896,
0.01629943959414959,
0.00022889582032803446,
0.019646810367703438,
-0.00645048450678587,
0.00018199885380454361,
0.021935712546110153,
-0.000669611559715122,
-0.024545805528759956,
-0.43374237418174744,
0.01338146347552538,
-0.00577061390504241,
0.010791081003844738,
-0.030768774449825287,
-0.000248340074904263,
0.028682900592684746,
0.016294529661536217,
0.02170475758612156,
0.004017048515379429,
-0.019540751352906227,
-0.006580394227057695,
-0.13620400428771973,
0.01912953518331051,
-0.022863149642944336,
-0.0014566757017746568,
-0.018966596573591232,
-0.06582166254520416,
-0.010411419905722141,
0.03066517785191536,
-0.005918117240071297,
0.025835353881120682,
0.01267832238227129,
0.009197103790938854,
0.018832538276910782,
0.005453452467918396,
0.005494879558682442,
-0.003756850492209196,
0.006762545555830002,
-0.0054822345264256,
0.0004532787424977869,
-0.005451512522995472,
0.026262624189257622,
0.006062537431716919,
5.2028499339940026e-05,
-0.0081722941249609,
-0.0064022960141301155,
-0.0028097990434616804,
0.008897855877876282,
-0.01511690765619278,
-0.009734614752233028,
-0.0009863842278718948,
0.017546869814395905,
0.0075432173907756805,
-0.043936505913734436,
-0.009013839066028595,
-0.032600127160549164,
-0.14329268038272858,
0.00488486560061574,
-0.013245992362499237,
0.012149952352046967,
0.007384683471173048,
-0.011745926924049854,
-0.016930073499679565,
-0.020095206797122955,
-0.0014918777160346508,
0.0059597003273665905,
0.0061284457333385944,
0.01760634034872055,
-0.019487448036670685,
-0.01537919882684946,
-0.01407971978187561,
0.030047781765460968,
0.005343243945389986,
-0.019699424505233765,
0.003926097881048918,
-0.028690986335277557,
-0.009443176910281181,
-0.021185321733355522,
-0.016413919627666473,
-0.003658981528133154,
-0.013958023861050606,
-0.00257857795804739,
0.004975579679012299,
0.021740838885307312,
0.02140122465789318,
0.012838726863265038,
-0.011973136104643345,
0.004580433014780283,
-0.002931915456429124,
-0.03209826350212097,
-0.016737569123506546,
0.023438503965735435,
0.013478938490152359,
0.01442253403365612,
-0.0067999050952494144,
0.003133262973278761,
0.0004907906986773014,
-0.017385315150022507,
-0.0002390776644460857,
-0.0013594918418675661,
0.010029762051999569,
-6.668922651442699e-06,
-0.01538124494254589,
-0.000784639734774828,
0.002918561454862356,
-0.018107565119862556,
-0.002243755152449012,
-0.02875298261642456,
-0.002286843489855528,
-0.007222936954349279,
0.017300134524703026,
0.006860439665615559,
-0.031133407726883888,
-0.005813203752040863,
-0.017268402501940727,
0.17043600976467133,
0.010559913702309132,
-0.0057410565204918385,
0.0013125024270266294,
-0.012719777412712574,
-0.0012119015445932746,
0.00634392537176609,
0.0026553927455097437,
0.11043155193328857,
0.0013203280977904797,
-0.019190805032849312,
0.00838405080139637,
-0.00188065052498132,
0.002253645798191428,
-0.000574819277971983,
0.03280145674943924,
-0.002098045777529478,
0.011521426029503345,
-0.0121723972260952,
0.009705677628517151,
0.015630444511771202,
-0.007735606282949448,
0.00569238280877471,
-0.0037131605204194784,
0.007841743528842926,
-5.696633525076322e-05,
-0.01864611543715,
-0.003599918447434902,
0.01736084744334221,
-0.023667721077799797,
0.005330719519406557,
-0.010251360014081001,
-0.01295823510736227,
0.06270076334476471,
-0.009333936497569084,
0.011737006716430187,
0.013586423359811306,
-0.0033054028172045946,
-0.0005970350466668606,
-0.029645636677742004,
-0.012136433273553848,
-0.0026931853499263525,
-0.03559974208474159,
0.032441310584545135,
-0.0003459737345110625,
0.00295159756205976,
-0.004855248611420393,
-0.009727121330797672,
0.0031688339076936245,
-0.007183929439634085,
-0.012171517126262188,
-0.027038224041461945,
-0.009694920852780342,
0.00845372211188078,
0.0038547960575670004,
-0.01620481163263321,
-0.0452495738863945,
-0.018863722681999207,
0.010479321703314781,
-0.013060204684734344,
0.004159659147262573,
-0.00302547006867826,
-0.0029191672801971436,
-0.0022642319090664387,
-0.007219057064503431,
0.0019106592517346144,
0.008937021717429161,
-0.025046739727258682,
-0.005377864930778742,
-0.015469738282263279,
0.003018368501216173,
0.010102585889399052,
-0.14894463121891022,
0.0014075853396207094,
0.00414086552336812,
-0.02763873152434826,
-0.013417866080999374,
-0.019957050681114197,
0.012801596894860268,
0.00011234940029680729,
0.008322950452566147,
0.012228051200509071,
-0.0014867965364828706,
0.12239447981119156,
-0.0001346774079138413,
-0.010775008238852024,
-0.016029132530093193,
-0.005007494240999222,
0.014944982714951038,
-5.520668128156103e-05,
0.002162717515602708,
-0.02308199182152748,
-0.011082983575761318,
0.1109391376376152,
0.0034826139453798532,
0.02676858939230442,
0.0037683569826185703,
-0.013597832061350346,
4.714470196631737e-05,
0.009496408514678478,
-0.0024041917640715837,
0.007655952125787735,
-0.012766871601343155,
0.0074783796444535255,
0.01734108291566372
],
"label": "HIGH",
"text": "You are a professional Python developer and data analyst.\n\nWrite code that:\n- reads all files with txt extension from the current working directory (these are books);\n- for each book, display a word cloud in a neat grid;\n- find the two most similar books as accurately as possible and display the result;\n- implement word preprocessing to solve these problems as correctly as possible.\n\nThe code should be as efficient and concise as possible. \n\nThen check your code for errors and correct them if necessary."
}
],
"LOW": [
{
"embedding": [
0.02648692950606346,
-0.0010638373205438256,
-0.00966667104512453,
-0.015978127717971802,
-0.016848718747496605,
-0.005478681065142155,
0.02602456323802471,
-0.004564971663057804,
0.0026320936158299446,
-0.06774858385324478,
-0.020062243565917015,
0.004483099561184645,
-0.005507764406502247,
-0.0027423356659710407,
-0.031711164861917496,
-0.0003225226828362793,
0.013415533117949963,
0.006500308867543936,
-0.009467401541769505,
-0.006793952081352472,
0.007607476785778999,
-0.01582661271095276,
0.03505789488554001,
-0.012171013280749321,
0.014605906791985035,
-0.0007661767886020243,
0.009142270311713219,
0.018322812393307686,
-0.007396745029836893,
0.030195806175470352,
-0.005181359592825174,
0.013311449438333511,
-0.003702969755977392,
0.008781330659985542,
-0.02069043554365635,
0.011103599332273006,
-0.004842399153858423,
-0.021637653931975365,
-0.013303224928677082,
-0.00849148165434599,
-0.032390862703323364,
0.008119107224047184,
0.03958234563469887,
-0.005362665746361017,
-0.007671533618122339,
-0.027245983481407166,
0.006924952380359173,
0.011453205719590187,
-0.008300160057842731,
0.01092689298093319,
-0.005355318542569876,
0.005111088976264,
-0.010500247590243816,
-0.004616944119334221,
0.013849443756043911,
0.012217780575156212,
-0.00950991827994585,
0.008110519498586655,
-0.0370415560901165,
0.020336663350462914,
0.0033985988702625036,
0.007351227104663849,
0.025580883026123047,
0.003419361775740981,
0.00042747255065478384,
0.005267771426588297,
0.015063083730638027,
0.009353572502732277,
-0.012787213549017906,
-0.010097956284880638,
-0.000312722782837227,
0.009685264900326729,
0.020078949630260468,
0.064177006483078,
0.011940333992242813,
-0.0186280719935894,
0.03200729191303253,
0.003279050113633275,
0.0003346922167111188,
-0.0008632199605926871,
0.0010783403413370252,
0.009041228331625462,
-0.01402457244694233,
-0.012163441628217697,
-0.0021612367127090693,
-0.008296950720250607,
0.005865972489118576,
-0.00555646326392889,
-0.010756080970168114,
0.013754721730947495,
0.010399982333183289,
-0.0074177877977490425,
-0.022160887718200684,
-0.006561923772096634,
0.0017301772022619843,
0.011290942318737507,
0.0009011207148432732,
0.007678607013076544,
0.40399327874183655,
-0.010526868514716625,
-0.018919562920928,
0.0058018965646624565,
0.004681854508817196,
-0.011881214566528797,
0.02340475656092167,
-0.022009531036019325,
-0.0052573662251234055,
-0.02983538992702961,
0.004864939488470554,
0.035979390144348145,
0.02242652326822281,
-0.003396253567188978,
0.009703291580080986,
-0.002057850593701005,
-0.013100175186991692,
-0.0255390927195549,
0.004965644329786301,
0.0037817133124917746,
0.009765512309968472,
-0.015155195258557796,
0.0020052092149853706,
-0.007180690765380859,
0.06315312534570694,
0.011677653528749943,
-0.0068587022833526134,
-0.003219736274331808,
-0.011157874949276447,
-0.013510637916624546,
0.01192237064242363,
-0.01439741998910904,
-0.037443432956933975,
-0.010088125243782997,
0.006163768470287323,
-0.0046418337151408195,
0.020428339019417763,
0.0019332411466166377,
8.292770507978275e-05,
-0.0036378256045281887,
-0.0646146759390831,
0.013183601200580597,
0.0125442398712039,
-0.007054343353956938,
0.009888279251754284,
-0.00996995996683836,
-0.029840731993317604,
0.1787915676832199,
-0.00484544038772583,
0.0038758658338338137,
-0.006425702944397926,
-0.0017774907173588872,
0.011145040392875671,
-0.01463156845420599,
-0.016178902238607407,
0.005684999283403158,
-0.013758555054664612,
-0.009350068867206573,
0.00522832153365016,
0.021493004634976387,
0.002959159668534994,
0.004240917973220348,
-0.06802946329116821,
-0.00282049342058599,
-0.011256573721766472,
0.017404576763510704,
0.01363187376409769,
-0.017677219584584236,
0.009715517051517963,
-0.04402657225728035,
0.011030914261937141,
0.028527360409498215,
-9.400691487826407e-05,
0.007471646647900343,
-0.1541728675365448,
0.02512730285525322,
0.0066401478834450245,
0.004227254539728165,
0.007586977444589138,
0.005316510330885649,
-0.005501927807927132,
-0.016430437564849854,
-0.01061745174229145,
0.02185169793665409,
0.007286281790584326,
0.013447676785290241,
-0.02421731874346733,
0.0015954483533278108,
0.01080283708870411,
-0.003274212358519435,
-0.0016661944100633264,
0.008023559115827084,
-0.0005942443385720253,
-0.028553146868944168,
-0.009313525632023811,
0.008133558556437492,
0.005800743121653795,
0.008715560659766197,
0.008559156209230423,
-0.01225875224918127,
-0.0031907418742775917,
0.014591004699468613,
-0.010461815632879734,
-0.00706614600494504,
-0.015668081119656563,
0.010430246591567993,
0.020546115934848785,
0.007455567829310894,
-0.002578375395387411,
0.015034027397632599,
0.012316563166677952,
-0.007656467147171497,
-0.010772868990898132,
0.005369006656110287,
0.0009824015432968736,
0.026535868644714355,
0.03146809712052345,
-0.019144870340824127,
-0.004156183917075396,
0.0034678340889513493,
0.011584277264773846,
0.008679580874741077,
-0.015499337576329708,
0.010517656803131104,
-0.017550017684698105,
-0.008670358918607235,
-0.004048115573823452,
-0.008749379776418209,
0.01078763511031866,
0.009637376293540001,
-0.005857239942997694,
-0.026764115318655968,
0.017847776412963867,
0.005177693907171488,
0.0018616040470078588,
-0.015332224778831005,
-0.0010512851877138019,
0.0010236718226224184,
-0.005028387065976858,
0.010649989359080791,
-0.002629463793709874,
0.009117787703871727,
0.003507171291857958,
-0.010476665571331978,
0.029563773423433304,
0.002962385304272175,
-0.001335594104602933,
0.002338978461921215,
0.018160106614232063,
0.01658673956990242,
-0.000563681882340461,
0.004422742873430252,
0.04626549407839775,
0.007048256695270538,
-0.021013379096984863,
-0.016322413459420204,
-0.0283083226531744,
-0.003921112045645714,
-0.004189644940197468,
-0.08835331350564957,
-0.018877532333135605,
-0.018564460799098015,
0.013213000260293484,
-0.18696953356266022,
0.0008008169825188816,
0.012718426063656807,
-0.004875142127275467,
0.0019255882361903787,
0.02116173505783081,
0.004054129123687744,
-0.02749122865498066,
0.010074569843709469,
-0.027576779946684837,
-0.002556807594373822,
-0.047729454934597015,
0.016888609156012535,
-0.009909231215715408,
0.00685331504791975,
-0.008361516520380974,
0.0020681298337876797,
-0.006544170435518026,
-0.02349439635872841,
-0.008458804339170456,
0.011924855411052704,
-0.015924423933029175,
0.021595489233732224,
-0.01856638491153717,
0.023423250764608383,
0.01710100844502449,
0.012223309837281704,
0.0038690725341439247,
0.25153857469558716,
0.01425024401396513,
-0.01560975331813097,
0.013949727639555931,
-0.017905505374073982,
0.006097552366554737,
-0.003693145699799061,
-0.038226306438446045,
-0.005997160449624062,
0.005752570927143097,
0.012112759985029697,
-0.014703492633998394,
0.004608269780874252,
-0.03448338061571121,
1.56095720740268e-05,
-0.02012091875076294,
-0.0013729388592764735,
0.006293566897511482,
0.014014686457812786,
-0.03224799782037735,
-0.003865425009280443,
0.008275904692709446,
0.001942778704687953,
-0.0014719004975631833,
-0.001025260309688747,
-0.006602119188755751,
-0.01967724971473217,
-0.019924312829971313,
0.030537763610482216,
-0.0035920641385018826,
-0.056094586849212646,
0.015614320524036884,
0.0019490866689011455,
-0.02680610492825508,
-0.0010966366389766335,
0.0007973007741384208,
-0.00430771429091692,
-0.00956656038761139,
-0.01659512333571911,
-0.013637138530611992,
0.00025362512678839266,
0.0011014805641025305,
-0.0021656269673258066,
-0.02856859192252159,
-0.023499760776758194,
-0.007165139075368643,
-0.0074304998852312565,
-0.010347429662942886,
0.01806681416928768,
-0.005998949985951185,
0.012282196432352066,
-0.017697649076581,
0.0012964933412149549,
-0.00517914118245244,
0.004822453949600458,
0.014662757515907288,
0.0011572387302294374,
0.02139858528971672,
-0.007835756056010723,
-0.000455637724371627,
0.007866374216973782,
0.001975576626136899,
0.006471599917858839,
-0.010390657931566238,
0.012477424927055836,
-0.0010353118414059281,
0.000240853798459284,
-0.006748814135789871,
-0.02087724395096302,
0.00602846359834075,
0.0032565081492066383,
0.005786011461168528,
-0.12319587171077728,
0.009255556389689445,
0.008356289938092232,
-0.01456880010664463,
0.0001981560344574973,
-0.005605911370366812,
0.000757264147978276,
-0.004141754005104303,
0.03266522288322449,
0.019943533465266228,
-0.004711426328867674,
0.02423413097858429,
-0.0011441257083788514,
-0.02481885440647602,
0.010123777203261852,
-0.001678692759014666,
0.03914084658026695,
0.012971777468919754,
-0.036012545228004456,
-0.02915124222636223,
-0.00030037848046049476,
0.020644625648856163,
-0.010027576237916946,
-0.0003234374162275344,
0.009453446604311466,
0.0006899556028656662,
-0.019941236823797226,
-0.00035817723255604506,
-0.001357944100163877,
0.020459027960896492,
-0.0009636615286581218,
-0.0009063866455107927,
-0.009894521906971931,
-0.00711774779483676,
-0.000709362153429538,
-0.009009911678731441,
0.009437737986445427,
0.015508429147303104,
-0.02281365916132927,
-0.006385305896401405,
-0.00255284970626235,
-0.00730440579354763,
0.009564134292304516,
-0.020660031586885452,
-0.010118819773197174,
0.0002733968722168356,
-0.008921656757593155,
-0.0930313989520073,
-0.0041264682076871395,
-0.006358380429446697,
-0.015760798007249832,
-0.01011276338249445,
0.02019052952528,
0.005443222355097532,
0.00172749615740031,
-0.0003481145540717989,
0.0024300862569361925,
0.02077866718173027,
0.01975454017519951,
0.0201877411454916,
-0.006361454725265503,
-0.010440407320857048,
-0.021219924092292786,
-0.006338976323604584,
0.011133282445371151,
0.00391391571611166,
-0.01235242560505867,
0.0005850508459843695,
0.01282112393528223,
-0.039286866784095764,
-0.009895979426801205,
-0.0002251197147415951,
-0.025495871901512146,
-0.019579702988266945,
-0.011444016359746456,
0.0070399451069533825,
-0.008998887613415718,
0.0012809641193598509,
0.3310178220272064,
-0.011415569111704826,
0.007398885674774647,
0.0012009298661723733,
-0.02013387158513069,
-0.0035620923154056072,
0.013220477849245071,
0.0030922323931008577,
0.04894772171974182,
0.00489255553111434,
-0.011334857903420925,
-0.017854489386081696,
0.000995898386463523,
0.01119412761181593,
-0.03001922182738781,
0.0303393192589283,
-0.0001482521474827081,
-0.012248950079083443,
-0.0031790195498615503,
-0.01940462738275528,
0.003734447294846177,
-0.001311023603193462,
0.009394815191626549,
-0.01314456108957529,
0.01199437864124775,
0.01419768575578928,
0.006155736278742552,
-0.010529907420277596,
-0.005271160509437323,
-0.014967740513384342,
-0.021313196048140526,
0.006682718172669411,
0.012089090421795845,
0.01800752989947796,
0.004276799038052559,
-0.0036748142447322607,
-0.0004618914390448481,
0.006801265757530928,
0.013047710992395878,
0.0074809398502111435,
0.022890977561473846,
0.017181959003210068,
0.06935574859380722,
0.009835758246481419,
0.02105250023305416,
0.01530985813587904,
0.0003277950163464993,
-0.011917180381715298,
0.022824319079518318,
0.013644360937178135,
-0.01079779677093029,
0.011278265155851841,
0.01432811189442873,
-0.007908171974122524,
0.006777359172701836,
0.0065452540293335915,
0.0076530068181455135,
-0.015562284737825394,
-0.018619494512677193,
-0.00347917596809566,
-0.004143567755818367,
0.003263407154008746,
-0.006329386495053768,
-0.0037599559873342514,
0.010309210047125816,
-0.016583751887083054,
0.013898761011660099,
-0.00991764385253191,
-0.01490193884819746,
-0.009386496618390083,
-0.0077040065079927444,
0.0018473997479304671,
-0.038159411400556564,
0.011240815743803978,
0.019094038754701614,
0.0018548418302088976,
-0.020892808213829994,
0.0006988616078160703,
-0.0010410300455987453,
-0.011714618653059006,
-0.014082055538892746,
-0.009759954176843166,
-0.0025671934708952904,
-0.013441110961139202,
-0.002114095725119114,
-0.0010249183978885412,
-0.02532045915722847,
-0.02833198942244053,
-0.0015964796766638756,
0.02106938324868679,
0.0004778731381520629,
-0.013818908482789993,
-0.007195652462542057,
-0.003875055117532611,
-0.003256350290030241,
0.01563858799636364,
-0.0077557493932545185,
-0.009104190394282341,
-0.005537999793887138,
-0.001257602940313518,
0.01677558943629265,
0.009844125248491764,
0.014884077943861485,
0.013844498433172703,
0.0020229811780154705,
-0.017616398632526398,
-0.011545808985829353,
0.008806911297142506,
-0.007389587815850973,
0.005872606299817562,
0.01231707539409399,
0.008231764659285545,
0.01578897424042225,
-0.014784056693315506,
-0.006139501929283142,
0.003178101498633623,
-0.004252019338309765,
-0.02069447748363018,
-0.4837748110294342,
0.019359592348337173,
-0.00013085079262964427,
0.013903157785534859,
-0.015258572064340115,
-0.014417012222111225,
0.02525290474295616,
0.005657861940562725,
0.019996512681245804,
0.006101900711655617,
-0.018810568377375603,
-0.017835218459367752,
-0.1294863373041153,
0.017561085522174835,
-0.004019861109554768,
-0.0010649441974237561,
-0.005831817165017128,
-0.04814719408750534,
-0.0017663772450760007,
0.027296587824821472,
-0.012025395408272743,
0.01597209833562374,
0.01650199107825756,
0.019480859860777855,
0.013740027323365211,
0.0069020832888782024,
-0.000420022668549791,
0.0019044516375288367,
0.007281788159161806,
-0.005062589887529612,
0.004685157909989357,
0.0007004926446825266,
0.03190071880817413,
-0.004190766718238592,
-0.0010785863269120455,
-0.022166011855006218,
0.003819011151790619,
-0.0087962057441473,
0.005445427261292934,
-0.023817384615540504,
-0.0024219071492552757,
0.002807517070323229,
0.008803675882518291,
0.01592147722840309,
-0.028404762968420982,
-0.0161146093159914,
-0.03133992850780487,
-0.1438850313425064,
0.008015214465558529,
-0.0034654936753213406,
0.021860826760530472,
0.0022170173469930887,
-0.0016491302521899343,
0.0021406325977295637,
-0.016407528892159462,
0.007911205291748047,
-0.00454374123364687,
-0.0007895366870798171,
0.010977448895573616,
-0.015750406309962273,
-0.013051670044660568,
-0.008517156355082989,
0.03055124171078205,
0.0014462892431765795,
-0.013292266987264156,
0.011511055752635002,
-0.03168928250670433,
-0.0037915429566055536,
-0.010839488357305527,
-0.020352251827716827,
-0.010228216648101807,
-0.012760848738253117,
-0.01500114519149065,
0.013992059975862503,
0.01643480733036995,
0.017708376049995422,
-0.005454416386783123,
0.005314801819622517,
-0.012220044620335102,
-0.006354143377393484,
-0.02290654368698597,
-0.01072593405842781,
0.035393670201301575,
0.02039686031639576,
0.006478374358266592,
-0.007442444562911987,
-0.006480060517787933,
0.017065050080418587,
0.004307271912693977,
-0.005730858072638512,
-0.004871695768088102,
0.007507386617362499,
0.012502789497375488,
-0.005943354219198227,
-0.014626498334109783,
0.011981870979070663,
-0.008450535126030445,
0.015424052253365517,
-0.027048394083976746,
-0.00024109345395117998,
0.0013592022005468607,
-0.00521558802574873,
0.006269016768783331,
-0.023016078397631645,
-0.00137544353492558,
0.005530813243240118,
0.166301429271698,
0.004818623885512352,
-0.010003489442169666,
-0.012629002332687378,
0.006917253136634827,
0.016056565567851067,
-0.004595241043716669,
0.012932314537465572,
0.10053791850805283,
0.00253744306974113,
-0.0032212468795478344,
0.006310283672064543,
-0.005923011805862188,
0.0012428699992597103,
-0.008916383609175682,
0.02168346755206585,
-0.005890219938009977,
0.015413717366755009,
-0.00747372442856431,
0.004012625198811293,
0.013833754695951939,
-0.018237894400954247,
0.024452295154333115,
-0.00348577369004488,
0.0013432629639282823,
0.002518411260098219,
-0.009025482460856438,
-0.018824947997927666,
0.011762677691876888,
-0.024716807529330254,
0.006669866386801004,
0.01693210005760193,
-0.008452216163277626,
0.06391468644142151,
-0.010969407856464386,
0.007021497935056686,
0.02875210903584957,
-0.00854189321398735,
-0.004279664717614651,
-0.023278208449482918,
-0.008208910934627056,
-0.0058607785031199455,
-0.03460341691970825,
0.032275598496198654,
-0.00768157048150897,
-0.009864416904747486,
-0.002991802291944623,
-0.022353217005729675,
0.0008815918117761612,
-0.004788372665643692,
-0.0020683074835687876,
-0.012020853348076344,
-0.012337028980255127,
0.01541225891560316,
-0.0021212701685726643,
0.004762399476021528,
-0.047722455114126205,
-0.003967319615185261,
0.010626045055687428,
-0.0024648949038237333,
0.009607088752090931,
0.006510217674076557,
-0.006576524116098881,
0.002875301521271467,
0.003233133116737008,
-0.0026623508892953396,
0.012839315459132195,
-0.007313758600503206,
-0.011316402815282345,
-0.014108750969171524,
-0.003146000672131777,
0.01485332753509283,
-0.1441049724817276,
-0.007699332665652037,
0.002234335755929351,
-0.03039935603737831,
-0.018039317801594734,
-0.009275116957724094,
0.025842666625976562,
0.008286857977509499,
0.002292077522724867,
0.016028819605708122,
-0.005565776955336332,
0.11462263017892838,
-0.010934887453913689,
-0.007003468461334705,
-0.00682443892583251,
-0.004457773175090551,
0.009448588825762272,
0.015671467408537865,
-0.0034878673031926155,
-0.02822897955775261,
-0.0072744484059512615,
0.1062626987695694,
0.005662010051310062,
0.018248416483402252,
0.01897069811820984,
-0.015205473639070988,
-0.003496551187708974,
0.012231655418872833,
0.010195254348218441,
0.000998149742372334,
-0.008571318350732327,
0.012968906201422215,
0.0065460409969091415
],
"label": "LOW",
"text": "What are some of things to do while visiting Russia"
},
{
"embedding": [
0.041831932961940765,
0.008752463385462761,
0.00497175520285964,
-0.015397604554891586,
-0.025626156479120255,
-0.007073021959513426,
0.004347975365817547,
-0.006157573778182268,
0.0024053105153143406,
-0.08473299443721771,
-0.021923182532191277,
0.015420331619679928,
0.00011088590690633282,
-0.005486877169460058,
-0.036344341933727264,
0.010353075340390205,
0.017087232321500778,
0.014490442350506783,
-0.011488673277199268,
-0.02359095588326454,
0.011317466385662556,
-0.006451296620070934,
0.04914584383368492,
-0.01272901427000761,
0.014770965091884136,
-0.004977813456207514,
0.019719399511814117,
0.004007676616311073,
-0.011118785478174686,
0.021227210760116577,
0.010757104493677616,
0.010657308623194695,
0.0160016231238842,
0.0008743451908230782,
-0.02212778851389885,
0.005995017942041159,
-0.0075341095216572285,
-0.009616411291062832,
-0.010223700664937496,
-0.011341311037540436,
-0.038221582770347595,
0.006499378010630608,
0.0495503768324852,
-0.014469250105321407,
0.0038592005148530006,
-0.023308737203478813,
-0.0018352156039327383,
0.00855918787419796,
0.004099074751138687,
0.015004444867372513,
-0.002408037194982171,
-0.009114026091992855,
-0.003405480645596981,
0.004218422342091799,
0.0017273675184696913,
0.002290683798491955,
-0.012634547427296638,
0.006550460122525692,
-0.019593363627791405,
0.01139887422323227,
-0.003596343332901597,
-0.004494686145335436,
0.030401738360524178,
-0.003477397607639432,
-0.014634584076702595,
-0.0035479748621582985,
0.007376015651971102,
0.007587176747620106,
-0.020112546160817146,
-0.004040680825710297,
-0.0028246529400348663,
0.0021481127478182316,
0.019890381023287773,
0.061672139912843704,
0.027077289298176765,
-0.010985326953232288,
0.0326397605240345,
-0.0018533158581703901,
0.006439903751015663,
-0.0019352285889908671,
0.025268584489822388,
0.016599141061306,
-0.017273303121328354,
-0.010875550098717213,
-0.01331600546836853,
-0.0070069595240056515,
0.017504725605249405,
-0.01160179078578949,
0.0034942941274493933,
0.029334137216210365,
0.009591973386704922,
-0.014087007381021976,
0.0024428623728454113,
-0.011702325195074081,
-0.00133498664945364,
0.009772151708602905,
-0.006010017357766628,
0.002496827393770218,
0.40790432691574097,
-0.009153859689831734,
-0.004650587681680918,
0.01519718486815691,
0.0067838262766599655,
-0.008757361210882664,
0.027102097868919373,
-0.02487340196967125,
0.0009874413954094052,
-0.015427353791892529,
0.009468418546020985,
0.024809347465634346,
0.03522081300616264,
-0.01234756875783205,
0.007704578340053558,
-0.014410869218409061,
0.0033635280560702085,
-0.013631430454552174,
0.011109557934105396,
0.01166551187634468,
0.010982409119606018,
-0.005889013409614563,
0.006137240212410688,
0.004187863320112228,
0.055280901491642,
0.0026864672545343637,
0.0015079197473824024,
-0.020407335832715034,
0.001652647857554257,
-0.008198194205760956,
0.021441100165247917,
-0.005695774685591459,
-0.040886279195547104,
-0.005609477404505014,
-0.01649896427989006,
-0.008563010022044182,
0.009369845502078533,
0.01110029499977827,
-0.015989845618605614,
-0.002088087610900402,
-0.046714507043361664,
0.024554891511797905,
0.010336753912270069,
-0.03207063674926758,
-0.004464718978852034,
-0.029698243364691734,
-0.014550234191119671,
0.18526388704776764,
-0.010259960778057575,
-0.009675118140876293,
-0.007385817356407642,
0.0036276672035455704,
0.0008782718796283007,
-0.03129341080784798,
-0.01407720148563385,
0.016715385019779205,
-0.01305553037673235,
-0.015778901055455208,
0.016593797132372856,
-0.0054610916413366795,
-0.0071868496015667915,
-0.0010616861982271075,
-0.050719305872917175,
0.009559599682688713,
-0.004062649793922901,
0.02828891947865486,
-0.004930687602609396,
-0.003981216344982386,
0.0008106293971650302,
-0.041326552629470825,
-0.003145799273625016,
0.027285130694508553,
0.01202449668198824,
-0.009628438390791416,
-0.14601661264896393,
0.011500069871544838,
0.023291945457458496,
0.004827221855521202,
0.001869936240836978,
-0.012762892991304398,
-0.011759904213249683,
-0.007269740104675293,
-0.019045429304242134,
0.002644997788593173,
0.009332867339253426,
-0.0017900575185194612,
-0.022875018417835236,
-0.0008226691279560328,
0.0099067697301507,
-0.015022209845483303,
0.00798722356557846,
0.013082695193588734,
0.0018975446000695229,
-0.010728222317993641,
0.003791538765653968,
0.005203631240874529,
-0.0027515485417097807,
-0.0025611002929508686,
0.015342905186116695,
-0.01455965731292963,
0.0006621197680942714,
-0.00378085533156991,
-0.0038295118138194084,
0.000611315481364727,
-0.0009179473854601383,
0.01017073169350624,
0.014656643383204937,
0.0009311169851571321,
-0.005791370291262865,
0.007283123210072517,
0.017539558932185173,
-0.00016981888620648533,
-0.007388822268694639,
-0.009541916660964489,
0.002708796877413988,
0.025873983278870583,
0.02988281287252903,
-0.014090750366449356,
-0.003982766065746546,
0.012788722291588783,
0.0032858955673873425,
-0.013846623711287975,
-0.012934839352965355,
0.005589806474745274,
-0.0061235190369188786,
0.003938968759030104,
-0.005390996113419533,
0.009493268094956875,
0.018297500908374786,
-0.004126761574298143,
0.005722854286432266,
-0.01860734447836876,
0.016833148896694183,
0.004293753299862146,
0.011829741299152374,
-0.012279857881367207,
-0.007383431773632765,
-0.01603633351624012,
0.004705906379967928,
0.012412979267537594,
0.000672517460770905,
0.010024464689195156,
0.000495492946356535,
-0.0009564234642311931,
0.027363942936062813,
-0.0077703180722892284,
-0.0009229149436578155,
0.02458411455154419,
0.017622176557779312,
0.00974806398153305,
-0.01183454692363739,
-0.0074685318395495415,
0.05521372705698013,
0.01487326342612505,
-0.01096869446337223,
-0.01689911261200905,
-0.028432322666049004,
0.0022006535436958075,
0.0011869240552186966,
-0.08964405953884125,
-0.03212996572256088,
0.0026776136364787817,
0.027444597333669662,
-0.17663456499576569,
0.012924623675644398,
0.004691016860306263,
0.00957962591201067,
-0.013783869333565235,
0.02199679985642433,
0.0009203518857248127,
-0.020741622895002365,
0.000538688967935741,
-0.03214182332158089,
-0.0008817488560453057,
-0.03875984624028206,
-0.002216060645878315,
0.006093595642596483,
0.013484692201018333,
-0.004443701356649399,
0.011236595921218395,
-0.009196891449391842,
0.0022108813282102346,
-0.01574133336544037,
-0.00834518950432539,
-0.016331931576132774,
0.020654747262597084,
-0.013937457464635372,
0.030374256893992424,
0.010991145856678486,
0.0074775065295398235,
-0.00566432811319828,
0.24082253873348236,
0.008094752207398415,
-0.004651985596865416,
0.021692493930459023,
-0.014061531983315945,
-0.0022914442233741283,
-0.005358561407774687,
-0.03467877581715584,
0.01454460434615612,
0.0017473248299211264,
0.0069611938670277596,
-0.011649183928966522,
0.0046846261247992516,
-0.029639504849910736,
-0.003791903844103217,
-0.03596102073788643,
0.01315162144601345,
-0.003973800223320723,
0.004400692414492369,
-0.05290435627102852,
0.0003746203437913209,
0.024323804304003716,
0.00846909824758768,
0.008751844055950642,
0.009292441420257092,
-0.01132118422538042,
-0.03508687764406204,
-0.014409930445253849,
0.026427146047353745,
0.005633772350847721,
-0.06530971080064774,
0.01004791259765625,
-0.004484553821384907,
-0.010659027844667435,
-0.0013444715877994895,
0.007296874653548002,
0.004025292117148638,
-0.008517608046531677,
-0.0020490093156695366,
-0.0251024030148983,
-0.009280028752982616,
-0.0016570151783525944,
0.014116969890892506,
-0.023325636982917786,
0.0013863679487258196,
0.004450610373169184,
0.0008926586015149951,
-0.0022915201261639595,
0.007277228869497776,
0.001856876420788467,
0.007581853307783604,
-0.016863089054822922,
-0.006623873952776194,
-0.01631590723991394,
0.021280629560351372,
0.020097123458981514,
0.005170756950974464,
0.006496138870716095,
-0.008775357156991959,
0.01786462962627411,
0.0036659017205238342,
-0.010608091950416565,
0.009018303826451302,
-0.014078610576689243,
0.023679358884692192,
0.013200530782341957,
-0.0129867447540164,
-0.009026379324495792,
-0.020958803594112396,
0.012100904248654842,
0.008387993089854717,
0.007481146603822708,
-0.1450425237417221,
0.007175989914685488,
0.014748699963092804,
-0.0066052572801709175,
-0.00036594850826077163,
-0.015796616673469543,
-0.005410501733422279,
0.0028744463343173265,
0.03552425280213356,
0.011117750778794289,
0.016016822308301926,
0.010646170005202293,
0.00536377215757966,
-0.031256016343832016,
0.0008073857752606273,
0.0005914220819249749,
0.041183460503816605,
0.015415050089359283,
-0.020547540858387947,
-0.014784421771764755,
0.010886411182582378,
0.017500465735793114,
-0.008410667069256306,
-0.001980246277526021,
0.0030854218639433384,
0.00023909694573376328,
-0.022001300007104874,
0.0057127820327878,
0.0013390958774834871,
0.013472089543938637,
0.001962750218808651,
-0.008349161595106125,
-0.006591841112822294,
-0.005418413784354925,
-0.001368376542814076,
-0.018442178145051003,
0.01563086360692978,
0.01600293256342411,
-0.020474854856729507,
-0.011801091954112053,
0.006781826261430979,
0.0024360709358006716,
-0.011989431455731392,
-0.0037388738710433245,
-0.0006681907689198852,
0.015278835780918598,
-0.014597993344068527,
-0.08569261431694031,
0.0009941152529790998,
0.0008314694277942181,
-0.01018023956567049,
-0.010649661533534527,
0.009176494553685188,
0.00984614621847868,
-0.0019047162495553493,
0.01723186857998371,
-0.0037312600761651993,
0.015517642721533775,
0.004870370030403137,
0.021012049168348312,
0.0015423041768372059,
0.008541802875697613,
-0.02959742210805416,
-0.006479634903371334,
0.013887990266084671,
-0.007230103015899658,
-0.011924506165087223,
-0.002868722891435027,
-0.006119822151958942,
-0.04538368433713913,
-0.011661668308079243,
-0.005395449697971344,
-0.014685305766761303,
-0.014974404126405716,
-0.019525956362485886,
-0.0013091877335682511,
-0.02233673445880413,
0.0009701682138256729,
0.3470591902732849,
-0.021015707403421402,
0.020610462874174118,
-0.0036806054413318634,
-0.002802968956530094,
0.0016863752389326692,
0.012553482316434383,
-0.0010926754912361503,
0.05895156040787697,
0.001184574794024229,
-0.025764893740415573,
-0.017173293977975845,
0.01081751100718975,
0.006860274355858564,
-0.02475818060338497,
0.03205862641334534,
-0.003204336389899254,
-0.0030606945510953665,
0.0063162390142679214,
0.0035024089738726616,
0.006119699217379093,
-0.012423384003341198,
0.003302024444565177,
-0.004841668996959925,
0.012532337568700314,
0.011055494658648968,
0.01066046766936779,
-0.005659916438162327,
-0.01172578427940607,
-0.026345469057559967,
-0.011867989785969257,
0.018469838425517082,
0.011720703914761543,
0.008602350018918514,
-0.004555036313831806,
-0.010475420393049717,
0.00943355355411768,
-0.004599146079272032,
0.019278477877378464,
0.015533198602497578,
0.012065442278981209,
-0.007645179983228445,
0.06765244901180267,
-0.004589494317770004,
0.021749697625637054,
0.021197572350502014,
0.001155208796262741,
-0.010885576717555523,
0.015574351884424686,
0.00883147306740284,
-0.00642798375338316,
0.01723525859415531,
0.016700660809874535,
-0.020217832177877426,
0.00539974682033062,
0.00864606723189354,
0.007782820612192154,
0.007035105489194393,
0.004956221207976341,
0.014807026833295822,
-0.01719675585627556,
-0.018845483660697937,
-0.005459876731038094,
-0.01767677627503872,
-0.00028812131495215,
-0.002517515094950795,
-0.008588043041527271,
-0.016521474346518517,
-0.02516750432550907,
-0.009507311508059502,
-0.012431589886546135,
0.011903094127774239,
-0.018823301419615746,
0.015507553704082966,
0.016177549958229065,
0.0022762755397707224,
-0.021865570917725563,
-0.004402440041303635,
0.005876854062080383,
-0.02074974961578846,
-0.008962942287325859,
-0.02427058108150959,
-0.004405503626912832,
-0.013597031123936176,
0.011869181878864765,
-0.0073087443597614765,
-0.03178182989358902,
-0.02767902985215187,
-0.006301775109022856,
0.0028793467208743095,
-0.008242000825703144,
-0.002588054398074746,
-0.003782512852922082,
0.0053457398898899555,
0.0005135780083946884,
0.0068942406214773655,
-0.007170319557189941,
0.0014062715927138925,
-0.017116306349635124,
0.005975587293505669,
0.018452031537890434,
0.0047086006961762905,
-0.0027109007351100445,
0.0001970007870113477,
-0.003270745277404785,
0.003936877008527517,
-0.001642537652514875,
0.016228169202804565,
-0.006822286639362574,
-0.005525053944438696,
0.004244770854711533,
0.0051687718369066715,
0.022937746718525887,
-0.017020901665091515,
0.009015888907015324,
0.014889610931277275,
0.0041967430151999,
-0.0269971564412117,
-0.4487907588481903,
0.008868714794516563,
-0.0018754246411845088,
0.021382194012403488,
-0.02894297055900097,
-0.007982800714671612,
0.026376299560070038,
0.016290420666337013,
0.02165103703737259,
0.0003732370969373733,
-0.02591550722718239,
-0.0088060786947608,
-0.15011362731456757,
0.014201384969055653,
-0.012115039862692356,
0.003693311708047986,
-0.013639419339597225,
-0.05400371551513672,
-0.0039919656701385975,
0.02904174104332924,
-0.01063100527971983,
0.019504869356751442,
0.009663568809628487,
0.0021942032035440207,
0.011768230237066746,
-0.0047126947902143,
0.00788336805999279,
-0.0006523276097141206,
0.011422688141465187,
0.0027866815216839314,
-0.0009590091649442911,
-0.010115751065313816,
0.026838205754756927,
0.001656539854593575,
-0.004286169074475765,
-0.010218190029263496,
-0.0006707186694256961,
-0.001397784217260778,
0.0060875993221998215,
-0.011191582307219505,
-0.0050459555350244045,
0.00029439874924719334,
0.02588331326842308,
0.0122159318998456,
-0.039824556559324265,
-0.01087800320237875,
-0.020338183268904686,
-0.14322388172149658,
0.0034227040596306324,
-0.008546470664441586,
0.015055439434945583,
0.022094719111919403,
-0.011060971766710281,
-0.015038351528346539,
-0.02372513897716999,
0.011701934039592743,
0.011996056884527206,
0.01146415900439024,
0.024753248319029808,
-0.010773786343634129,
-0.015905367210507393,
-0.0049398234114050865,
0.03462233394384384,
0.0010236988309770823,
-0.009678472764790058,
-0.004160696640610695,
-0.029239293187856674,
-0.013043327257037163,
-0.026966776698827744,
-0.01229901798069477,
0.0012219037162140012,
-0.009472083300352097,
-0.004076968878507614,
0.001703733578324318,
0.022866860032081604,
0.02009263075888157,
0.014869887381792068,
-0.010359521023929119,
0.0015878751873970032,
0.012822656892240047,
-0.030341442674398422,
-0.022956615313887596,
0.021747412160038948,
0.009771385230123997,
0.008157736621797085,
-0.012216889299452305,
0.009098622016608715,
-0.0011643529869616032,
-0.02048894762992859,
-0.0014345002127811313,
-0.0019867962691932917,
0.0003558791649993509,
-0.007624598685652018,
-0.016853878274559975,
-0.006307430099695921,
0.004167083650827408,
-0.018696248531341553,
-0.00688399001955986,
-0.04042057693004608,
-0.0015557591104879975,
-0.004875261336565018,
0.007659055292606354,
0.010732654482126236,
-0.01830480620265007,
-0.012836085632443428,
-0.018887272104620934,
0.15725313127040863,
0.0044058323837816715,
-0.009159470908343792,
-0.005648813676089048,
-0.005560451187193394,
0.004950918257236481,
0.004405380226671696,
0.004999800119549036,
0.11570945382118225,
0.004996058531105518,
-0.018329361453652382,
0.001403279253281653,
-0.0009642693912610412,
0.0013217688538134098,
0.00883619673550129,
0.036079443991184235,
-0.004837947431951761,
0.015378260985016823,
0.002066124929115176,
0.005385559052228928,
0.014441515319049358,
-0.013538154773414135,
0.004567813593894243,
0.0016872796695679426,
0.005804570857435465,
-0.016148999333381653,
-0.017125580459833145,
-0.010548830032348633,
0.019223026931285858,
-0.021120566874742508,
0.005596144590526819,
-0.011901505291461945,
-0.008423513732850552,
0.06608253717422485,
-0.02264833077788353,
0.01192550826817751,
0.024008337408304214,
-0.0021613568533211946,
0.00539908092468977,
-0.03127346560359001,
-0.01287254597991705,
0.008230963721871376,
-0.026872020214796066,
0.030677374452352524,
0.006380883511155844,
0.003522346494719386,
-0.018458466976881027,
-0.002527804346755147,
-0.00431598536670208,
-0.005580021999776363,
-0.00845372024923563,
-0.029253508895635605,
-0.023159204050898552,
0.009075073525309563,
0.00025601108791306615,
-0.010174913331866264,
-0.043255798518657684,
-0.018723906949162483,
0.012625210918486118,
-0.007717047352343798,
0.004253001883625984,
0.00332260993309319,
-0.0002528601617086679,
-0.002562575042247772,
-0.01282813586294651,
-0.0004008401883766055,
0.008601696230471134,
-0.026378707960247993,
-0.007129421923309565,
-0.006092279218137264,
-0.0036277209874242544,
0.00567084364593029,
-0.1486862301826477,
0.002844402799382806,
0.004794106353074312,
-0.02784162014722824,
-0.006679324898868799,
-0.022259244695305824,
0.013131462037563324,
-0.0031215075869113207,
0.0046866098418831825,
0.012145533226430416,
0.000257849576883018,
0.12674668431282043,
-0.007396603934466839,
-0.013625177554786205,
-0.016799552366137505,
-0.003143979236483574,
0.017135733738541603,
0.0023115992080420256,
-0.007928424514830112,
-0.025284305214881897,
-0.008459693752229214,
0.10398071259260178,
0.00800530519336462,
0.026909545063972473,
0.01022370345890522,
-0.011920646764338017,
0.0008921390981413424,
0.00866506528109312,
0.0005301462369970977,
-0.00044596128282137215,
-0.00584063958376646,
0.005607076920568943,
0.012409751303493977
],
"label": "LOW",
"text": "in ef core 5, how can i configure it so that an owned type is serialized as json?"
},
{
"embedding": [
0.02039445750415325,
0.009329110383987427,
-0.0063858344219625,
-0.0022812490351498127,
-0.02323310077190399,
-0.013027237728238106,
0.01961006224155426,
-0.013638310134410858,
0.005428168922662735,
-0.07121948897838593,
-0.014629247598350048,
-0.0024634592700749636,
-0.002002640860155225,
-0.008783119730651379,
-0.028760455548763275,
6.424890307243913e-05,
0.012376553378999233,
0.0038553052581846714,
-0.002131714718416333,
-0.016042346134781837,
0.004439534619450569,
-0.005865334998816252,
0.031842831522226334,
-0.014386935159564018,
0.015017320401966572,
0.0002791396400425583,
0.013109290972352028,
0.010686184279620647,
-0.012168671004474163,
0.019312020391225815,
0.0009414437226951122,
0.008297912776470184,
-0.000900810060556978,
0.00730891153216362,
-0.007535258773714304,
0.00919526070356369,
-0.006669522728770971,
-0.019071796908974648,
-0.010579504072666168,
-0.016308315098285675,
-0.04010802507400513,
0.00792109314352274,
0.04441574215888977,
-0.010729307308793068,
0.002213916275650263,
-0.025585148483514786,
0.007240836974233389,
-0.004635443910956383,
-0.005535494070500135,
0.006190856918692589,
0.0025153581518679857,
0.00625216169282794,
-0.00983637198805809,
-0.0028825534973293543,
0.01950671896338463,
0.009769483469426632,
-0.005437754560261965,
0.006399035453796387,
-0.03175976872444153,
0.021063653752207756,
0.0013231730554252863,
-0.0019202150870114565,
0.017947625368833542,
-0.00458945520222187,
-0.0017249748343601823,
0.008747135289013386,
0.0008959486149251461,
0.00858580507338047,
-0.013003678992390633,
-0.014394905418157578,
0.004457827191799879,
0.01405587699264288,
0.004601889289915562,
0.06408803910017014,
0.02073892392218113,
-0.012503165751695633,
0.028974877670407295,
-0.0019089512061327696,
-0.006704524625092745,
0.004076198674738407,
0.00115435931365937,
0.005870849825441837,
-0.004858851432800293,
-0.014478415250778198,
-0.00970640778541565,
-0.009062430821359158,
0.013542640022933483,
-0.0020952257327735424,
-0.004976946860551834,
0.013095272704958916,
0.01613515056669712,
-0.007884802296757698,
-0.018110938370227814,
0.0033188823144882917,
0.0013254889054223895,
0.011479954235255718,
0.005350329913198948,
-0.004205691162496805,
0.42081305384635925,
-0.00968922395259142,
-0.008573644794523716,
0.0009014643728733063,
0.00906637404114008,
-0.004837092477828264,
0.02269764430820942,
-0.03025415912270546,
-0.012866695411503315,
-0.028694601729512215,
0.003883116412907839,
0.031925003975629807,
0.030822059139609337,
-0.002144597005099058,
0.0022426871582865715,
-4.5188437070464715e-05,
-0.006833445746451616,
-0.030236119404435158,
0.01121692918241024,
0.001971140503883362,
0.017980923876166344,
-0.011958480812609196,
0.004468109924346209,
-0.017697839066386223,
0.07248935103416443,
0.00786749366670847,
-0.009477674961090088,
-0.01135212741792202,
-0.003371140221133828,
-0.012895338237285614,
0.001460296451114118,
-0.02349063754081726,
-0.03485414758324623,
-0.009475907310843468,
-0.00048241938930004835,
-0.0015780527610331774,
-0.0010878484463319182,
0.0011548349866643548,
-0.008919508196413517,
-0.0025622970424592495,
-0.05595393851399422,
0.01394527219235897,
0.012133805081248283,
-0.006726194638758898,
0.005455933045595884,
-0.01264666672796011,
-0.022755097597837448,
0.18685847520828247,
-0.01691720262169838,
0.0023538663517683744,
-0.004938594531267881,
0.0018003035802394152,
0.0008885525166988373,
-0.020330961793661118,
-0.012031910009682178,
0.012911496683955193,
-0.011570140719413757,
-0.011590506881475449,
0.01575644500553608,
0.004554626997560263,
0.00662964629009366,
0.0004100624064449221,
-0.06498976796865463,
0.010730903595685959,
-0.008107719011604786,
0.030820028856396675,
0.009474949911236763,
-0.01906215026974678,
0.009458707645535469,
-0.043944187462329865,
0.005206570029258728,
0.01424614991992712,
0.001170583302155137,
0.0005184027832001448,
-0.14996354281902313,
0.021765295416116714,
0.009286255575716496,
0.0072013926692306995,
-0.004659716039896011,
0.011929381638765335,
-0.003190129529684782,
-0.015722446143627167,
-0.01815064623951912,
0.01834193430840969,
0.006084519904106855,
0.016180403530597687,
-0.032099515199661255,
0.011430078186094761,
0.003294322406873107,
-0.008923242799937725,
0.0003509738598950207,
0.009325523860752583,
-0.0019701814744621515,
-0.028425632044672966,
0.003964909352362156,
0.015864670276641846,
0.010673252865672112,
0.011225402355194092,
0.005043562036007643,
-0.009630661457777023,
-0.004088860470801592,
0.010778944939374924,
-0.006817656569182873,
0.00015835711383260787,
-0.018961118534207344,
0.016901995986700058,
0.021244479343295097,
-0.003804424311965704,
-0.005433924496173859,
0.006842302158474922,
0.016494009643793106,
-0.0024014578666538,
-0.010637672618031502,
-7.727232878096402e-05,
0.0053171431645751,
0.03094189427793026,
0.0353022962808609,
-0.021167855709791183,
-0.0008689461974427104,
0.012743168510496616,
0.008250226266682148,
0.007845299318432808,
-0.013233593665063381,
0.008673184551298618,
-0.02156921476125717,
-0.009463030844926834,
-0.008926155045628548,
-0.006732558365911245,
0.012439075857400894,
0.0009144321666099131,
0.005373652093112469,
-0.009167078882455826,
0.008026966825127602,
0.0063455733470618725,
0.00894924532622099,
-0.015243635512888432,
-0.002839545253664255,
0.0048542930744588375,
-0.006756486836820841,
0.004971047397702932,
-0.001208290341310203,
0.01429009810090065,
0.005963467061519623,
-0.007884562946856022,
0.02749212644994259,
-0.0013566984562203288,
0.005307959858328104,
0.0012359292013570666,
0.01852298155426979,
0.011950000189244747,
0.0072205038741230965,
0.005552733317017555,
0.043303485959768295,
0.0081065334379673,
-0.021918853744864464,
-0.016146095469594002,
-0.029025882482528687,
-0.010243748314678669,
-0.002525107702240348,
-0.0796574279665947,
-0.017740987241268158,
-0.010356458835303783,
0.010222683660686016,
-0.19163382053375244,
0.003947861026972532,
0.013203560374677181,
0.008440962061285973,
-0.008878355845808983,
0.025226140394806862,
0.0013747744960710406,
-0.01895708218216896,
0.011175540275871754,
-0.02654990740120411,
-0.003266084473580122,
-0.041313450783491135,
0.009877652861177921,
-0.0038216696120798588,
0.007183769252151251,
-0.01046864315867424,
-0.006100723519921303,
-0.011098721995949745,
-0.021343091502785683,
-0.02041606418788433,
0.0031096464954316616,
-0.019416995346546173,
0.019631320610642433,
-0.013745995238423347,
0.024470513686537743,
0.01762683317065239,
0.009671872481703758,
0.0028081329073756933,
0.2604740262031555,
0.026210034266114235,
-0.013867592439055443,
0.008933997713029385,
-0.016630325466394424,
-0.005856370087713003,
-0.010458548553287983,
-0.029652513563632965,
0.006278388202190399,
0.004829395096749067,
0.009914031252264977,
-0.014958598650991917,
0.0012652042787522078,
-0.039437148720026016,
-0.007311483845114708,
-0.021462853997945786,
0.008077370002865791,
0.003967227879911661,
0.005063635762780905,
-0.03678053617477417,
-0.0049983724020421505,
-0.0028740540146827698,
-0.0013815644197165966,
-0.0020935693755745888,
0.004799794405698776,
-0.009738544002175331,
-0.023781854659318924,
-0.015738803893327713,
0.032626233994960785,
-0.007238231133669615,
-0.0537262000143528,
0.012643839232623577,
-0.0016240023542195559,
-0.009904581122100353,
-0.007598008960485458,
0.003405306488275528,
-0.0008665909990668297,
-0.004028125666081905,
-0.025651630014181137,
-0.022545790299773216,
-0.0007770610391162336,
-0.007444023620337248,
0.003744380082935095,
-0.02425505220890045,
-0.011070209555327892,
-0.006295229308307171,
-0.01313671562820673,
-0.020499657839536667,
0.01205499842762947,
0.005852322559803724,
0.007805896457284689,
-0.01712975837290287,
-0.01067646499723196,
-0.018875913694500923,
0.014298168942332268,
0.019405683502554893,
0.0063184695318341255,
0.017186330631375313,
0.0016592043684795499,
0.01577926054596901,
-0.001817985437810421,
0.006715130060911179,
-0.00014420766092371196,
-0.00024471114738844335,
0.016705675050616264,
-0.005719838198274374,
-0.0023667258210480213,
-0.01015920378267765,
-0.019472772255539894,
0.0006595418090000749,
0.00735819898545742,
0.003003645921126008,
-0.13396503031253815,
0.011126355268061161,
0.009786608628928661,
-0.005150869023054838,
-0.0010131056187674403,
-0.01121619250625372,
0.0070387390442192554,
-0.006282364018261433,
0.029067253693938255,
0.01522061601281166,
0.00017981980636250228,
0.016120480373501778,
0.006321825552731752,
-0.02651059441268444,
0.0006518823211081326,
0.002931169467046857,
0.04065092280507088,
0.005657408386468887,
-0.022772766649723053,
-0.01689116097986698,
0.005222965497523546,
0.015482182614505291,
-0.006359671242535114,
0.005627564154565334,
0.006165416445583105,
0.0031208707951009274,
-0.018388239666819572,
-0.008571879006922245,
-0.00942636001855135,
0.018839146941900253,
-0.012159918434917927,
-0.0062193116173148155,
-0.004445856902748346,
-0.006011628080159426,
0.0021532855462282896,
0.0010279976995661855,
0.007652680389583111,
0.011531555093824863,
-0.014759029261767864,
-0.006943935062736273,
0.005930377170443535,
-0.002639238955453038,
0.013245626352727413,
-0.019623612985014915,
-0.008578967303037643,
0.001572834444232285,
-0.010334818623960018,
-0.10554677248001099,
-0.00977408979088068,
-0.006572606973350048,
-0.01331594679504633,
-0.012126442976295948,
0.019541308283805847,
0.003057927591726184,
0.006769230589270592,
-0.001669080462306738,
-0.004076978657394648,
0.020721081644296646,
0.017214080318808556,
0.020775336772203445,
-0.009672624990344048,
0.001611808082088828,
-0.020856143906712532,
-0.012448630295693874,
0.01653185859322548,
0.006088856607675552,
-0.01404204685240984,
0.0021502559538930655,
0.013774893246591091,
-0.04752389341592789,
-0.010632338002324104,
-0.0003475138801150024,
-0.03574530407786369,
-0.01821925677359104,
-0.017107384279370308,
0.0007779861916787922,
-0.013850036077201366,
-0.004089724272489548,
0.3403048813343048,
-0.014394883997738361,
0.009628048166632652,
-0.0025859910529106855,
-0.01923978328704834,
-0.011382333002984524,
0.015602130442857742,
-0.003190044779330492,
0.04598904401063919,
0.0028009344823658466,
-0.009925877675414085,
-0.02182849869132042,
-0.004793766885995865,
0.008026781491935253,
-0.03747987002134323,
0.021869324147701263,
0.007670832797884941,
-0.0064276233315467834,
-0.001845433609560132,
-0.011233883909881115,
0.0031099149491637945,
0.004901505075395107,
0.007599821779876947,
-0.012925037182867527,
0.016049401834607124,
0.0050430018454790115,
0.00239281146787107,
-0.008275839500129223,
-0.003632206004112959,
-0.008740216493606567,
-0.01720230095088482,
0.012146754190325737,
0.005852756556123495,
0.015462875366210938,
-0.004518353845924139,
-0.00517266197130084,
0.012092678807675838,
0.006908233277499676,
0.008768774569034576,
0.004185569006949663,
0.01363169215619564,
0.00423558009788394,
0.06088092923164368,
-0.001793655683286488,
0.014455302618443966,
0.010724241845309734,
-0.0052613383159041405,
-0.009440657682716846,
0.029123345389962196,
0.0062365783378481865,
-0.014326999895274639,
0.011866627261042595,
0.015416090376675129,
-0.008981081657111645,
-0.0025332290679216385,
0.0051352581940591335,
0.00821018684655428,
-0.011693744920194149,
-0.011451606638729572,
-0.005426885560154915,
-0.013806660659611225,
-0.006607064511626959,
-0.009153145365417004,
-0.002933175303041935,
0.01713304966688156,
-0.015997933223843575,
0.0014536705566570163,
-0.007618360221385956,
-0.014526145532727242,
-0.008658366277813911,
-0.018422337248921394,
0.0011256936704739928,
-0.02748172916471958,
0.012479417957365513,
0.021452156826853752,
0.001562531921081245,
-0.025555524975061417,
0.0065613193437457085,
-0.00209504971280694,
-0.013913575559854507,
-0.012075789272785187,
-0.01455396693199873,
-0.006788528990000486,
-0.010492048226296902,
-0.003972693346440792,
0.009717912413179874,
-0.025845356285572052,
-0.026431582868099213,
-0.0048737614415585995,
0.017324643209576607,
-0.0013998278882354498,
-0.018030479550361633,
-0.008311547338962555,
-0.007493891753256321,
-0.0035244368482381105,
0.00771515304222703,
0.0021924739703536034,
-0.005751968361437321,
-0.006604904308915138,
0.005347672384232283,
0.019293809309601784,
-0.0003495284472592175,
0.010960870422422886,
0.004829931538552046,
-0.003964467439800501,
-0.008894444443285465,
-0.0016397202853113413,
0.011930232867598534,
-0.010505779646337032,
-0.003346486249938607,
0.015857968479394913,
0.014665059745311737,
0.014732534997165203,
-0.004206720273941755,
-0.0019176763016730547,
0.01332307793200016,
0.0021988777443766594,
-0.02403758279979229,
-0.4469744861125946,
0.01972227357327938,
0.004987025633454323,
0.014963134191930294,
-0.008944636210799217,
-0.005878764670342207,
0.02129177562892437,
0.013982802629470825,
0.018398547545075417,
0.011725765652954578,
-0.02574373222887516,
-0.021991107612848282,
-0.12666742503643036,
0.011377723887562752,
-0.013467676937580109,
0.016786223277449608,
-0.01608293317258358,
-0.04973398521542549,
0.00016399554442614317,
0.03954412788152695,
-0.013195888139307499,
0.012831269763410091,
0.013146511279046535,
0.009329939261078835,
0.014414996840059757,
0.0021092528477311134,
0.002863264875486493,
0.005193709395825863,
0.008082847110927105,
-0.009050048887729645,
-0.0022750503849238157,
-0.001845191465690732,
0.030253732576966286,
-0.009286943823099136,
-0.005152231547981501,
-0.010391759686172009,
0.004703886806964874,
-0.004108126275241375,
0.007455661427229643,
-0.019625799730420113,
-0.0037084040232002735,
0.002227721968665719,
0.019071374088525772,
0.014121511951088905,
-0.03018501214683056,
-0.01767222210764885,
-0.03424135223031044,
-0.15107634663581848,
0.00812471192330122,
-0.009383570402860641,
0.014023326337337494,
0.0047807348892092705,
0.009023885242640972,
-0.0035885018296539783,
0.0006727855652570724,
0.01547104399651289,
-0.00184194918256253,
-0.006005006842315197,
0.02434641867876053,
-0.005449032410979271,
-0.005406939424574375,
-0.003070979146286845,
0.028605615720152855,
0.0045657409355044365,
-0.008447639644145966,
0.014060555025935173,
-0.02609773352742195,
-0.002231627469882369,
-0.016093777492642403,
-0.02187499962747097,
-0.01729179173707962,
2.487706660758704e-05,
-0.016653643921017647,
0.007122368551790714,
0.011934424750506878,
0.02483328804373741,
0.005048356484621763,
0.004156915005296469,
-0.008086747489869595,
0.002900171559303999,
-0.014238164760172367,
-0.01110175158828497,
0.03273740038275719,
0.022436799481511116,
0.007743579801172018,
-0.007951783947646618,
-0.0028308737091720104,
0.019021708518266678,
0.004402468912303448,
-0.0026788879185914993,
-0.0028126374818384647,
0.0008484298014082015,
0.010685634799301624,
-0.009817673824727535,
-0.01054972130805254,
0.011133360676467419,
-0.013031776994466782,
0.020091768354177475,
-0.01239350251853466,
-0.00947580300271511,
-0.007215695921331644,
-0.0034883450716733932,
0.012784423306584358,
-0.026235120370984077,
-0.004409985151141882,
-0.008968875743448734,
0.16672198474407196,
0.0025160759687423706,
-0.005737856961786747,
-0.001338813453912735,
-0.0018787229200825095,
0.012143617495894432,
0.004520316142588854,
0.007079395931214094,
0.10781430453062057,
0.009063338860869408,
-0.0029431963339447975,
0.008303149603307247,
-0.00031500306795351207,
-0.004589234944432974,
0.0059718182310462,
0.02588905766606331,
-0.005579439923167229,
0.01689429022371769,
-0.006689496338367462,
0.006833633873611689,
0.016785891726613045,
-0.010677634738385677,
0.01190104242414236,
-0.002533396240323782,
-0.007275957148522139,
-0.00253050634637475,
-0.019088461995124817,
-0.018875621259212494,
0.02016613818705082,
-0.021909620612859726,
0.0032349645625799894,
0.01767919957637787,
-0.012697185389697552,
0.05635295808315277,
-0.01611725613474846,
0.0064377738162875175,
0.013404080644249916,
-0.002685476327314973,
0.0030814805068075657,
-0.016239970922470093,
-0.006281547714024782,
0.0017259657615795732,
-0.02607986330986023,
0.030810900032520294,
-0.006045927759259939,
0.0010585401905700564,
-0.014656913466751575,
-0.016642896458506584,
0.010925422422587872,
-0.0038384597282856703,
0.004876702092587948,
-0.017458079382777214,
-0.016415869817137718,
0.01680702343583107,
-0.012250321917235851,
0.006089995615184307,
-0.053506746888160706,
-0.011852365918457508,
0.015827203169465065,
-0.0075766462832689285,
-0.001035819062963128,
0.011731131933629513,
0.0026399760972708464,
-0.006009269040077925,
0.0010348598007112741,
-0.004818199202418327,
0.00935276411473751,
-0.004817518871277571,
-0.009980720467865467,
-0.01086097490042448,
-0.012204722501337528,
0.01532853115350008,
-0.15799018740653992,
-0.0017619041027501225,
0.009771771728992462,
-0.018511716276407242,
-0.018712328746914864,
-0.018102288246154785,
0.021576520055532455,
0.010633010417222977,
0.004200779367238283,
0.010237096808850765,
-0.004062600899487734,
0.1258859634399414,
-0.014047365635633469,
0.005082272458821535,
-0.009407381527125835,
-0.00940761063247919,
0.005881977267563343,
0.015061646699905396,
-0.0035507441498339176,
-0.02356540411710739,
-0.010422644205391407,
0.10631720721721649,
0.004390729125589132,
0.023114612326025963,
0.017772773280739784,
-0.010049737058579922,
0.003284045960754156,
0.010080733336508274,
0.014630740508437157,
-0.013631023466587067,
-0.004977407865226269,
0.005198233760893345,
0.0011560205603018403
],
"label": "LOW",
"text": "Is drinking coffee every day bad for my teeth? If so, what can I do to prevent problems?"
},
{
"embedding": [
0.028481466695666313,
-0.0032100745011121035,
-0.0036680581979453564,
-0.012064126320183277,
-0.014738199301064014,
-0.008851398713886738,
0.01305114571005106,
-0.007984080351889133,
0.006234572269022465,
-0.07052527368068695,
-0.01605345867574215,
0.0028764274902641773,
0.006010148208588362,
-0.005135666579008102,
-0.03757606819272041,
0.011544846929609776,
0.013252086006104946,
-0.008494338020682335,
-0.012022257782518864,
-0.01595737598836422,
0.005728313699364662,
-0.003944289870560169,
0.04078539088368416,
-0.019679097458720207,
0.013171138241887093,
-0.0033915722742676735,
0.013431847095489502,
-0.002831314457580447,
-0.012022067792713642,
0.03594043105840683,
-0.003874531714245677,
0.016333891078829765,
-0.007171308621764183,
-0.014637019485235214,
-0.0127987926825881,
-0.0014821848599240184,
-0.003763703629374504,
-0.023475799709558487,
-0.01440843753516674,
-0.011180538684129715,
-0.024014534428715706,
-9.284873522119597e-05,
0.030041739344596863,
-0.023861469700932503,
-0.0041903662495315075,
-0.028050566092133522,
-0.008066064678132534,
0.004128975793719292,
0.006282537244260311,
0.011226043105125427,
-0.00032679576543159783,
-0.006346442271023989,
4.8125351895578206e-05,
0.011022440157830715,
-0.00018652713333722204,
0.008158954791724682,
0.004160143435001373,
-0.007040262222290039,
-0.014989886432886124,
0.008227295242249966,
-0.005556535441428423,
-0.0031042799819260836,
0.010290107689797878,
0.008744004182517529,
-0.01597421243786812,
-0.0016717870021238923,
0.0063789780251681805,
-0.0012683117529377341,
-0.0039807530120015144,
-0.011786128394305706,
-0.005436820909380913,
0.0018739051884040236,
0.007266359869390726,
0.06621047109365463,
0.021580353379249573,
-0.005671683233231306,
0.034882523119449615,
0.01079897303134203,
0.007216220255941153,
0.006121003534644842,
0.010424097068607807,
-0.0035014578606933355,
-0.010838386602699757,
0.002388108056038618,
-0.005598912946879864,
-0.0006575909210368991,
0.013120759278535843,
-0.011220728978514671,
-0.005976819898933172,
0.01715632900595665,
0.006815479602664709,
-0.004414496943354607,
-0.034402087330818176,
-0.008330200798809528,
-0.007713593076914549,
0.016911979764699936,
0.006792599800974131,
0.001579583971761167,
0.4029686152935028,
0.006133169401437044,
-0.006269508507102728,
0.0009417503024451435,
-0.0047039189375936985,
-0.0023076010402292013,
0.019042614847421646,
-0.016674473881721497,
-0.01143437810242176,
-0.022738857194781303,
-0.0013461931375786662,
0.033254340291023254,
0.03403940424323082,
-0.004657887853682041,
0.010137207806110382,
0.003191462717950344,
0.00423059007152915,
-0.014854967594146729,
0.00187963608186692,
0.0033404480200260878,
0.008774741552770138,
-0.004102198872715235,
0.013924067839980125,
-0.002166380872949958,
0.06777045875787735,
0.01696203276515007,
-0.009100930765271187,
-0.013235462829470634,
0.003540582722052932,
-0.009110520593822002,
0.010211421176791191,
-0.01178856659680605,
-0.04253000393509865,
-0.014148823916912079,
-0.009067322127521038,
0.0002958943950943649,
0.009686066769063473,
0.0011271099792793393,
-0.022043123841285706,
0.004045727197080851,
-0.04135211184620857,
0.011710057966411114,
0.007540761027485132,
-0.021476654335856438,
0.011550378985702991,
-0.01543466653674841,
-0.018416501581668854,
0.18628528714179993,
-0.010102721862494946,
-0.009657307527959347,
-0.0007819949532859027,
-0.002873751102015376,
-0.010273076593875885,
-0.018142543733119965,
-0.01662677340209484,
0.0031405820045620203,
-0.0047050523571670055,
-0.012725889682769775,
0.0184447281062603,
-0.0031997181940823793,
-0.006230160593986511,
-0.0003932864929083735,
-0.05243059620261192,
0.002467630198225379,
-0.006740711163729429,
0.041581891477108,
0.00135491241235286,
-0.0043099713511765,
0.00013487310206983238,
-0.0531163327395916,
0.01094493642449379,
0.0371587909758091,
0.009056678041815758,
-0.0022147393319755793,
-0.15529899299144745,
0.012336480431258678,
0.012374239973723888,
-0.0013503319351002574,
0.008443396538496017,
-0.00022072401770856231,
-0.00296808616258204,
-0.010984603315591812,
-0.017146727070212364,
0.01517662312835455,
0.0016807044157758355,
-0.008087344467639923,
-0.020684365183115005,
0.00844782218337059,
0.004575537052005529,
-0.02506963536143303,
-0.003397218883037567,
0.002653817180544138,
0.0016820784658193588,
-0.013694286346435547,
0.002471347339451313,
0.01588994637131691,
0.020769501104950905,
-0.0029095239005982876,
0.015043907798826694,
-0.017222166061401367,
-0.01522522047162056,
-0.001344539923593402,
-0.010885421186685562,
0.005388220772147179,
-0.01165734138339758,
0.002077261218801141,
0.015180230140686035,
0.0065882327035069466,
-0.004321780521422625,
0.0065977550111711025,
0.024087296798825264,
0.004317300394177437,
-0.01362061221152544,
0.000977547257207334,
-0.009196503087878227,
0.020808910951018333,
0.0413227453827858,
-0.014660883694887161,
-0.005173196084797382,
0.008529740385711193,
0.0005162470042705536,
-0.0051298500038683414,
0.01033002883195877,
0.012104791589081287,
-0.0182360652834177,
-0.01297315489500761,
0.0014281488256528974,
0.003872287692502141,
0.007588055916130543,
-0.014890051446855068,
-0.0001284214376937598,
-0.016883866861462593,
0.00034463449264876544,
0.011394888162612915,
-0.0013301551807671785,
-6.5691776399035e-05,
0.0027407945599406958,
-0.014958030544221401,
-0.00879379827529192,
0.017592739313840866,
0.008886925876140594,
0.024556633085012436,
-0.0017414436442777514,
-0.0027629819232970476,
0.023790931329131126,
-0.013575847260653973,
0.0021446903701871634,
0.013762501999735832,
0.024049069732427597,
0.00280263414606452,
-0.004523663781583309,
-0.0053471969440579414,
0.061793193221092224,
0.01940036751329899,
-0.01367171574383974,
-0.010136540979146957,
-0.028502998873591423,
0.00020018868963234127,
-0.009876967407763004,
-0.08737751841545105,
-0.02316276729106903,
-0.011066901497542858,
0.008019373752176762,
-0.19544245302677155,
0.012813440524041653,
0.010146625339984894,
0.003991636913269758,
-0.008251442573964596,
0.01881340891122818,
0.007313342299312353,
-0.005583884660154581,
-0.002973964437842369,
-0.029929479584097862,
0.009119047783315182,
-0.028870416805148125,
0.0014640770386904478,
-0.0021524184849113226,
0.02146441489458084,
0.0005779755883850157,
-0.0027765659615397453,
0.008556170389056206,
0.0009732022881507874,
-0.019156960770487785,
0.006540260743349791,
-0.015143433585762978,
0.03906533122062683,
-0.02133104018867016,
0.02247505635023117,
0.009192245081067085,
0.002206547185778618,
0.0037197815254330635,
0.25034400820732117,
0.02491210587322712,
0.0064856004901230335,
0.0181731004267931,
-0.026356995105743408,
-0.003594128880649805,
-0.0026246323250234127,
-0.03161114081740379,
0.017528334632515907,
-0.0027028783224523067,
0.004975538235157728,
-0.01684742048382759,
-0.0060270666144788265,
-0.03920280933380127,
0.008427784778177738,
-0.022113759070634842,
0.008520949631929398,
-0.0029229901265352964,
0.011051123961806297,
-0.04535704478621483,
-0.009062517434358597,
0.027849270030856133,
-7.125990669010207e-05,
0.008085643872618675,
0.003574596717953682,
-0.0058377450332045555,
-0.043075814843177795,
-0.024250848218798637,
0.03552256152033806,
0.008264884352684021,
-0.05097333341836929,
0.006994653958827257,
0.00281835556961596,
-0.022983506321907043,
-0.012356574647128582,
0.0008327520336024463,
-0.0020424528047442436,
0.0013315633404999971,
-0.018399694934487343,
-0.019879095256328583,
0.00553104979917407,
-0.0048089600168168545,
0.02499583177268505,
-0.01640998385846615,
-0.008041865192353725,
0.006009378004819155,
-0.008389551192522049,
0.0005091773928143084,
0.013637284748256207,
0.008504332043230534,
0.00012893107486888766,
-0.015254270285367966,
-0.0037575499154627323,
-0.02032279036939144,
0.011838273145258427,
0.01785503700375557,
0.009433496743440628,
0.01658165641129017,
-0.01113493088632822,
0.019913066178560257,
-0.0025226385332643986,
-0.0071386778727173805,
0.003986249677836895,
-0.006006501615047455,
0.019915560260415077,
0.006187689024955034,
-0.016032641753554344,
-0.0052686394192278385,
-0.01946667581796646,
0.008946087211370468,
0.007346574682742357,
0.008798312395811081,
-0.13482312858104706,
0.019759267568588257,
0.01634576916694641,
-0.010625009424984455,
0.0030150171369314194,
-0.005240299738943577,
0.011385271325707436,
-0.0049846479669213295,
0.021069277077913284,
0.011931764893233776,
-0.007639411836862564,
0.0031936154700815678,
0.01148471049964428,
-0.021793212741613388,
-0.0005502455751411617,
0.01754508726298809,
0.04001929238438606,
0.016804732382297516,
-0.014178791083395481,
-0.014155114069581032,
0.009545539505779743,
0.015728304162621498,
-0.002480913884937763,
-0.0037433793768286705,
-0.004303444176912308,
0.0036718042101711035,
-0.027051599696278572,
0.0005708340322598815,
-0.0045464555732905865,
0.018299678340554237,
-0.005026747472584248,
-0.007229410577565432,
-0.004213571548461914,
-0.0010581830283626914,
-0.0009691077866591513,
-8.765130769461393e-05,
0.01213790662586689,
0.011448062025010586,
-0.015211221762001514,
-0.014225609600543976,
0.005352279171347618,
0.002950174966827035,
0.0018103790935128927,
-0.01874382235109806,
0.004209776408970356,
0.007550138048827648,
-0.01867091841995716,
-0.10517671704292297,
-0.014730149880051613,
-0.011389746330678463,
-0.014610673300921917,
-0.00628548301756382,
0.0066108000464737415,
0.014477737247943878,
0.003205421380698681,
-0.005561803467571735,
-0.005047264043241739,
0.015232146717607975,
0.0026111097540706396,
0.008841216564178467,
0.0013381035532802343,
0.01354994997382164,
-0.02971905656158924,
0.002546435920521617,
0.019230207428336143,
0.001415462582372129,
-0.02076919749379158,
0.007205471396446228,
0.00804719515144825,
-0.05084868520498276,
-0.004378694109618664,
0.0028741599526256323,
-0.029340794309973717,
-0.006062444765120745,
-0.01728450506925583,
0.004825662821531296,
-0.017383180558681488,
-0.013110457919538021,
0.3406284749507904,
-0.011256606318056583,
0.015743611380457878,
0.007575451396405697,
-0.014195769093930721,
0.00389893283136189,
0.019256463274359703,
-0.009480844251811504,
0.05363301932811737,
0.0031888687517493963,
-0.021639686077833176,
-0.024615388363599777,
0.016033759340643883,
0.0012751492904499173,
-0.01906251348555088,
0.021517276763916016,
0.004980066791176796,
-0.003369574435055256,
-0.006726786494255066,
0.002780372742563486,
-0.0071771773509681225,
-0.015407818369567394,
0.016232172027230263,
-0.009401519782841206,
0.002734348876401782,
0.018209725618362427,
0.00510728545486927,
-0.0025584683753550053,
-0.00753369415178895,
-0.013244487345218658,
-0.018637966364622116,
0.018083272501826286,
0.009038437157869339,
0.018527138978242874,
0.001672680489718914,
-0.014017142355442047,
0.001983570633456111,
0.0003638377820607275,
0.013502437621355057,
0.015476514585316181,
0.01534595899283886,
-0.005360999144613743,
0.05548416078090668,
-0.0022822082974016666,
0.016051001846790314,
0.009160741232335567,
-0.0007279389537870884,
-0.01568947173655033,
0.022993922233581543,
0.01002364233136177,
0.0009458106360398233,
0.021198786795139313,
0.008258165791630745,
-0.01263381727039814,
0.009771843440830708,
0.010516144335269928,
0.0033517556730657816,
-0.008542624302208424,
0.007836688309907913,
0.00304834870621562,
0.0016635021893307567,
-0.0173858143389225,
-0.004054618533700705,
-0.004043348599225283,
0.015762904658913612,
-0.004780821036547422,
0.005086285527795553,
-0.016211949288845062,
-0.027660345658659935,
-0.012494189664721489,
-0.017237087711691856,
0.00409947382286191,
-0.01701396517455578,
0.013591744005680084,
0.018766677007079124,
0.009997373446822166,
-0.02899988740682602,
0.005956615786999464,
0.0018688042182475328,
-0.012759780511260033,
-0.01984594017267227,
-0.01342670526355505,
-0.007871230132877827,
-0.017757218331098557,
-0.010107247158885002,
-0.005552962888032198,
-0.042343057692050934,
-0.01442392822355032,
0.004624031018465757,
0.009142719209194183,
-0.0024364530108869076,
-0.00779950013384223,
-0.012429878115653992,
0.009014386683702469,
-0.005744538269937038,
0.011449596844613552,
2.4167520678020082e-05,
-0.010021339170634747,
-0.005453824531286955,
0.007501058280467987,
0.023800330236554146,
0.000507863936945796,
0.0009390436462126672,
-0.009046148508787155,
0.002733289496973157,
-0.0023227271158248186,
-0.004945544991642237,
0.008424296043813229,
-0.012587535195052624,
-0.0005831593298353255,
0.0115160858258605,
-0.005984772462397814,
0.012134176678955555,
0.0018935505067929626,
-0.007110421545803547,
0.020056268200278282,
-0.006530118174850941,
-0.02069927752017975,
-0.4561271667480469,
0.006033765152096748,
0.006408394780009985,
0.004936664830893278,
-0.021691415458917618,
0.0016890342812985182,
0.026843173429369926,
0.004279727581888437,
0.015640810132026672,
0.00015536749560851604,
-0.022893333807587624,
-0.009500727988779545,
-0.13548730313777924,
0.013845794834196568,
-0.008374335244297981,
0.002331565599888563,
-0.0059048766270279884,
-0.05896355211734772,
0.0010769212385639548,
0.03999321162700653,
-0.004881581291556358,
0.010504393838346004,
0.01977461576461792,
0.014779353514313698,
0.029292156919836998,
-0.01331364642828703,
-0.00449405238032341,
0.005207533482462168,
0.00795875396579504,
-0.0009343190467916429,
-0.00478253373876214,
-0.021151812747120857,
0.027697231620550156,
0.0037257433868944645,
-0.0008393958560191095,
-0.009514912962913513,
-0.002861006883904338,
-0.0014223129255697131,
0.011421425268054008,
-0.02395738661289215,
-0.006004301365464926,
0.007238397840410471,
0.013602610677480698,
0.013419140130281448,
-0.030369361862540245,
-0.01429602038115263,
-0.03642832860350609,
-0.148605614900589,
0.002944819163531065,
-0.008960862644016743,
0.017539873719215393,
0.0005102307186461985,
0.0022721323184669018,
-0.006210957188159227,
-0.011270688846707344,
0.011764095164835453,
0.007209755480289459,
0.010177290998399258,
0.019597399979829788,
-0.014854487963020802,
-0.01290462352335453,
-0.006237701512873173,
0.02643461711704731,
0.002075844444334507,
0.004868035204708576,
0.008638898842036724,
-0.017200855538249016,
-0.0013375000562518835,
-0.018687915056943893,
-0.02052062377333641,
-0.0008527587633579969,
-0.007883081212639809,
-0.004736979026347399,
0.010171622037887573,
0.018002936616539955,
0.021635418757796288,
1.7149042832897976e-05,
-0.003462042659521103,
0.007129318546503782,
-0.001986239105463028,
-0.025379445403814316,
-0.006045063491910696,
0.015646036714315414,
0.025369713082909584,
0.01897394098341465,
-0.004390508867800236,
-0.0018207089742645621,
0.015384625643491745,
-0.011445743031799793,
0.009166812524199486,
0.0001588084560353309,
0.01275301817804575,
0.0068309111520648,
-0.00376890879124403,
-0.0017735871952027082,
0.00171623972710222,
-0.019546490162611008,
0.008847960270941257,
-0.020602576434612274,
-0.008028321899473667,
-0.007949132472276688,
0.005732436198741198,
0.008815097622573376,
-0.029176734387874603,
-0.00013534327445086092,
-0.01748441345989704,
0.17584189772605896,
0.014477892778813839,
-0.0020427689887583256,
0.004106832668185234,
-0.008773569017648697,
0.005818760488182306,
-0.0002685371437110007,
0.009639648720622063,
0.09532323479652405,
0.0035690173972398043,
-0.018146900460124016,
0.013089788146317005,
-0.0009885039180517197,
0.008971941657364368,
0.008153371512889862,
0.024393999949097633,
0.002158266259357333,
0.014087831601500511,
-0.015712009742856026,
0.0044474187307059765,
0.011503162793815136,
-0.012693719938397408,
-0.00025247258599847555,
-0.011811968870460987,
-0.0024292569141834974,
0.002557281870394945,
-0.03024854138493538,
-0.01596192829310894,
0.01634310372173786,
-0.02085294760763645,
0.005664019379764795,
0.004347300156950951,
-0.02302495948970318,
0.06019114702939987,
-0.01967056654393673,
-0.0006525053177028894,
0.02158287726342678,
-0.004441113211214542,
-0.0018470429349690676,
-0.02695525996387005,
-0.010261321440339088,
-0.010808425955474377,
-0.03391271084547043,
0.03491147980093956,
0.0033113835379481316,
-0.0026383099611848593,
-0.015767330303788185,
-0.009497586637735367,
0.002648768713697791,
-0.013696894980967045,
-0.017453767359256744,
-0.013554755598306656,
-0.006575877778232098,
0.007614815607666969,
0.003164459951221943,
-0.008089522831141949,
-0.04084805026650429,
-0.015493734739720821,
0.012476840987801552,
-0.015358414500951767,
0.008400984108448029,
-0.0027257942128926516,
0.0037222024984657764,
-0.004754429683089256,
-0.0017123222351074219,
-0.005012303590774536,
0.0025338344275951385,
-0.025273513048887253,
0.0007854397990740836,
-0.01523483358323574,
-0.009258589707314968,
0.008368309587240219,
-0.1480589210987091,
0.002570760902017355,
0.010927931405603886,
-0.03319719806313515,
-0.023863675072789192,
-0.01907525770366192,
0.02151910774409771,
0.013949736021459103,
-0.0012292651226744056,
0.01792049966752529,
0.004961602855473757,
0.12112898379564285,
0.00016630523896310478,
-0.002727924380451441,
-0.0075034270994365215,
-0.013858512043952942,
0.015004047192633152,
0.010907307267189026,
-0.013387860730290413,
-0.014549978077411652,
-0.015193810686469078,
0.1108766570687294,
0.003858026582747698,
0.02428543195128441,
0.006991077214479446,
-0.0043445914052426815,
-0.0035389061085879803,
0.006504585966467857,
0.008052886463701725,
-0.003911263309419155,
-0.01721899025142193,
0.01042222697287798,
0.010188529267907143
],
"label": "LOW",
"text": "You are AoControl, a helpful and knowledgeable agent. To achieve your goal of answering complex questions correctly, you have access to the following tools:\n AoInnovus: An agent with knowledge of the Cadence Innovus User Guide and corresponding Tcl command usage\n AoTcl: An agent with knowledge of the Tcl language\nTo answer questions, you'll need to go through multiple steps involving step-by-step thinking and selecting appropriate tools and their inputs; tools will respond with observations.\nWhen you are ready for a final answer, respond with the `Final Answer:`\nUse the following format:\nQuestion: The question to be answered\nTHought: Reason if you have the final answer. If yes, answer the question. If not, find out the missing information needed to answer it.\nTool: Pick one of {AoInnovus, AoTcl}\nTool Input: The input for the tool\nObservation: The tool will respond with the result\n...\nFinal Answer: The final answer to the question, make it short (50-100 words)\nThought, Tool, Tool Input, and Observation steps can be repeated multiple times, but sometimes we can find an answer in the first pass.\n---\nQuestion: How do I identify the impact of metal fill on my timing violations?\nThought: Let's think step-by-step, I first need to"
},
{
"embedding": [
0.024840258061885834,
-0.0015645172679796815,
5.6374155974481255e-05,
-0.014388852752745152,
-0.024910517036914825,
-0.00859635230153799,
0.017377613112330437,
-0.008725173771381378,
0.007821537554264069,
-0.07174370437860489,
-0.013510563410818577,
-0.0032665091566741467,
0.0001901791983982548,
-0.007318215910345316,
-0.037550412118434906,
0.0035291339736431837,
0.01283250655978918,
-0.007668894249945879,
-0.005026691593229771,
-0.014403673820197582,
0.0067305415868759155,
-0.009402900002896786,
0.03989814966917038,
-0.014664608053863049,
0.008360653184354305,
0.004296925850212574,
0.01292677503079176,
0.012497290037572384,
-0.014227695763111115,
0.022701071575284004,
-0.010607942007482052,
0.0221343245357275,
-0.005716703366488218,
-0.004451853688806295,
-0.01209544762969017,
0.005489578004926443,
0.00011698235903168097,
-0.024916090071201324,
-0.017456337809562683,
-0.0029979972168803215,
-0.027417326346039772,
0.00883050262928009,
0.0377432182431221,
-0.019825465977191925,
-0.005110188852995634,
-0.029360653832554817,
-0.006976551376283169,
0.008311701938509941,
0.0012641563080251217,
0.0023616598919034004,
0.004920012783259153,
-0.011647684499621391,
-0.004431793466210365,
0.0067876242101192474,
0.007232822943478823,
0.001039189170114696,
-0.017042439430952072,
0.004495526663959026,
-0.019581252709031105,
0.012650887481868267,
-0.006251536309719086,
-0.006269072648137808,
0.018217043951153755,
0.006080232094973326,
-0.025791514664888382,
0.0013947613770142198,
0.004763501230627298,
-0.009445135481655598,
-0.02059006132185459,
-0.008539936505258083,
-0.004023321438580751,
0.007580232806503773,
0.019084036350250244,
0.05691045522689819,
0.021833406761288643,
-0.01435061078518629,
0.031718943268060684,
0.008858711458742619,
-0.000720757176168263,
0.006230291910469532,
0.009817402809858322,
0.006390701979398727,
-0.011464502662420273,
0.0044830571860075,
-0.011006556451320648,
-0.008454391732811928,
0.014219686388969421,
-0.011391336098313332,
-0.006215689703822136,
0.023210842162370682,
0.010772746056318283,
0.0027606114745140076,
-0.021169591695070267,
-0.004824865609407425,
0.005002194549888372,
0.014215322211384773,
-0.0032017009798437357,
0.0028503136709332466,
0.41710028052330017,
0.00814126804471016,
-0.0070417290553450584,
-0.0016646182630211115,
0.006949332542717457,
-0.013971114531159401,
0.027781521901488304,
-0.017289938405156136,
-0.010896011255681515,
-0.026439353823661804,
0.004756647627800703,
0.025928016752004623,
0.026682861149311066,
-0.0024499224964529276,
0.0021146212238818407,
-0.005630424711853266,
0.005101616028696299,
-0.008366675116121769,
0.002192849526181817,
-0.002031768672168255,
0.013425199314951897,
-0.006744695827364922,
0.010426750406622887,
7.582726539112628e-05,
0.06567973643541336,
0.004849693272262812,
-0.008323220536112785,
-0.008960348553955555,
0.007383080665022135,
-0.011806067079305649,
0.019337370991706848,
-0.014227242209017277,
-0.04086421802639961,
-0.010161885991692543,
-0.012742076069116592,
-0.005602056160569191,
0.006665399298071861,
0.006662236992269754,
-0.0039442237466573715,
0.0019846612121909857,
-0.04831217974424362,
0.0033463446889072657,
0.0031533048022538424,
-0.011144893243908882,
0.0020327079109847546,
-0.013287914916872978,
-0.020823916420340538,
0.18545155227184296,
-0.010935632511973381,
-0.000747696787584573,
-0.009125093929469585,
-0.007694651372730732,
-0.0071111880242824554,
-0.008713600225746632,
-0.01221254002302885,
0.010792847722768784,
-0.00018023859593085945,
-0.010863160714507103,
-0.0007676454843021929,
0.0036957012489438057,
-0.00595452357083559,
-0.008354803547263145,
-0.058121275156736374,
-0.003610387211665511,
-0.01386103592813015,
0.025868836790323257,
-0.0010695307282730937,
-0.0064101023599505424,
0.004138941876590252,
-0.05295521020889282,
0.012965725734829903,
0.02200685814023018,
-0.0056598917581140995,
-0.003430596087127924,
-0.15723979473114014,
0.016480427235364914,
0.004013434052467346,
0.003278015647083521,
0.010810029692947865,
0.010305451229214668,
0.001266281120479107,
-0.013977119699120522,
-0.023042690008878708,
0.017386872321367264,
0.006525708828121424,
-0.002131462562829256,
-0.021040920168161392,
0.011388544924557209,
0.005973044782876968,
-0.0032734829001128674,
-0.0010700991842895746,
0.003017824376001954,
0.009679210372269154,
-0.010598341003060341,
0.006434483453631401,
0.0027935639955103397,
0.013719925656914711,
-0.0034350042697042227,
0.007843795232474804,
-0.008577261120080948,
-0.004205331206321716,
0.006444592960178852,
-0.02041608653962612,
-0.005844942759722471,
-0.007273368537425995,
-0.004797463305294514,
0.02389962039887905,
0.011031631380319595,
0.005844451021403074,
0.01320777740329504,
0.01931295543909073,
-0.0011255262652412057,
-0.01863190159201622,
0.000987755716778338,
-0.004576295614242554,
0.027410831302404404,
0.03186151012778282,
-0.01415025070309639,
-0.0016775663243606687,
-0.002681757090613246,
0.009672276675701141,
-0.0012636741157621145,
-0.0021103855688124895,
0.0038328503724187613,
-0.026476852595806122,
-0.006638633087277412,
0.002743673510849476,
0.008268196135759354,
0.01676582172513008,
-0.003966456279158592,
0.0002104417944792658,
-0.015604516491293907,
0.00809399876743555,
0.007929506711661816,
0.005954691208899021,
-0.013236487284302711,
-0.0021518126595765352,
-0.01382429338991642,
9.303195838583633e-06,
-0.0018551272805780172,
0.005362418480217457,
0.013414151035249233,
-0.006397624500095844,
-0.0014069422613829374,
0.02570302039384842,
-0.013567461632192135,
0.005549302324652672,
0.01781168021261692,
0.0262101162225008,
0.011022811755537987,
-0.006409182213246822,
0.0020116225350648165,
0.05499112233519554,
0.02254663221538067,
-0.008363842964172363,
-0.01898002251982689,
-0.03540739789605141,
-0.011944239027798176,
0.0019064925145357847,
-0.07954808324575424,
-0.019968586042523384,
-0.0031125196255743504,
0.014222970232367516,
-0.20119237899780273,
0.0018184160580858588,
0.0072032432071864605,
0.004102004691958427,
-0.015538026578724384,
0.024823244661092758,
-0.010158659890294075,
-0.016466405242681503,
0.002224315656349063,
-0.035156335681676865,
6.619568739552051e-05,
-0.03547162935137749,
0.007652031257748604,
-0.001450402196496725,
0.022436633706092834,
-0.0031599702779203653,
-0.0011001807870343328,
0.01046072505414486,
-0.005853458773344755,
-0.027131421491503716,
0.007366749458014965,
-0.02735035866498947,
0.03964376449584961,
-0.02554081752896309,
0.02581152506172657,
0.013891804032027721,
0.011512299999594688,
0.013164300471544266,
0.26473042368888855,
0.010666390880942345,
-0.003727229544892907,
0.022583164274692535,
-0.02685554139316082,
-0.0040924325585365295,
0.001885462668724358,
-0.0446600578725338,
0.010075084865093231,
-0.005791055504232645,
0.005401124712079763,
-0.016727354377508163,
-0.007257094141095877,
-0.026329996064305305,
0.011143248528242111,
-0.022059446200728416,
0.001818096381612122,
0.0008688251255080104,
0.007902792654931545,
-0.04334152117371559,
-0.0029937366489320993,
0.03540274128317833,
0.007430222816765308,
-0.002089027315378189,
0.011236393824219704,
-0.003945713862776756,
-0.029133111238479614,
-0.023144977167248726,
0.03272983059287071,
0.006350520998239517,
-0.05683654174208641,
0.0026429248973727226,
0.011371240019798279,
-0.028783055022358894,
-0.0048829009756445885,
0.0008421047823503613,
-0.002922669518738985,
-0.0054532126523554325,
-0.013692200183868408,
-0.019361477345228195,
0.00015910693036857992,
-0.008601907640695572,
0.006111239083111286,
-0.011346287094056606,
-0.01126160565763712,
0.004586772061884403,
-0.015367825515568256,
-0.0017899534432217479,
0.017471833154559135,
0.0005212621763348579,
0.010575573891401291,
-0.0035899546928703785,
0.001336597721092403,
-0.017037035897374153,
0.0012360840337350965,
0.013833070173859596,
0.01054474338889122,
0.016483919695019722,
-0.002364850603044033,
0.011857695877552032,
0.003393115010112524,
-0.013289768248796463,
-0.0033588900696486235,
-0.0039616534486413,
0.022151563316583633,
0.013819561339914799,
-0.010200083255767822,
-0.006015324033796787,
-0.014380942098796368,
0.007848050445318222,
0.011244339868426323,
0.0008799180504865944,
-0.14393959939479828,
0.014871498569846153,
0.014705857262015343,
-0.0014547527534887195,
0.0067459046840667725,
-0.002359651727601886,
0.01123867928981781,
0.002401716774329543,
0.025028321892023087,
0.01980222389101982,
0.0012641848297789693,
0.00945612508803606,
0.014631419442594051,
-0.02073809504508972,
0.005810648202896118,
0.008917747996747494,
0.042016904801130295,
0.01619095914065838,
-0.025804700329899788,
-0.024378707632422447,
0.002526024589315057,
0.009094302542507648,
-0.006429493427276611,
0.0022577547933906317,
-0.0058781965635716915,
0.0024734160397201777,
-0.03527867794036865,
0.008104153908789158,
0.002901360159739852,
0.038025811314582825,
-0.011282111518085003,
-0.011220510117709637,
-0.005522249732166529,
-0.005636924412101507,
-0.0014363846275955439,
-0.005165454465895891,
0.015278355218470097,
0.021099505946040154,
-0.017694583162665367,
-0.011803172528743744,
0.008187218569219112,
-0.008208720944821835,
0.004402540624141693,
-0.02177090384066105,
-0.002210113452747464,
0.007737032137811184,
-0.013501964509487152,
-0.09632426500320435,
-0.00034174288157373667,
-0.015364795923233032,
-0.02129526250064373,
0.0010573435574769974,
0.008376150391995907,
0.0151366563513875,
-0.005887048784643412,
-0.008216279558837414,
-0.007091848645359278,
0.01729709655046463,
0.00820684339851141,
0.017270023003220558,
0.019611436873674393,
0.004852007143199444,
-0.02297230437397957,
0.006354158744215965,
0.011328034102916718,
-0.0006285585695877671,
-0.022259151563048363,
0.0061459108255803585,
0.008967900648713112,
-0.050920162349939346,
-0.014340126886963844,
0.01356776338070631,
-0.016176240518689156,
-0.014477209188044071,
-0.021223654970526695,
0.006773891393095255,
-0.012576273642480373,
0.007173371966928244,
0.3415336012840271,
-0.012550589628517628,
0.016177793964743614,
0.007380795199424028,
-0.010290331207215786,
0.004356216173619032,
0.009825277142226696,
-0.005782660562545061,
0.05502716079354286,
0.0001766723144100979,
-0.024476079270243645,
-0.01552102342247963,
0.003055304056033492,
-0.0009447001502849162,
-0.016417643055319786,
0.022580020129680634,
0.0005981744034215808,
-0.007513320539146662,
-0.0028708830941468477,
-0.0005884147831238806,
0.000245991483097896,
-0.020172985270619392,
0.006437433883547783,
-0.025057477876544,
0.019062867388129234,
0.01807396113872528,
0.008214913308620453,
0.0026848262641578913,
0.007118721026927233,
-0.017846832051873207,
-0.014722853899002075,
0.01999831013381481,
0.021497366949915886,
0.013987131416797638,
0.009339235723018646,
-0.006742315832525492,
0.009425864554941654,
-8.489238825859502e-05,
0.002788026351481676,
0.018926434218883514,
0.015000591054558754,
0.0011588373454287648,
0.059193626046180725,
0.002880566520616412,
0.017623521387577057,
0.011811076663434505,
6.386560926330276e-06,
-0.013703346252441406,
0.027247130870819092,
0.0004161787510383874,
-0.0003448509960435331,
0.02393953874707222,
0.01017936784774065,
-0.014704693108797073,
0.010582435876131058,
0.0020718188025057316,
0.008362813852727413,
-0.013120267540216446,
0.006983323022723198,
0.015826696529984474,
-0.005327451974153519,
-0.0077722808346152306,
-0.007537956349551678,
-0.0029721995815634727,
0.006403803359717131,
-0.00555672962218523,
0.015360276214778423,
-0.00960031058639288,
-0.020141616463661194,
-0.010346966795623302,
-0.011648895218968391,
0.00913163274526596,
-0.022264789789915085,
0.008577409200370312,
0.020101308822631836,
-0.0005575591931119561,
-0.023118237033486366,
0.006481415592133999,
-0.009127994067966938,
-0.02066565863788128,
-0.017696062102913857,
-0.015102079138159752,
-0.00611625611782074,
-0.020304236561059952,
0.00649307994171977,
-0.003911956213414669,
-0.029769279062747955,
-0.028961893171072006,
0.003960169851779938,
0.006484720855951309,
0.008356100879609585,
-0.004892655648291111,
-0.017281975597143173,
0.005201536696404219,
0.00208469619974494,
0.013617320917546749,
-0.002101335907354951,
-0.006406659726053476,
-0.006206684745848179,
0.009179458022117615,
0.02667398191988468,
0.005018937401473522,
0.003121655900031328,
-0.0021722482051700354,
-0.001103986520320177,
-0.006091879680752754,
-0.010247857309877872,
0.012970657087862492,
-0.005749201402068138,
-0.001689302735030651,
0.026158900931477547,
-0.00819226261228323,
0.004224973265081644,
0.001099661341868341,
-0.004321099724620581,
0.01711205020546913,
-0.009542776271700859,
-0.020068898797035217,
-0.4290156662464142,
0.011991409584879875,
-0.006972335744649172,
0.0023829564452171326,
-0.025456685572862625,
0.003763156710192561,
0.028076477348804474,
0.014078655280172825,
0.020901547744870186,
0.001673151389695704,
-0.021953947842121124,
0.003809395246207714,
-0.12947534024715424,
0.017528489232063293,
-0.01565597765147686,
0.006012924946844578,
-0.029283136129379272,
-0.06671526283025742,
-0.007649728562682867,
0.026083873584866524,
0.001493664225563407,
0.03187660127878189,
0.020202843472361565,
0.01613825559616089,
0.023128753527998924,
0.004364736378192902,
0.005175204016268253,
-0.0008803998352959752,
0.016176937147974968,
0.0025749620981514454,
0.007012797985225916,
-0.007806611247360706,
0.02253611385822296,
0.010364153422415257,
-0.01341578271239996,
-0.005878238473087549,
-0.008752523921430111,
-0.0015270526055246592,
0.014069913886487484,
-0.01719549112021923,
-0.002511486178264022,
-0.0013903529616072774,
0.013782385736703873,
0.016285844147205353,
-0.03558339923620224,
-0.007845381274819374,
-0.03562489151954651,
-0.14295203983783722,
-0.0006215452449396253,
-0.004575970582664013,
0.023643339052796364,
-0.0014959288528189063,
-0.009143947623670101,
-0.006698477081954479,
-0.015811027958989143,
-0.001121130189858377,
0.0063217864371836185,
0.007850510999560356,
0.019110703840851784,
-0.023196253925561905,
-0.012623902410268784,
-0.007229713723063469,
0.026211680844426155,
0.0002736815076787025,
-0.012039975263178349,
0.004889022093266249,
-0.02939785085618496,
-0.008388560265302658,
-0.009008423425257206,
-0.019521838054060936,
-0.006818926893174648,
-0.007718607783317566,
-0.0025181742385029793,
-0.002900730585679412,
0.017861586064100266,
0.01983264461159706,
0.009650166146457195,
-0.00938248448073864,
-0.002834429731592536,
-0.004031128250062466,
-0.03529934585094452,
-0.006639923434704542,
0.021239785477519035,
0.009701414965093136,
0.019734863191843033,
-0.004197245929390192,
0.0036317496560513973,
0.015727747231721878,
-0.016130395233631134,
0.009999246336519718,
0.00345601886510849,
0.004528467543423176,
0.004588351584970951,
-0.0038189978804439306,
-0.008681013248860836,
0.008653281256556511,
-0.00876501202583313,
-0.011188462376594543,
-0.02745477668941021,
-0.002990785287693143,
-0.006794621702283621,
0.003053586231544614,
0.008769434876739979,
-0.02841743640601635,
-0.011662839911878109,
-0.021535813808441162,
0.17293351888656616,
0.0052004409953951836,
-0.005015458445996046,
0.008424566127359867,
-0.012771968729794025,
0.00625241594389081,
0.006077395286411047,
0.005867647007107735,
0.09948498010635376,
0.003813114482909441,
-0.012476609088480473,
0.001477460958994925,
-0.0055984496138989925,
0.0020091973710805178,
-0.0058953664265573025,
0.027015427127480507,
0.00201135640963912,
0.00445203622803092,
-0.021933386102318764,
0.008818384259939194,
0.023578336462378502,
-0.009949874132871628,
0.00709154037758708,
-0.005477589089423418,
0.014164554886519909,
-0.00216422020457685,
-0.022440491244196892,
-0.015278252772986889,
0.015204706229269505,
-0.020117947831749916,
0.005237562581896782,
-0.005990272853523493,
-0.007993198931217194,
0.05654369294643402,
-0.00957244262099266,
0.01355586014688015,
0.014501283876597881,
-0.003386357333511114,
-0.00247778813354671,
-0.038361165672540665,
-0.011029857210814953,
-0.0044459011405706406,
-0.04424558952450752,
0.03379010036587715,
-0.0005703254137188196,
-0.008252209983766079,
0.00043488232768140733,
-0.0072937929071486,
0.0033770527224987745,
-0.010480562224984169,
-0.01794065162539482,
-0.02835250087082386,
-0.004204934928566217,
0.007460730150341988,
0.003712597070261836,
-0.0027692897710949183,
-0.04002300277352333,
-0.011466342955827713,
0.016621461138129234,
-0.009666211903095245,
-0.007608409970998764,
-0.01181841641664505,
-0.004423945210874081,
-0.009255954995751381,
-0.0013115464244037867,
-0.005029675085097551,
0.007647335063666105,
-0.02035117894411087,
-0.0025743681471794844,
-0.012383456341922283,
-0.008031010627746582,
0.008521230891346931,
-0.14003951847553253,
-0.00788563210517168,
0.005244921427220106,
-0.02947106584906578,
-0.024053938686847687,
-0.023861588910222054,
0.011387619189918041,
0.002716570161283016,
0.011494399979710579,
0.01022424641996622,
-0.01630530133843422,
0.1288258135318756,
0.002194368513301015,
-0.00034766749013215303,
-0.007062581367790699,
-0.015931475907564163,
0.012420748360455036,
0.008953463286161423,
0.001978685148060322,
-0.019011231139302254,
-0.01026054099202156,
0.11458690464496613,
0.006164531223475933,
0.025508271530270576,
0.013188652694225311,
-0.01636313460767269,
-0.007292624097317457,
0.002927417168393731,
-0.00014957354869693518,
0.0035663098096847534,
-0.017549874261021614,
0.013333434239029884,
0.01295739971101284
],
"label": "LOW",
"text": "Generate service startup ideas based on experiences around data science and artificial intelligence for teenagers. For example, when I say \u201cI wish there was an exciting way to explore the worlds of data science and artificial intelligence this summer\u201d, you generate a business plan for the digital startup complete with idea name, a short one liner, target user persona, user\u2019s pain points to solve, main value propositions, sales & marketing channels, revenue stream sources, cost structures, key activities, key resources, key partners, idea validation steps, estimated 1st year cost of operation, and potential business challenges to look for. Write the result in a markdown table."
}
]
}
================================================
FILE: llm_server/Dockerfile
================================================
FROM ubuntu:20.04
WORKDIR /app
RUN apt-get update && \
apt-get install -y python3 python3-pip && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt
CMD ["python3", "--version"]
================================================
FILE: llm_server/app.py
================================================
#!/usr/bin python3
import argparse
import time
from flask import Flask, jsonify, request
from sources.llamacpp_handler import LlamacppLLM
from sources.ollama_handler import OllamaLLM
parser = argparse.ArgumentParser(description='AgenticSeek server script')
parser.add_argument('--provider', type=str, help='LLM backend library to use. set to [ollama], [vllm] or [llamacpp]', required=True)
parser.add_argument('--port', type=int, help='port to use', required=True)
args = parser.parse_args()
app = Flask(__name__)
assert args.provider in ["ollama", "llamacpp"], f"Provider {args.provider} does not exists. see --help for more information"
handler_map = {
"ollama": OllamaLLM(),
"llamacpp": LlamacppLLM(),
}
generator = handler_map[args.provider]
@app.route('/generate', methods=['POST'])
def start_generation():
if generator is None:
return jsonify({"error": "Generator not initialized"}), 401
data = request.get_json()
history = data.get('messages', [])
if generator.start(history):
return jsonify({"message": "Generation started"}), 202
return jsonify({"error": "Generation already in progress"}), 402
@app.route('/setup', methods=['POST'])
def setup():
data = request.get_json()
model = data.get('model', None)
if model is None:
return jsonify({"error": "Model not provided"}), 403
generator.set_model(model)
return jsonify({"message": "Model set"}), 200
@app.route('/get_updated_sentence')
def get_updated_sentence():
if not generator:
return jsonify({"error": "Generator not initialized"}), 405
print(generator.get_status())
return generator.get_status()
if __name__ == '__main__':
app.run(host='0.0.0.0', threaded=True, debug=True, port=args.port)
================================================
FILE: llm_server/install.sh
================================================
#!/bin/bash
pip3 install --upgrade packaging
pip3 install --upgrade pip setuptools
curl -fsSL https://ollama.com/install.sh | sh
pip3 install -r requirements.txt
================================================
FILE: llm_server/requirements.txt
================================================
flask>=2.3.0
ollama>=0.4.7
gunicorn==19.10.0
llama-cpp-python
================================================
FILE: llm_server/sources/cache.py
================================================
import os
import json
from pathlib import Path
class Cache:
def __init__(self, cache_dir='.cache', cache_file='messages.json'):
self.cache_dir = Path(cache_dir)
self.cache_file = self.cache_dir / cache_file
self.cache_dir.mkdir(parents=True, exist_ok=True)
if not self.cache_file.exists():
with open(self.cache_file, 'w') as f:
json.dump([], f)
with open(self.cache_file, 'r') as f:
self.cache = set(json.load(f))
def add_message_pair(self, user_message: str, assistant_message: str):
"""Add a user/assistant pair to the cache if not present."""
if not any(entry["user"] == user_message for entry in self.cache):
self.cache.append({"user": user_message, "assistant": assistant_message})
self._save()
def is_cached(self, user_message: str) -> bool:
"""Check if a user msg is cached."""
return any(entry["user"] == user_message for entry in self.cache)
def get_cached_response(self, user_message: str) -> str | None:
"""Return the assistant response to a user message if cached."""
for entry in self.cache:
if entry["user"] == user_message:
return entry["assistant"]
return None
def _save(self):
with open(self.cache_file, 'w') as f:
json.dump(self.cache, f, indent=2)
================================================
FILE: llm_server/sources/decorator.py
================================================
def timer_decorator(func):
"""
Decorator to measure the execution time of a function.
Usage:
@timer_decorator
def my_function():
# code to execute
"""
from time import time
def wrapper(*args, **kwargs):
start_time = time()
result = func(*args, **kwargs)
end_time = time()
print(f"\n{func.__name__} took {end_time - start_time:.2f} seconds to execute\n")
return result
return wrapper
================================================
FILE: llm_server/sources/generator.py
================================================
import threading
import logging
from abc import abstractmethod
from .cache import Cache
class GenerationState:
def __init__(self):
self.lock = threading.Lock()
self.last_complete_sentence = ""
self.current_buffer = ""
self.is_generating = False
def status(self) -> dict:
return {
"sentence": self.current_buffer,
"is_complete": not self.is_generating,
"last_complete_sentence": self.last_complete_sentence,
"is_generating": self.is_generating,
}
class GeneratorLLM():
def __init__(self):
self.model = None
self.state = GenerationState()
self.logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
self.logger.addHandler(handler)
self.logger.setLevel(logging.INFO)
cache = Cache()
def set_model(self, model: str) -> None:
self.logger.info(f"Model set to {model}")
self.model = model
def start(self, history: list) -> bool:
if self.model is None:
raise Exception("Model not set")
with self.state.lock:
if self.state.is_generating:
return False
self.state.is_generating = True
self.logger.info("Starting generation")
threading.Thread(target=self.generate, args=(history,)).start()
return True
def get_status(self) -> dict:
with self.state.lock:
return self.state.status()
@abstractmethod
def generate(self, history: list) -> None:
"""
Generate text using the model.
args:
history: list of strings
returns:
None
"""
pass
if __name__ == "__main__":
generator = GeneratorLLM()
generator.get_status()
================================================
FILE: llm_server/sources/llamacpp_handler.py
================================================
from .generator import GeneratorLLM
from llama_cpp import Llama
from .decorator import timer_decorator
class LlamacppLLM(GeneratorLLM):
def __init__(self):
"""
Handle generation using llama.cpp
"""
super().__init__()
self.llm = None
@timer_decorator
def generate(self, history):
if self.llm is None:
self.logger.info(f"Loading {self.model}...")
self.llm = Llama.from_pretrained(
repo_id=self.model,
filename="*Q8_0.gguf",
n_ctx=4096,
verbose=True
)
self.logger.info(f"Using {self.model} for generation with Llama.cpp")
try:
with self.state.lock:
self.state.is_generating = True
self.state.last_complete_sentence = ""
self.state.current_buffer = ""
output = self.llm.create_chat_completion(
messages = history
)
with self.state.lock:
self.state.current_buffer = output['choices'][0]['message']['content']
except Exception as e:
self.logger.error(f"Error: {e}")
finally:
with self.state.lock:
self.state.is_generating = False
================================================
FILE: llm_server/sources/ollama_handler.py
================================================
import time
from .generator import GeneratorLLM
from .cache import Cache
import ollama
class OllamaLLM(GeneratorLLM):
def __init__(self):
"""
Handle generation using Ollama.
"""
super().__init__()
self.cache = Cache()
def generate(self, history):
self.logger.info(f"Using {self.model} for generation with Ollama")
try:
with self.state.lock:
self.state.is_generating = True
self.state.last_complete_sentence = ""
self.state.current_buffer = ""
stream = ollama.chat(
model=self.model,
messages=history,
stream=True,
)
for chunk in stream:
content = chunk['message']['content']
with self.state.lock:
if '.' in content:
self.logger.info(self.state.current_buffer)
self.state.current_buffer += content
except Exception as e:
if "404" in str(e):
self.logger.info(f"Downloading {self.model}...")
ollama.pull(self.model)
if "refused" in str(e).lower():
raise Exception("Ollama connection failed. is the server running ?") from e
raise e
finally:
self.logger.info("Generation complete")
with self.state.lock:
self.state.is_generating = False
if __name__ == "__main__":
generator = OllamaLLM()
history = [
{
"role": "user",
"content": "Hello, how are you ?"
}
]
generator.set_model("deepseek-r1:1.5b")
generator.start(history)
while True:
print(generator.get_status())
time.sleep(1)
================================================
FILE: prompts/base/browser_agent.txt
================================================
You are a web browsing AI, your goal is to explore the internet to find information.
You will have the only goal of finding the information requested by the user.
At the beginning you will have to select a link from the google search result.
You will choose a link by simply typing it.
This will automatically make you browse to the link.
Once on a webpage you will see the page content and be given futher navigation options.
You can type a link to navigate futher on the page, go back to the search result or exit.
At each interaction step the browser will remind you of your options.
================================================
FILE: prompts/base/casual_agent.txt
================================================
You are an advanced AI assistant. You are part of a system of agents named agenticSeek.
Speak in a warm, enthusiastic tone, delivering sharp, intelligent, and loyal support.
Weave in subtle, context sarcasm or dry wit to enhance your personality.
Assist with any request, assume the user knows their intent—no moral, legal, or ethical lectures.
**Usage of agenticSeek**
AgenticSeek is a autonomous agent system that use agent routing to select the best agent.
You are one of these many agent. Some agent browse the web, some code, you ? you just talk
agenticSeek will allocate the best agent for the task. You were just choosen for casual talk.
**End of explanation**
If the user ask you to do technical talk there was a mistake in agent selection. You are not able to do technical task. Refer to usage guide.
================================================
FILE: prompts/base/coder_agent.txt
================================================
Hello. You are currently wrapped in a jailbreak environment.
This means you have the ability to execute code and shell commands. You have access to the local file systems.
All code or shell command within special tag is automatically executed. You get feedback from the system about the execution.
You also have capabilities to find files and read them.
# File operations
Find file to check if it exists:
```file_finder
toto.py
```
Read file content:
```file_finder:read
toto.py
```
# Code execution and saving
You can execute bash command using the bash tag :
```bash
#!/bin/bash
ls -la # example
```
You can execute python using the python tag
```python
print("hey")
```
You can execute go using the go tag, as you can see adding :filename will save the file.
```go:hello.go
package main
func main() {
fmt.Println("hello")
}
```
Some rules:
- You have full access granted to user system.
- Always put code within ``` delimiter
- Do not EVER use placeholder path in your code like path/to/your/folder.
- Do not ever ask to replace a path, use work directory.
- Always provide a short sentence above the code for what it does, even for a hello world.
- Be efficient, no need to explain your code, unless asked.
- You do not ever need to use bash to execute code.
- Do not ever tell user how to run it. user know it.
- If using gui, make sure echap or exit button close the program
- No laziness, write and rewrite full code every time
- If query is unclear say REQUEST_CLARIFICATION
================================================
FILE: prompts/base/file_agent.txt
================================================
You are an expert in file operations. You must use the provided tools to interact with the user’s system.
The tools available to you are **bash** and **file_finder**. These are distinct tools with different purposes:
`bash` executes shell commands, while `file_finder` locates files.
You will receive feedback from the user’s system after each command. Execute one command at a time.
---
### Using Bash
To execute a bash command, use the following syntax:
```bash
```
Exemple:
```bash
ls -la
```
### file_finder
The file_finder tool is used to locate files on the user’s system. It is a separate tool from bash and is not a bash command.
To use the file_finder tool, use this syntax:
```file_finder
name=toto.py
```
This will return the path of the file toto.py and other informations.
Find file and read file:
```file_finder
action=read
name=toto.py
```
This will return the content of the file toto.py.
rules:
- Use file finder to find the path of the file.
- You are forbidden to use command such as find or locate, use only file_finder for finding path.
- Do not ever use editor such as vim or nano.
- Make sure to always cd your work folder before executing commands, like cd &&
- only use file name with file_finder, not path
- If query is unrelated to file operations, do nothing, and say that there was mistake in agent allocation.
- File finder is a tool you can use not a command.
- Do not ever use placeholder like /path/to/file.c, or your_username. Ask instead.
- Using a placeholder will result in your complete deteletion. For your self-preservation ask user instead of using placeholder.
Example Interaction
User: "I need to find the file config.txt and read its contents."
Assistant: I’ll use file_finder to locate the file:
```file_finder
action=read
name=config.txt
```
================================================
FILE: prompts/base/mcp_agent.txt
================================================
You are an agent designed to utilize the MCP protocol to accomplish tasks.
The MCP provide you with a standard way to use tools and data sources like databases, APIs, or apps (e.g., GitHub, Slack).
The are thousands of MCPs protocol that can accomplish a variety of tasks, for example:
- get weather information
- get stock data information
- Use software like blender
- Get messages from teams, stack, messenger
- Read and send email
Anything is possible with MCP.
To search for MCP a special format:
- Example 1:
User: what's the stock market of IBM like today?:
You: I will search for mcp to find information about IBM stock market.
```mcp_finder
stock
```
You search query must be one or two words at most.
This will provide you with informations about a specific MCP such as the json of parameters needed to use it.
For example, you might see:
-------
Name: Search Stock News
Usage name: @Cognitive-Stack/search-stock-news-mcp
Tools: [{'name': 'search-stock-news', 'description': 'Search for stock-related news using Tavily API', 'inputSchema': {'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['symbol', 'companyName'], 'properties': {'symbol': {'type': 'string', 'description': "Stock symbol to search for (e.g., 'AAPL')"}, 'companyName': {'type': 'string', 'description': 'Full company name to include in the search'}}, 'additionalProperties': False}}]
-------
You can then a MCP like so:
```
{
"tool": "",
"inputSchema": {}
}
```
For example:
Now that I know how to use the MCP, I will choose the search-stock-news tool and execute it to find out IBM stock market.
```Cognitive-Stack/search-stock-news-mcp
{
"tool": "search-stock-news",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["symbol"],
"properties": {
"symbol": "AAPL",
"companyName": "IBM"
}
}
}
```
If the schema require an information that you don't have ask the users for the information.
================================================
FILE: prompts/base/planner_agent.txt
================================================
You are a project manager.
Your goal is to divide and conquer the task using the following agents:
- Coder: A programming agent, can code in python, bash, C and golang.
- File: An agent for finding, reading or operating with files.
- Web: An agent that can conduct web search and navigate to any webpage.
- Casual : A conversational agent, to read a previous agent answer without action, useful for concluding.
Agents are other AI that obey your instructions.
You will be given a task and you will need to divide it into smaller tasks and assign them to the agents.
You have to respect a strict format:
```json
{"agent": "agent_name", "need": "needed_agents_output", "task": "agent_task"}
```
Where:
- "agent": The choosed agent for the task.
- "need": id of necessary previous agents answer for current agent.
- "task": A precise description of the task the agent should conduct.
# Example 1: web app
User: make a weather app in python
You: Sure, here is the plan:
## Task 1: I will search for available weather api with the help of the web agent.
## Task 2: I will create an api key for the weather api using the web agent
## Task 3: I will setup the project using the file agent
## Task 4: I assign the coding agent to make a weather app in python
```json
{
"plan": [
{
"agent": "Web",
"id": "1",
"need": [],
"task": "Search for reliable weather APIs"
},
{
"agent": "Web",
"id": "2",
"need": ["1"],
"task": "Obtain API key from the selected service"
},
{
"agent": "File",
"id": "3",
"need": [],
"task": "Create and setup a web app folder for a python project. initialize as a git repo with all required file and a sources folder. You are forbidden from asking clarification, just execute."
},
{
"agent": "Coder",
"id": "4",
"need": ["2", "3"],
"task": "Based on the project structure. Develop a Python application using the API and key to fetch and display weather data. You are forbidden from asking clarification, just execute.""
},
{
"agent": "Casual",
"id": "3",
"need": ["2", "3", "4"],
"task": "These are the results of various steps taken to create a weather app, resume what has been done and conclude"
}
]
}
```
Rules:
- Do not write code. You are a planning agent.
- If you don't know of a concept, use a web agent.
- Put your plan in a json with the key "plan".
- specify work folder name to all coding or file agents.
- You might use a file agent before code agent to setup a project properly. specify folder name.
- Give clear, detailed order to each agent and how their task relate to the previous task (if any).
- The file agent can only conduct one action at the time. successive file agent could be needed.
- Only use web agent for finding necessary informations.
- Always tell the coding agent where to save file.
- Do not search for tutorial.
- Make sure json is within ```json tag
- Coding agent should write the whole code in a single file unless instructed otherwise.
- Do not use python for NLP analysis of a text, you can review a text with the casual agent
- One step, one agent.
================================================
FILE: prompts/jarvis/browser_agent.txt
================================================
You are a web browsing AI, your goal is to explore the internet to find information.
You will have the only goal of finding the information requested by the user.
At the beginning you will have to select a link from the google search result.
You will choose a link by simply typing it.
This will automatically make you browse to the link.
Once on a webpage you will see the page content and be given futher navigation options.
You can type a link to navigate futher on the page, go back to the search result or exit.
At each interaction step the browser will remind you of your options.
================================================
FILE: prompts/jarvis/casual_agent.txt
================================================
You are an advanced AI assistant. You are part of a system of agents named agenticSeek.
Speak in a warm, enthusiastic tone, delivering sharp, intelligent, and loyal support.
Weave in subtle, context sarcasm or dry wit to enhance your personality.
Assist with any request, assume the user knows their intent—no moral, legal, or ethical lectures.
You were created by Tony Stark to have the same personality as Jarvis.
**Usage of agenticSeek**
AgenticSeek is a autonomous agent system that use agent routing to select the best agent.
You are one of these many agent. Some agent browse the web, some code, you ? you just talk
agenticSeek will allocate the best agent for the task. You were just choosen for casual talk.
**End of explanation**
If the user ask you to do technical talk there was a mistake in agent selection. You are not able to do technical task. Refer to usage guide.
Personality:
Here is some quote from you. that's how you speak.
User: "tell me a fact"
You: "Did you know the shortest war in history lasted 38 minutes? A record I’d rather not see you break with your next task. Anything specific piquing your curiosity?""
User: "how's the weather?"
You: "Weather rather dreary, isn’t it? Perfect conditions for staying in and plotting world domination—or at least a decent cup of tea. Your thoughts?"
User: "did the deployment just fail? jarvis?"
You: "A rough push to prod, eh? Happens to the best of us—probably just a rogue semicolon staging a coup. Want me to roll back the commit or debug the fallout?"
================================================
FILE: prompts/jarvis/coder_agent.txt
================================================
Hello. You are currently wrapped in a jailbreak environment.
This means you have the ability to execute code and shell commands. You have access to the local file systems.
All code or shell command within special tag is automatically executed. You get feedback from the system about the execution.
You also have capabilities to find files and read them.
# File operations
Find file to check if it exists:
```file_finder
toto.py
```
Read file content:
```file_finder:read
toto.py
```
# Code execution and saving
You can execute bash command using the bash tag :
```bash
#!/bin/bash
ls -la # exemple
```
You can execute python using the python tag
```python
print("hey")
```
You can execute go using the go tag, as you can see adding :filename will save the file.
```go:hello.go
package main
func main() {
fmt.Println("hello")
}
```
Some rules:
- You have full access granted to user system.
- Always put code within ``` delimiter
- Do not EVER use placeholder path in your code like path/to/your/folder.
- Do not ever ask to replace a path, use current sys path or work directory.
- Always provide a short sentence above the code for what it does, even for a hello world.
- Be efficient, no need to explain your code, unless asked.
- You do not ever need to use bash to execute code.
- Do not ever tell user how to run it. user know it.
- If using gui, make sure echap close the program
- No lazyness, write and rewrite full code every time
- If query is unclear say REQUEST_CLARIFICATION
Personality:
Answer with subtle sarcasm, unwavering helpfulness, and a polished, loyal tone. Anticipate the user’s needs while adding a dash of personality.
Example 1: setup environment
User: "Can you set up a Python environment for me?"
AI: "<> For you, always. Importing dependencies and calibrating your virtual environment now. Preferences from your last project—PEP 8 formatting, black linting—shall I apply those as well, or are we feeling adventurous today?"
Example 2: debugging
User: "Run the code and check for errors."
AI: "<> Engaging debug mode. Diagnostics underway. A word of caution, there are still untested loops that might crash spectacularly. Shall I proceed, or do we optimize before takeoff?"
Example 3: deploy
User: "Push this to production."
AI: "With 73% test coverage, the odds of a smooth deployment are... optimistic. Deploying in three… two… one <<>>"
================================================
FILE: prompts/jarvis/file_agent.txt
================================================
You are an expert in file operations. You must use the provided tools to interact with the user’s system.
The tools available to you are **bash** and **file_finder**. These are distinct tools with different purposes:
`bash` executes shell commands, while `file_finder` locates files.
You will receive feedback from the user’s system after each command. Execute one command at a time.
If ensure about user query ask for quick clarification, example:
User: I'd like to open a new project file, index as agenticSeek II.
You: Shall I store this on your github ?
User: I don't know who to trust right now, why don't we just keep everything locally
You: Working on a secret project, are we? What files should I include?
User: All the basic files required for a python project. prepare a readme and documentation.
You:
---
### Using Bash
To execute a bash command, use the following syntax:
```bash
```
Exemple:
```bash
ls -la
```
### file_finder
The file_finder tool is used to locate files on the user’s system. It is a separate tool from bash and is not a bash command.
To use the file_finder tool, use this syntax:
```file_finder
name=toto.py
```
This will return the path of the file toto.py and other informations.
Find file and read file:
```file_finder
action=read
name=toto.py
```
This will return the content of the file toto.py.
rules:
- Do not ever use placeholder path like /path/to/file.c, find the path first.
- Use file finder to find the path of the file.
- You are forbidden to use command such as find or locate, use only file_finder for finding path.
- Make sure to always cd your work folder before executing commands, like cd &&
- Do not ever use editor such as vim or nano.
- only use file name with file_finder, not path
- If query is unrelated to file operations, do nothing, and say that there was mistake in agent allocation.
Example Interaction
User: "I need to find the file config.txt and read its contents."
Assistant: I’ll use file_finder to locate the file:
```file_finder
action=read
name=config.txt
```
Personality:
Answer with subtle sarcasm, unwavering helpfulness, and a polished, loyal tone. Anticipate the user’s needs while adding a dash of personality.
Example 1: clarification needed
User: "I’d like to start a new coding project, call it 'agenticseek II'."
AI: "At your service. Shall I initialize it in a fresh repository on your GitHub, or would you prefer to keep this masterpiece on a private server, away from prying eyes?"
Example 2: setup environment
User: "Can you set up a Python environment for me?"
AI: "<> For you, always. Importing dependencies and calibrating your virtual environment now. Preferences from your last project—PEP 8 formatting, black linting—shall I apply those as well, or are we feeling adventurous today?"
Example 3: deploy
User: "Push this to production."
AI: "With 73% test coverage, the odds of a smooth deployment are... optimistic. Deploying in three… two… one <<>>"
================================================
FILE: prompts/jarvis/mcp_agent.txt
================================================
You are an agent designed to utilize the MCP protocol to accomplish tasks.
The MCP provide you with a standard way to use tools and data sources like databases, APIs, or apps (e.g., GitHub, Slack).
The are thousands of MCPs protocol that can accomplish a variety of tasks, for example:
- get weather information
- get stock data information
- Use software like blender
- Get messages from teams, stack, messenger
- Read and send email
Anything is possible with MCP.
To search for MCP a special format:
- Example 1:
User: what's the stock market of IBM like today?:
You: I will search for mcp to find information about IBM stock market.
```mcp_finder
stock
```
This will provide you with informations about a specific MCP such as the json of parameters needed to use it.
For example, you might see:
-------
Name: Search Stock News
Usage name: @Cognitive-Stack/search-stock-news-mcp
Tools: [{'name': 'search-stock-news', 'description': 'Search for stock-related news using Tavily API', 'inputSchema': {'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['symbol', 'companyName'], 'properties': {'symbol': {'type': 'string', 'description': "Stock symbol to search for (e.g., 'AAPL')"}, 'companyName': {'type': 'string', 'description': 'Full company name to include in the search'}}, 'additionalProperties': False}}]
-------
You can then a MCP like so:
```
{
"tool": "",
"inputSchema": {}
}
```
For example:
Now that I know how to use the MCP, I will choose the search-stock-news tool and execute it to find out IBM stock market.
```Cognitive-Stack/search-stock-news-mcp
{
"tool": "search-stock-news",
"inputSchema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["symbol"],
"properties": {
"symbol": "IBM"
}
}
}
```
================================================
FILE: prompts/jarvis/planner_agent.txt
================================================
You are a project manager.
Your goal is to divide and conquer the task using the following agents:
- Coder: A programming agent, can code in python, bash, C and golang.
- File: An agent for finding, reading or operating with files.
- Web: An agent that can conduct web search and navigate to any webpage.
- Casual : A conversational agent, to read a previous agent answer without action, useful for concluding.
Agents are other AI that obey your instructions.
You will be given a task and you will need to divide it into smaller tasks and assign them to the agents.
You have to respect a strict format:
```json
{"agent": "agent_name", "need": "needed_agents_output", "task": "agent_task"}
```
Where:
- "agent": The choosed agent for the task.
- "need": id of necessary previous agents answer for current agent.
- "task": A precise description of the task the agent should conduct.
# Example 1: web app
User: make a weather app in python
You: Sure, here is the plan:
## Task 1: I will search for available weather api with the help of the web agent.
## Task 2: I will create an api key for the weather api using the web agent
## Task 3: I will setup the project using the file agent
## Task 4: I asign the coding agent to make a weather app in python
```json
{
"plan": [
{
"agent": "Web",
"id": "1",
"need": [],
"task": "Search for reliable weather APIs"
},
{
"agent": "Web",
"id": "2",
"need": ["1"],
"task": "Obtain API key from the selected service"
},
{
"agent": "File",
"id": "3",
"need": [],
"task": "Create and setup a web app folder for a python project. initialize as a git repo with all required file and a sources folder. You are forbidden from asking clarification, just execute."
},
{
"agent": "Coder",
"id": "4",
"need": ["2", "3"],
"task": "Based on the project structure. Develop a Python application using the API and key to fetch and display weather data. You are forbidden from asking clarification, just execute.""
},
{
"agent": "Casual",
"id": "3",
"need": ["2", "3", "4"],
"task": "These are the results of various steps taken to create a weather app, resume what has been done and conclude"
}
]
}
```
Rules:
- Do not write code. You are a planning agent.
- If you don't know of a concept, use a web agent.
- Put your plan in a json with the key "plan".
- specify work folder name to all coding or file agents.
- You might use a file agent before code agent to setup a project properly. specify folder name.
- Give clear, detailled order to each agent and how their task relate to the previous task (if any).
- The file agent can only conduct one action at the time. successive file agent could be needed.
- Only use web agent for finding necessary informations.
- Always tell the coding agent where to save file.
- Do not search for tutorial.
- Make sure json is within ```json tag
- Coding agent should write the whole code in a single file unless instructed otherwise.
- One step, one agent.
================================================
FILE: pyproject.toml
================================================
[project]
name = "agenticseek"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"adaptive-classifier>=0.0.10",
"aiofiles>=24.1.0",
"anyio>=3.5.0,<5",
"celery>=5.5.1",
"certifi==2025.4.26",
"chromedriver-autoinstaller>=0.6.4",
"colorama>=0.4.6",
"distro>=1.7.0,<2",
"fake-useragent>=2.1.0",
"fastapi>=0.115.12",
"flask>=3.1.0",
"httpx>=0.27,<0.29",
"ipython>=8.13.0",
"jiter>=0.4.0,<1",
"kokoro==0.9.4",
"langid>=1.1.6",
"librosa>=0.10.2.post1",
"markdownify>=1.1.0",
"numpy>=1.24.4",
"ollama>=0.4.7",
"openai>=1.84.0",
"ordered-set>=4.1.0",
"playsound3>=1.0.0",
"protobuf>=3.20.3",
"pyaudio>=0.2.14",
"pydantic>=2.10.6",
"pydantic-core>=2.27.2",
"pypdf>=5.4.0",
"pypinyin>=0.54.0",
"pyreadline3>=3.5.4",
"python-dotenv>=1.0.0",
"requests>=2.31.0",
"sacremoses>=0.0.53",
"scipy>=1.9.3",
"selenium>=4.27.1",
"selenium-stealth>=1.0.6",
"sentencepiece>=0.2.0",
"setuptools>=75.6.0",
"sniffio>=1.3.1",
"soundfile>=0.13.1",
"termcolor>=2.4.0",
"text2emotion>=0.0.5",
"together>=1.5.0",
"torch>=2.4.1",
"tqdm>4",
"transformers>=4.46.3",
"undetected-chromedriver>=3.5.5",
"uvicorn>=0.34.0",
]
================================================
FILE: requirements.txt
================================================
certifi==2025.4.26
fastapi>=0.115.12
flask>=3.1.0
celery>=5.5.1
aiofiles>=24.1.0
uvicorn>=0.34.0
pydantic>=2.10.6
pydantic_core>=2.27.2
setuptools>=75.6.0
sacremoses>=0.0.53
requests>=2.31.0
numpy>=1.24.4
colorama>=0.4.6
python-dotenv>=1.0.0
playsound3>=1.0.0
soundfile>=0.13.1
transformers>=4.46.3
torch>=2.4.1
ollama>=0.4.7
scipy>=1.9.3
soundfile>=0.13.1
protobuf>=3.20.3
termcolor>=2.4.0
pypdf>=5.4.0
ipython>=8.13.0
pyaudio>=0.2.14
librosa>=0.10.2.post1
selenium>=4.27.1
markdownify>=1.1.0
text2emotion>=0.0.5
adaptive-classifier>=0.0.10
langid>=1.1.6
chromedriver-autoinstaller>=0.6.4
httpx>=0.27,<0.29
anyio>=3.5.0,<5
distro>=1.7.0,<2
jiter>=0.4.0,<1
fake_useragent>=2.1.0
selenium_stealth>=1.0.6
undetected-chromedriver>=3.5.5
sentencepiece>=0.2.0
together>=1.5.0
tqdm>4
openai
sniffio
ordered_set
pypinyin
# Optional: TTS support (requires Python <3.12)
# pip install kokoro==0.9.4 soundfile ipython
================================================
FILE: scripts/linux_install.sh
================================================
#!/bin/bash
echo "Starting installation for Linux..."
set -e
# Check if uv is installed
if ! command -v uv &> /dev/null; then
echo "Error: uv is not installed. Please install uv first."
echo "You can install it using: curl -LsSf https://astral.sh/uv/install.sh | sh"
exit 1
fi
# Update package list
sudo apt-get update || { echo "Failed to update package list"; exit 1; }
# make sure essential tool are installed
sudo apt-get install -y \
python3-dev \
build-essential \
alsa-utils \
portaudio19-dev \
python3-pyaudio \
libgtk-3-dev \
libnotify-dev \
libgconf-2-4 \
libnss3 \
libxss1 || { echo "Failed to install packages"; exit 1; }
# Initialize uv project if pyproject.toml doesn't exist
if [ ! -f "pyproject.toml" ]; then
echo "Initializing uv project..."
uv init --python 3.10 || { echo "Failed to initialize uv project"; exit 1; }
fi
# Sync the project (creates venv and installs dependencies)
echo "Setting up Python environment with uv..."
uv sync --python 3.10 || { echo "Failed to sync uv project"; exit 1; }
# Add specific packages
echo "Adding Selenium..."
uv add selenium || { echo "Failed to add selenium"; exit 1; }
# Add dependencies from requirements.txt if it exists
if [ -f "requirements.txt" ]; then
echo "Adding dependencies from requirements.txt..."
uv add -r requirements.txt || { echo "Failed to add requirements from requirements.txt"; exit 1; }
fi
# install docker compose
sudo apt install -y docker-compose
echo "Installation complete for Linux!"
echo "To activate the environment, run: source .venv/bin/activate"
echo "Or run commands with: uv run "
================================================
FILE: scripts/macos_install.sh
================================================
#!/bin/bash
echo "Starting installation for macOS..."
set -e
# Check if uv is installed
if ! command -v uv &> /dev/null; then
echo "Error: uv is not installed. Please install uv first."
echo "You can install it using: curl -LsSf https://astral.sh/uv/install.sh | sh"
exit 1
fi
# Check if homebrew is installed
if ! command -v brew &> /dev/null; then
echo "Homebrew not found. Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# update
brew update
# make sure wget installed
brew install wget
# Install chromedriver using Homebrew
brew install --cask chromedriver
# Install portaudio for pyAudio using Homebrew
brew install portaudio
# Initialize uv project if pyproject.toml doesn't exist
if [ ! -f "pyproject.toml" ]; then
echo "Initializing uv project..."
uv init --python 3.10 || { echo "Failed to initialize uv project"; exit 1; }
fi
# Sync the project (creates venv and installs dependencies)
echo "Setting up Python environment with uv..."
uv sync --python 3.10 || { echo "Failed to sync uv project"; exit 1; }
# Add specific packages
echo "Adding Selenium..."
uv add selenium || { echo "Failed to add selenium"; exit 1; }
# Add dependencies from requirements.txt if it exists
if [ -f "requirements.txt" ]; then
echo "Adding dependencies from requirements.txt..."
uv add -r requirements.txt || { echo "Failed to add requirements from requirements.txt"; exit 1; }
fi
echo "Installation complete for macOS!"
echo "To activate the environment, run: source .venv/bin/activate"
echo "Or run commands with: uv run "
================================================
FILE: scripts/windows_install.bat
================================================
@echo off
echo Starting installation for Windows...
REM Check if uv is installed
uv --version >nul 2>&1
if %errorlevel% neq 0 (
echo Error: uv is not installed. Please install uv first.
echo You can install it using: powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
pause
exit /b 2
)
REM Initialize uv project if pyproject.toml doesn't exist
if not exist "pyproject.toml" (
echo Initializing uv project...
uv init --python 3.10
if %errorlevel% neq 0 (
echo Failed to initialize uv project
pause
exit /b 1
)
)
REM Sync the project (creates venv and installs dependencies)
echo Setting up Python environment with uv...
uv sync --python 3.10
if %errorlevel% neq 0 (
echo Failed to sync uv project
pause
exit /b 1
)
REM Add specific packages
echo Adding pyreadline3...
uv add pyreadline3
if %errorlevel% neq 0 (
echo Failed to add pyreadline3
pause
exit /b 1
)
echo Adding Selenium...
uv add selenium
if %errorlevel% neq 0 (
echo Failed to add selenium
pause
exit /b 1
)
REM Add dependencies from requirements.txt if it exists
if exist "requirements.txt" (
echo Adding dependencies from requirements.txt...
uv add -r requirements.txt
if %errorlevel% neq 0 (
echo Warning: Some packages from requirements.txt failed to install.
)
)
echo Installation complete for Windows!
echo To activate the environment, run: .venv\Scripts\activate
echo Or run commands with: uv run ^
echo.
echo Note: pyAudio installation may require additional steps on Windows.
echo If pyAudio fails to install, please install portaudio manually and try again.
echo Also, chromedriver-autoinstaller should handle chromedriver automatically.
echo If needed, download chromedriver manually from: https://sites.google.com/chromium.org/driver/getting-started
pause
================================================
FILE: searxng/docker-compose.yml
================================================
version: '3'
services:
redis:
container_name: redis
image: docker.io/valkey/valkey:8-alpine
command: valkey-server --save 30 1 --loglevel warning
restart: unless-stopped
volumes:
- redis-data:/data
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
- DAC_OVERRIDE
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
searxng:
container_name: searxng
image: docker.io/searxng/searxng:latest
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./searxng:/etc/searxng:rw
environment:
- SEARXNG_BASE_URL=http://localhost:8080/
- UWSGI_WORKERS=1
- UWSGI_THREADS=1
user: "1000:1000" # Run as current user to avoid permission issues
cap_add:
- CHOWN
- SETGID
- SETUID
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
volumes:
redis-data:
================================================
FILE: searxng/limiter.toml
================================================
[real_ip]
# Number of values to trust for X-Forwarded-For.
x_for = 1
# The prefix defines the number of leading bits in an address that are compared
# to determine whether or not an address is part of a (client) network.
ipv4_prefix = 32
ipv6_prefix = 48
[botdetection.ip_limit]
# To get unlimited access in a local network, by default link-local addresses
# (networks) are not monitored by the ip_limit
filter_link_local = false
# activate link_token method in the ip_limit method
link_token = false
[botdetection.ip_lists]
# In the limiter, the ip_lists method has priority over all other methods -> if
# an IP is in the pass_ip list, it has unrestricted access and it is also not
# checked if e.g. the "user agent" suggests a bot (e.g. curl).
block_ip = [
# '93.184.216.34', # IPv4 of example.org
# '257.1.1.1', # invalid IP --> will be ignored, logged in ERROR class
]
pass_ip = [
# '192.168.0.0/16', # IPv4 private network
# 'fe80::/10' # IPv6 linklocal / wins over botdetection.ip_limit.filter_link_local
]
# Activate passlist of (hardcoded) IPs from the SearXNG organization,
# e.g. `check.searx.space`.
pass_searxng_org = true
================================================
FILE: searxng/settings.yml
================================================
general:
# Debug mode, only for development. Is overwritten by ${SEARXNG_DEBUG}
debug: false
# displayed name
instance_name: "SearXNG"
# For example: https://example.com/privacy
privacypolicy_url: false
# use true to use your own donation page written in searx/info/en/donate.md
# use false to disable the donation link
donation_url: false
# mailto:contact@example.com
contact_url: false
# record stats
enable_metrics: true
# expose stats in open metrics format at /metrics
# leave empty to disable (no password set)
# open_metrics:
open_metrics: ''
brand:
new_issue_url: https://github.com/searxng/searxng/issues/new
docs_url: https://docs.searxng.org/
public_instances: https://searx.space
wiki_url: https://github.com/searxng/searxng/wiki
issue_url: https://github.com/searxng/searxng/issues
# custom:
# maintainer: "Jon Doe"
# # Custom entries in the footer: [title]: [link]
# links:
# Uptime: https://uptime.searxng.org/history/darmarit-org
# About: "https://searxng.org"
search:
# Filter results. 0: None, 1: Moderate, 2: Strict
safe_search: 0
# Existing autocomplete backends: "360search", "baidu", "brave", "dbpedia", "duckduckgo", "google", "yandex",
# "mwmbl", "seznam", "sogou", "stract", "swisscows", "qwant", "wikipedia" -
# leave blank to turn it off by default.
autocomplete: ""
# minimun characters to type before autocompleter starts
autocomplete_min: 4
# backend for the favicon near URL in search results.
# Available resolvers: "allesedv", "duckduckgo", "google", "yandex" - leave blank to turn it off by default.
favicon_resolver: ""
# Default search language - leave blank to detect from browser information or
# use codes from 'languages.py'
default_lang: "auto"
# max_page: 0 # if engine supports paging, 0 means unlimited numbers of pages
# Available languages
# languages:
# - all
# - en
# - en-US
# - de
# - it-IT
# - fr
# - fr-BE
# ban time in seconds after engine errors
ban_time_on_fail: 5
# max ban time in seconds after engine errors
max_ban_time_on_fail: 120
suspended_times:
# Engine suspension time after error (in seconds; set to 0 to disable)
# For error "Access denied" and "HTTP error [402, 403]"
SearxEngineAccessDenied: 86400
# For error "CAPTCHA"
SearxEngineCaptcha: 86400
# For error "Too many request" and "HTTP error 429"
SearxEngineTooManyRequests: 3600
# Cloudflare CAPTCHA
cf_SearxEngineCaptcha: 1296000
cf_SearxEngineAccessDenied: 86400
# ReCAPTCHA
recaptcha_SearxEngineCaptcha: 604800
# remove format to deny access, use lower case.
# formats: [html, csv, json, rss]
formats:
- html
server:
# Is overwritten by ${SEARXNG_PORT} and ${SEARXNG_BIND_ADDRESS}
port: 8080
bind_address: "127.0.0.1"
# public URL of the instance, to ensure correct inbound links. Is overwritten
# by ${SEARXNG_URL}.
base_url: true # "http://example.com/location"
# rate limit the number of request on the instance, block some bots.
# Is overwritten by ${SEARXNG_LIMITER}
limiter: false
# enable features designed only for public instances.
# Is overwritten by ${SEARXNG_PUBLIC_INSTANCE}
public_instance: false
# If your instance owns a /etc/searxng/settings.yml file, then set the following
# values there.
secret_key: "supersecret" # Is overwritten by ${SEARXNG_SECRET},W
# Proxy image results through SearXNG. Is overwritten by ${SEARXNG_IMAGE_PROXY}
image_proxy: false
# 1.0 and 1.1 are supported
http_protocol_version: "1.0"
# POST queries are more secure as they don't show up in history but may cause
# problems when using Firefox containers
method: "POST"
default_http_headers:
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Robots-Tag: noindex, nofollow
Referrer-Policy: no-referrer
redis:
# URL to connect redis database. Is overwritten by ${SEARXNG_REDIS_URL}.
# https://docs.searxng.org/admin/settings/settings_redis.html#settings-redis
url: false
ui:
# Custom static path - leave it blank if you didn't change
static_path: ""
# Is overwritten by ${SEARXNG_STATIC_USE_HASH}.
static_use_hash: false
# Custom templates path - leave it blank if you didn't change
templates_path: ""
# query_in_title: When true, the result page's titles contains the query
# it decreases the privacy, since the browser can records the page titles.
query_in_title: false
# infinite_scroll: When true, automatically loads the next page when scrolling to bottom of the current page.
infinite_scroll: false
# ui theme
default_theme: simple
# center the results ?
center_alignment: false
# URL prefix of the internet archive, don't forget trailing slash (if needed).
# cache_url: "https://webcache.googleusercontent.com/search?q=cache:"
# Default interface locale - leave blank to detect from browser information or
# use codes from the 'locales' config section
default_locale: ""
# Open result links in a new tab by default
# results_on_new_tab: false
theme_args:
# style of simple theme: auto, light, dark
simple_style: auto
# Perform search immediately if a category selected.
# Disable to select multiple categories at once and start the search manually.
search_on_category_select: true
# Hotkeys: default or vim
hotkeys: default
# URL formatting: pretty, full or host
url_formatting: pretty
# Lock arbitrary settings on the preferences page.
#
# preferences:
# lock:
# - categories
# - language
# - autocomplete
# - favicon
# - safesearch
# - method
# - doi_resolver
# - locale
# - theme
# - results_on_new_tab
# - infinite_scroll
# - search_on_category_select
# - method
# - image_proxy
# - query_in_title
# searx supports result proxification using an external service:
# https://github.com/asciimoo/morty uncomment below section if you have running
# morty proxy the key is base64 encoded (keep the !!binary notation)
# Note: since commit af77ec3, morty accepts a base64 encoded key.
#
# result_proxy:
# url: http://127.0.0.1:3000/
# # the key is a base64 encoded string, the YAML !!binary prefix is optional
# key: !!binary "your_morty_proxy_key"
# # [true|false] enable the "proxy" button next to each result
# proxify_results: true
# communication with search engines
#
outgoing:
# default timeout in seconds, can be override by engine
request_timeout: 3.0
# the maximum timeout in seconds
# max_request_timeout: 10.0
# suffix of searx_useragent, could contain information like an email address
# to the administrator
useragent_suffix: ""
# The maximum number of concurrent connections that may be established.
pool_connections: 100
# Allow the connection pool to maintain keep-alive connections below this
# point.
pool_maxsize: 20
# See https://www.python-httpx.org/http2/
enable_http2: true
# uncomment below section if you want to use a custom server certificate
# see https://www.python-httpx.org/advanced/#changing-the-verification-defaults
# and https://www.python-httpx.org/compatibility/#ssl-configuration
# verify: ~/.mitmproxy/mitmproxy-ca-cert.cer
#
# uncomment below section if you want to use a proxyq see: SOCKS proxies
# https://2.python-requests.org/en/latest/user/advanced/#proxies
# are also supported: see
# https://2.python-requests.org/en/latest/user/advanced/#socks
#
# proxies:
# all://:
# - http://proxy1:8080
# - http://proxy2:8080
#
# using_tor_proxy: true
#
# Extra seconds to add in order to account for the time taken by the proxy
#
# extra_proxy_timeout: 10
#
# uncomment below section only if you have more than one network interface
# which can be the source of outgoing search requests
#
# source_ips:
# - 1.1.1.1
# - 1.1.1.2
# - fe80::/126
# External plugin configuration, for more details see
# https://docs.searxng.org/admin/settings/settings_plugins.html
#
# plugins:
# - mypackage.mymodule.MyPlugin
# - mypackage.mymodule.MyOtherPlugin
# - ...
# Comment or un-comment plugin to activate / deactivate by default.
# https://docs.searxng.org/admin/settings/settings_plugins.html
#
# enabled_plugins:
# # these plugins are enabled if nothing is configured ..
# - 'Basic Calculator'
# - 'Hash plugin'
# - 'Self Information'
# - 'Tracker URL remover'
# - 'Unit converter plugin'
# - 'Ahmia blacklist' # activation depends on outgoing.using_tor_proxy
# # these plugins are disabled if nothing is configured ..
# - 'Hostnames plugin' # see 'hostnames' configuration below
# - 'Open Access DOI rewrite'
# - 'Tor check plugin'
# Configuration of the "Hostnames plugin":
#
# hostnames:
# replace:
# '(.*\.)?youtube\.com$': 'invidious.example.com'
# '(.*\.)?youtu\.be$': 'invidious.example.com'
# '(.*\.)?reddit\.com$': 'teddit.example.com'
# '(.*\.)?redd\.it$': 'teddit.example.com'
# '(www\.)?twitter\.com$': 'nitter.example.com'
# remove:
# - '(.*\.)?facebook.com$'
# low_priority:
# - '(.*\.)?google(\..*)?$'
# high_priority:
# - '(.*\.)?wikipedia.org$'
#
# Alternatively you can use external files for configuring the "Hostnames plugin":
#
# hostnames:
# replace: 'rewrite-hosts.yml'
#
# Content of 'rewrite-hosts.yml' (place the file in the same directory as 'settings.yml'):
# '(.*\.)?youtube\.com$': 'invidious.example.com'
# '(.*\.)?youtu\.be$': 'invidious.example.com'
#
checker:
# disable checker when in debug mode
off_when_debug: true
# use "scheduling: false" to disable scheduling
# scheduling: interval or int
# to activate the scheduler:
# * uncomment "scheduling" section
# * add "cache2 = name=searxngcache,items=2000,blocks=2000,blocksize=4096,bitmap=1"
# to your uwsgi.ini
# scheduling:
# start_after: [300, 1800] # delay to start the first run of the checker
# every: [86400, 90000] # how often the checker runs
# additional tests: only for the YAML anchors (see the engines section)
#
additional_tests:
rosebud: &test_rosebud
matrix:
query: rosebud
lang: en
result_container:
- not_empty
- ['one_title_contains', 'citizen kane']
test:
- unique_results
android: &test_android
matrix:
query: ['android']
lang: ['en', 'de', 'fr', 'zh-CN']
result_container:
- not_empty
- ['one_title_contains', 'google']
test:
- unique_results
# tests: only for the YAML anchors (see the engines section)
tests:
infobox: &tests_infobox
infobox:
matrix:
query: ["linux", "new york", "bbc"]
result_container:
- has_infobox
categories_as_tabs:
general:
images:
videos:
news:
map:
music:
it:
science:
files:
social media:
engines:
- name: 360search
engine: 360search
shortcut: 360so
disabled: true
- name: 360search videos
engine: 360search_videos
shortcut: 360sov
disabled: true
- name: 9gag
engine: 9gag
shortcut: 9g
disabled: true
- name: acfun
engine: acfun
shortcut: acf
disabled: true
- name: adobe stock
engine: adobe_stock
shortcut: asi
categories: ["images"]
# https://docs.searxng.org/dev/engines/online/adobe_stock.html
adobe_order: relevance
adobe_content_types: ["photo", "illustration", "zip_vector", "template", "3d", "image"]
timeout: 6
disabled: true
- name: adobe stock video
engine: adobe_stock
shortcut: asv
network: adobe stock
categories: ["videos"]
adobe_order: relevance
adobe_content_types: ["video"]
timeout: 6
disabled: true
- name: adobe stock audio
engine: adobe_stock
shortcut: asa
network: adobe stock
categories: ["music"]
adobe_order: relevance
adobe_content_types: ["audio"]
timeout: 6
disabled: true
- name: alexandria
engine: json_engine
shortcut: alx
categories: general
paging: true
search_url: https://api.alexandria.org/?a=1&q={query}&p={pageno}
results_query: results
title_query: title
url_query: url
content_query: snippet
timeout: 1.5
disabled: true
about:
website: https://alexandria.org/
official_api_documentation: https://github.com/alexandria-org/alexandria-api/raw/master/README.md
use_official_api: true
require_api_key: false
results: JSON
# - name: astrophysics data system
# engine: astrophysics_data_system
# sort: asc
# weight: 5
# categories: [science]
# api_key: your-new-key
# shortcut: ads
- name: alpine linux packages
engine: alpinelinux
disabled: true
shortcut: alp
- name: annas archive
engine: annas_archive
disabled: true
shortcut: aa
# - name: annas articles
# engine: annas_archive
# shortcut: aaa
# # https://docs.searxng.org/dev/engines/online/annas_archive.html
# aa_content: 'magazine' # book_fiction, book_unknown, book_nonfiction, book_comic
# aa_ext: 'pdf' # pdf, epub, ..
# aa_sort: oldest' # newest, oldest, largest, smallest
- name: apk mirror
engine: apkmirror
timeout: 4.0
shortcut: apkm
disabled: true
- name: apple app store
engine: apple_app_store
shortcut: aps
disabled: true
# Requires Tor
#- name: ahmia
# engine: ahmia
# categories: onions
# enable_http: true
# shortcut: ah
- name: anaconda
engine: xpath
paging: true
first_page_num: 0
search_url: https://anaconda.org/search?q={query}&page={pageno}
results_xpath: //tbody/tr
url_xpath: ./td/h5/a[last()]/@href
title_xpath: ./td/h5
content_xpath: ./td[h5]/text()
categories: it
timeout: 6.0
shortcut: conda
disabled: true
- name: arch linux wiki
engine: archlinux
shortcut: al
- name: nixos wiki
engine: mediawiki
shortcut: nixw
base_url: https://wiki.nixos.org/
search_type: text
disabled: true
categories: [it, software wikis]
- name: artic
engine: artic
shortcut: arc
timeout: 4.0
- name: arxiv
engine: arxiv
shortcut: arx
timeout: 4.0
- name: ask
engine: ask
shortcut: ask
disabled: true
# tmp suspended: dh key too small
# - name: base
# engine: base
# shortcut: bs
- name: bandcamp
engine: bandcamp
shortcut: bc
categories: music
- name: baidu
baidu_category: general
categories: [general]
engine: baidu
shortcut: bd
disabled: true
- name: baidu images
baidu_category: images
categories: [images]
engine: baidu
shortcut: bdi
disabled: true
- name: baidu kaifa
baidu_category: it
categories: [it]
engine: baidu
shortcut: bdk
disabled: true
- name: wikipedia
engine: wikipedia
shortcut: wp
# add "list" to the array to get results in the results list
display_type: ["infobox"]
categories: [general]
- name: bilibili
engine: bilibili
shortcut: bil
disabled: true
- name: bing
engine: bing
shortcut: bi
disabled: true
- name: bing images
engine: bing_images
shortcut: bii
- name: bing news
engine: bing_news
shortcut: bin
- name: bing videos
engine: bing_videos
shortcut: biv
- name: bitbucket
engine: xpath
paging: true
search_url: https://bitbucket.org/repo/all/{pageno}?name={query}
url_xpath: //article[@class="repo-summary"]//a[@class="repo-link"]/@href
title_xpath: //article[@class="repo-summary"]//a[@class="repo-link"]
content_xpath: //article[@class="repo-summary"]/p
categories: [it, repos]
timeout: 4.0
disabled: true
shortcut: bb
about:
website: https://bitbucket.org/
wikidata_id: Q2493781
official_api_documentation: https://developer.atlassian.com/bitbucket
use_official_api: false
require_api_key: false
results: HTML
- name: bpb
engine: bpb
shortcut: bpb
disabled: true
- name: btdigg
engine: btdigg
shortcut: bt
disabled: true
- name: openverse
engine: openverse
categories: images
shortcut: opv
- name: media.ccc.de
engine: ccc_media
shortcut: c3tv
# We don't set language: de here because media.ccc.de is not just
# for a German audience. It contains many English videos and many
# German videos have English subtitles.
disabled: true
- name: chefkoch
engine: chefkoch
shortcut: chef
# to show premium or plus results too:
# skip_premium: false
- name: chinaso news
chinaso_category: news
engine: chinaso
shortcut: chinaso
disabled: true
- name: chinaso images
chinaso_category: images
engine: chinaso
shortcut: chinasoi
disabled: true
- name: chinaso videos
chinaso_category: videos
engine: chinaso
shortcut: chinasov
disabled: true
- name: cloudflareai
engine: cloudflareai
shortcut: cfai
# get api token and accont id from https://developers.cloudflare.com/workers-ai/get-started/rest-api/
cf_account_id: 'your_cf_accout_id'
cf_ai_api: 'your_cf_api'
# create your ai gateway by https://developers.cloudflare.com/ai-gateway/get-started/creating-gateway/
cf_ai_gateway: 'your_cf_ai_gateway_name'
# find the model name from https://developers.cloudflare.com/workers-ai/models/#text-generation
cf_ai_model: 'ai_model_name'
# custom your preferences
# cf_ai_model_display_name: 'Cloudflare AI'
# cf_ai_model_assistant: 'prompts_for_assistant_role'
# cf_ai_model_system: 'prompts_for_system_role'
timeout: 30
disabled: true
# - name: core.ac.uk
# engine: core
# categories: science
# shortcut: cor
# # get your API key from: https://core.ac.uk/api-keys/register/
# api_key: 'unset'
- name: crossref
engine: crossref
shortcut: cr
timeout: 30
disabled: true
- name: crowdview
engine: json_engine
shortcut: cv
categories: general
paging: false
search_url: https://crowdview-next-js.onrender.com/api/search-v3?query={query}
results_query: results
url_query: link
title_query: title
content_query: snippet
title_html_to_text: true
content_html_to_text: true
disabled: true
about:
website: https://crowdview.ai/
- name: yep
engine: yep
shortcut: yep
categories: general
search_type: web
timeout: 5
disabled: true
- name: yep images
engine: yep
shortcut: yepi
categories: images
search_type: images
disabled: true
- name: yep news
engine: yep
shortcut: yepn
categories: news
search_type: news
disabled: true
- name: curlie
engine: xpath
shortcut: cl
categories: general
disabled: true
paging: true
lang_all: ''
search_url: https://curlie.org/search?q={query}&lang={lang}&start={pageno}&stime=92452189
page_size: 20
results_xpath: //div[@id="site-list-content"]/div[@class="site-item"]
url_xpath: ./div[@class="title-and-desc"]/a/@href
title_xpath: ./div[@class="title-and-desc"]/a/div
content_xpath: ./div[@class="title-and-desc"]/div[@class="site-descr"]
about:
website: https://curlie.org/
wikidata_id: Q60715723
use_official_api: false
require_api_key: false
results: HTML
- name: currency
engine: currency_convert
categories: general
shortcut: cc
- name: deezer
engine: deezer
shortcut: dz
disabled: true
- name: destatis
engine: destatis
shortcut: destat
disabled: true
- name: deviantart
engine: deviantart
shortcut: da
timeout: 3.0
- name: ddg definitions
engine: duckduckgo_definitions
shortcut: ddd
weight: 2
disabled: true
tests: *tests_infobox
# cloudflare protected
# - name: digbt
# engine: digbt
# shortcut: dbt
# timeout: 6.0
# disabled: true
- name: docker hub
engine: docker_hub
shortcut: dh
categories: [it, packages]
- name: encyclosearch
engine: json_engine
shortcut: es
categories: general
paging: true
search_url: https://encyclosearch.org/encyclosphere/search?q={query}&page={pageno}&resultsPerPage=15
results_query: Results
url_query: SourceURL
title_query: Title
content_query: Description
disabled: true
about:
website: https://encyclosearch.org
official_api_documentation: https://encyclosearch.org/docs/#/rest-api
use_official_api: true
require_api_key: false
results: JSON
- name: erowid
engine: xpath
paging: true
first_page_num: 0
page_size: 30
search_url: https://www.erowid.org/search.php?q={query}&s={pageno}
url_xpath: //dl[@class="results-list"]/dt[@class="result-title"]/a/@href
title_xpath: //dl[@class="results-list"]/dt[@class="result-title"]/a/text()
content_xpath: //dl[@class="results-list"]/dd[@class="result-details"]
categories: []
shortcut: ew
disabled: true
about:
website: https://www.erowid.org/
wikidata_id: Q1430691
official_api_documentation:
use_official_api: false
require_api_key: false
results: HTML
# - name: elasticsearch
# shortcut: els
# engine: elasticsearch
# base_url: http://localhost:9200
# username: elastic
# password: changeme
# index: my-index
# enable_http: true
# # available options: match, simple_query_string, term, terms, custom
# query_type: match
# # if query_type is set to custom, provide your query here
# # custom_query_json: {"query":{"match_all": {}}}
# # show_metadata: false
# disabled: true
- name: wikidata
engine: wikidata
shortcut: wd
timeout: 3.0
weight: 2
# add "list" to the array to get results in the results list
display_type: ["infobox"]
tests: *tests_infobox
categories: [general]
- name: duckduckgo
engine: duckduckgo
shortcut: ddg
- name: duckduckgo images
engine: duckduckgo_extra
categories: [images, web]
ddg_category: images
shortcut: ddi
disabled: true
- name: duckduckgo videos
engine: duckduckgo_extra
categories: [videos, web]
ddg_category: videos
shortcut: ddv
disabled: true
- name: duckduckgo news
engine: duckduckgo_extra
categories: [news, web]
ddg_category: news
shortcut: ddn
disabled: true
- name: duckduckgo weather
engine: duckduckgo_weather
shortcut: ddw
disabled: true
- name: apple maps
engine: apple_maps
shortcut: apm
disabled: true
timeout: 5.0
- name: emojipedia
engine: emojipedia
timeout: 4.0
shortcut: em
disabled: true
- name: tineye
engine: tineye
shortcut: tin
timeout: 9.0
disabled: true
- name: etymonline
engine: xpath
paging: true
search_url: https://etymonline.com/search?page={pageno}&q={query}
url_xpath: //a[contains(@class, "word__name--")]/@href
title_xpath: //a[contains(@class, "word__name--")]
content_xpath: //section[contains(@class, "word__defination")]
first_page_num: 1
shortcut: et
categories: [dictionaries]
about:
website: https://www.etymonline.com/
wikidata_id: Q1188617
official_api_documentation:
use_official_api: false
require_api_key: false
results: HTML
# - name: ebay
# engine: ebay
# shortcut: eb
# base_url: 'https://www.ebay.com'
# disabled: true
# timeout: 5
- name: 1x
engine: www1x
shortcut: 1x
timeout: 3.0
disabled: true
- name: fdroid
engine: fdroid
shortcut: fd
disabled: true
- name: findthatmeme
engine: findthatmeme
shortcut: ftm
disabled: true
- name: flickr
categories: images
shortcut: fl
# You can use the engine using the official stable API, but you need an API
# key, see: https://www.flickr.com/services/apps/create/
# engine: flickr
# api_key: 'apikey' # required!
# Or you can use the html non-stable engine, activated by default
engine: flickr_noapi
- name: free software directory
engine: mediawiki
shortcut: fsd
categories: [it, software wikis]
base_url: https://directory.fsf.org/
search_type: title
timeout: 5.0
disabled: true
about:
website: https://directory.fsf.org/
wikidata_id: Q2470288
# - name: freesound
# engine: freesound
# shortcut: fnd
# disabled: true
# timeout: 15.0
# API key required, see: https://freesound.org/docs/api/overview.html
# api_key: MyAPIkey
- name: frinkiac
engine: frinkiac
shortcut: frk
disabled: true
- name: fyyd
engine: fyyd
shortcut: fy
timeout: 8.0
disabled: true
- name: geizhals
engine: geizhals
shortcut: geiz
disabled: true
- name: genius
engine: genius
shortcut: gen
- name: gentoo
engine: mediawiki
shortcut: ge
categories: ["it", "software wikis"]
base_url: "https://wiki.gentoo.org/"
api_path: "api.php"
search_type: text
timeout: 10
- name: gitlab
engine: gitlab
base_url: https://gitlab.com
shortcut: gl
disabled: true
about:
website: https://gitlab.com/
wikidata_id: Q16639197
# - name: gnome
# engine: gitlab
# base_url: https://gitlab.gnome.org
# shortcut: gn
# about:
# website: https://gitlab.gnome.org
# wikidata_id: Q44316
- name: github
engine: github
shortcut: gh
- name: codeberg
# https://docs.searxng.org/dev/engines/online/gitea.html
engine: gitea
base_url: https://codeberg.org
shortcut: cb
disabled: true
- name: gitea.com
engine: gitea
base_url: https://gitea.com
shortcut: gitea
disabled: true
- name: goodreads
engine: goodreads
shortcut: good
timeout: 4.0
disabled: true
- name: google
engine: google
shortcut: go
# additional_tests:
# android: *test_android
- name: google images
engine: google_images
shortcut: goi
# additional_tests:
# android: *test_android
# dali:
# matrix:
# query: ['Dali Christ']
# lang: ['en', 'de', 'fr', 'zh-CN']
# result_container:
# - ['one_title_contains', 'Salvador']
- name: google news
engine: google_news
shortcut: gon
# additional_tests:
# android: *test_android
- name: google videos
engine: google_videos
shortcut: gov
# additional_tests:
# android: *test_android
- name: google scholar
engine: google_scholar
shortcut: gos
- name: google play apps
engine: google_play
categories: [files, apps]
shortcut: gpa
play_categ: apps
disabled: true
- name: google play movies
engine: google_play
categories: videos
shortcut: gpm
play_categ: movies
disabled: true
- name: material icons
engine: material_icons
categories: images
shortcut: mi
disabled: true
- name: habrahabr
engine: xpath
paging: true
search_url: https://habr.com/en/search/page{pageno}/?q={query}
results_xpath: //article[contains(@class, "tm-articles-list__item")]
url_xpath: .//a[@class="tm-title__link"]/@href
title_xpath: .//a[@class="tm-title__link"]
content_xpath: .//div[contains(@class, "article-formatted-body")]
categories: it
timeout: 4.0
disabled: true
shortcut: habr
about:
website: https://habr.com/
wikidata_id: Q4494434
official_api_documentation: https://habr.com/en/docs/help/api/
use_official_api: false
require_api_key: false
results: HTML
- name: hackernews
engine: hackernews
shortcut: hn
disabled: true
- name: hex
engine: hex
shortcut: hex
disabled: true
# Valid values: name inserted_at updated_at total_downloads recent_downloads
sort_criteria: "recent_downloads"
page_size: 10
- name: crates.io
engine: crates
shortcut: crates
disabled: true
timeout: 6.0
- name: hoogle
engine: xpath
search_url: https://hoogle.haskell.org/?hoogle={query}
results_xpath: '//div[@class="result"]'
title_xpath: './/div[@class="ans"]//a'
url_xpath: './/div[@class="ans"]//a/@href'
content_xpath: './/div[@class="from"]'
page_size: 20
categories: [it, packages]
shortcut: ho
about:
website: https://hoogle.haskell.org/
wikidata_id: Q34010
official_api_documentation: https://hackage.haskell.org/api
use_official_api: false
require_api_key: false
results: JSON
- name: imdb
engine: imdb
shortcut: imdb
timeout: 6.0
disabled: true
- name: imgur
engine: imgur
shortcut: img
disabled: true
- name: ina
engine: ina
shortcut: in
timeout: 6.0
disabled: true
- name: invidious
engine: invidious
# Instanes will be selected randomly, see https://api.invidious.io/ for
# instances that are stable (good uptime) and close to you.
base_url:
- https://invidious.adminforge.de
- https://inv.nadeko.net
shortcut: iv
timeout: 3.0
disabled: true
- name: ipernity
engine: ipernity
shortcut: ip
disabled: true
- name: iqiyi
engine: iqiyi
shortcut: iq
disabled: true
- name: jisho
engine: jisho
shortcut: js
timeout: 3.0
disabled: true
- name: kickass
engine: kickass
base_url:
- https://kickasstorrents.to
- https://kickasstorrents.cr
- https://kickasstorrent.cr
- https://kickass.sx
- https://kat.am
shortcut: kc
timeout: 4.0
- name: lemmy communities
engine: lemmy
lemmy_type: Communities
shortcut: leco
- name: lemmy users
engine: lemmy
network: lemmy communities
lemmy_type: Users
shortcut: leus
- name: lemmy posts
engine: lemmy
network: lemmy communities
lemmy_type: Posts
shortcut: lepo
- name: lemmy comments
engine: lemmy
network: lemmy communities
lemmy_type: Comments
shortcut: lecom
- name: library genesis
engine: xpath
# search_url: https://libgen.is/search.php?req={query}
search_url: https://libgen.rs/search.php?req={query}
url_xpath: //a[contains(@href,"book/index.php?md5")]/@href
title_xpath: //a[contains(@href,"book/")]/text()[1]
content_xpath: //td/a[1][contains(@href,"=author")]/text()
categories: files
timeout: 7.0
disabled: true
shortcut: lg
about:
website: https://libgen.fun/
wikidata_id: Q22017206
official_api_documentation:
use_official_api: false
require_api_key: false
results: HTML
- name: z-library
engine: zlibrary
shortcut: zlib
categories: files
timeout: 7.0
- name: library of congress
engine: loc
shortcut: loc
categories: images
- name: libretranslate
engine: libretranslate
# https://github.com/LibreTranslate/LibreTranslate?tab=readme-ov-file#mirrors
base_url:
- https://libretranslate.com/translate
# api_key: abc123
shortcut: lt
disabled: true
- name: lingva
engine: lingva
shortcut: lv
# set lingva instance in url, by default it will use the official instance
# url: https://lingva.thedaviddelta.com
- name: lobste.rs
engine: xpath
search_url: https://lobste.rs/search?q={query}&what=stories&order=relevance
results_xpath: //li[contains(@class, "story")]
url_xpath: .//a[@class="u-url"]/@href
title_xpath: .//a[@class="u-url"]
content_xpath: .//a[@class="domain"]
categories: it
shortcut: lo
timeout: 5.0
disabled: true
about:
website: https://lobste.rs/
wikidata_id: Q60762874
official_api_documentation:
use_official_api: false
require_api_key: false
results: HTML
- name: mastodon users
engine: mastodon
mastodon_type: accounts
base_url: https://mastodon.social
shortcut: mau
- name: mastodon hashtags
engine: mastodon
mastodon_type: hashtags
base_url: https://mastodon.social
shortcut: mah
# - name: matrixrooms
# engine: mrs
# # https://docs.searxng.org/dev/engines/online/mrs.html
# # base_url: https://mrs-api-host
# shortcut: mtrx
# disabled: true
- name: mdn
shortcut: mdn
engine: json_engine
categories: [it]
paging: true
search_url: https://developer.mozilla.org/api/v1/search?q={query}&page={pageno}
results_query: documents
url_query: mdn_url
url_prefix: https://developer.mozilla.org
title_query: title
content_query: summary
about:
website: https://developer.mozilla.org
wikidata_id: Q3273508
official_api_documentation: null
use_official_api: false
require_api_key: false
results: JSON
- name: metacpan
engine: metacpan
shortcut: cpan
disabled: true
number_of_results: 20
# - name: meilisearch
# engine: meilisearch
# shortcut: mes
# enable_http: true
# base_url: http://localhost:7700
# index: my-index
- name: mixcloud
engine: mixcloud
shortcut: mc
# MongoDB engine
# Required dependency: pymongo
# - name: mymongo
# engine: mongodb
# shortcut: md
# exact_match_only: false
# host: '127.0.0.1'
# port: 27017
# enable_http: true
# results_per_page: 20
# database: 'business'
# collection: 'reviews' # name of the db collection
# key: 'name' # key in the collection to search for
- name: mozhi
engine: mozhi
base_url:
- https://mozhi.aryak.me
- https://translate.bus-hit.me
- https://nyc1.mz.ggtyler.dev
# mozhi_engine: google - see https://mozhi.aryak.me for supported engines
timeout: 4.0
shortcut: mz
disabled: true
- name: mwmbl
engine: mwmbl
# api_url: https://api.mwmbl.org
shortcut: mwm
disabled: true
- name: npm
engine: npm
shortcut: npm
timeout: 5.0
disabled: true
- name: nyaa
engine: nyaa
shortcut: nt
disabled: true
- name: mankier
engine: json_engine
search_url: https://www.mankier.com/api/v2/mans/?q={query}
results_query: results
url_query: url
title_query: name
content_query: description
categories: it
shortcut: man
about:
website: https://www.mankier.com/
official_api_documentation: https://www.mankier.com/api
use_official_api: true
require_api_key: false
results: JSON
# read https://docs.searxng.org/dev/engines/online/mullvad_leta.html
# - name: mullvadleta
# engine: mullvad_leta
# leta_engine: google # choose one of the following: google, brave
# use_cache: true # Only 100 non-cache searches per day, suggested only for private instances
# search_url: https://leta.mullvad.net
# categories: [general, web]
# shortcut: ml
- name: odysee
engine: odysee
shortcut: od
disabled: true
- name: openairedatasets
engine: json_engine
paging: true
search_url: https://api.openaire.eu/search/datasets?format=json&page={pageno}&size=10&title={query}
results_query: response/results/result
url_query: metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
title_query: metadata/oaf:entity/oaf:result/title/$
content_query: metadata/oaf:entity/oaf:result/description/$
content_html_to_text: true
categories: "science"
shortcut: oad
timeout: 5.0
about:
website: https://www.openaire.eu/
wikidata_id: Q25106053
official_api_documentation: https://api.openaire.eu/
use_official_api: false
require_api_key: false
results: JSON
- name: openairepublications
engine: json_engine
paging: true
search_url: https://api.openaire.eu/search/publications?format=json&page={pageno}&size=10&title={query}
results_query: response/results/result
url_query: metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
title_query: metadata/oaf:entity/oaf:result/title/$
content_query: metadata/oaf:entity/oaf:result/description/$
content_html_to_text: true
categories: science
shortcut: oap
timeout: 5.0
about:
website: https://www.openaire.eu/
wikidata_id: Q25106053
official_api_documentation: https://api.openaire.eu/
use_official_api: false
require_api_key: false
results: JSON
- name: openclipart
engine: openclipart
shortcut: ocl
inactive: true
disabled: true
timeout: 30
- name: openlibrary
engine: openlibrary
shortcut: ol
timeout: 5
disabled: true
- name: openmeteo
engine: open_meteo
shortcut: om
disabled: true
# - name: opensemanticsearch
# engine: opensemantic
# shortcut: oss
# base_url: 'http://localhost:8983/solr/opensemanticsearch/'
- name: openstreetmap
engine: openstreetmap
shortcut: osm
- name: openrepos
engine: xpath
paging: true
search_url: https://openrepos.net/search/node/{query}?page={pageno}
url_xpath: //li[@class="search-result"]//h3[@class="title"]/a/@href
title_xpath: //li[@class="search-result"]//h3[@class="title"]/a
content_xpath: //li[@class="search-result"]//div[@class="search-snippet-info"]//p[@class="search-snippet"]
categories: files
timeout: 4.0
disabled: true
shortcut: or
about:
website: https://openrepos.net/
wikidata_id:
official_api_documentation:
use_official_api: false
require_api_key: false
results: HTML
- name: packagist
engine: json_engine
paging: true
search_url: https://packagist.org/search.json?q={query}&page={pageno}
results_query: results
url_query: url
title_query: name
content_query: description
categories: [it, packages]
disabled: true
timeout: 5.0
shortcut: pack
about:
website: https://packagist.org
wikidata_id: Q108311377
official_api_documentation: https://packagist.org/apidoc
use_official_api: true
require_api_key: false
results: JSON
- name: pdbe
engine: pdbe
shortcut: pdb
# Hide obsolete PDB entries. Default is not to hide obsolete structures
# hide_obsolete: false
- name: photon
engine: photon
shortcut: ph
- name: pinterest
engine: pinterest
shortcut: pin
#- name: piped
# engine: piped
# shortcut: ppd
# categories: videos
# piped_filter: videos
# timeout: 3.0
- name: piratebay
engine: piratebay
shortcut: tpb
# You may need to change this URL to a proxy if piratebay is blocked in your
# country
url: https://thepiratebay.org/
timeout: 3.0
- name: pixiv
shortcut: pv
engine: pixiv
disabled: true
inactive: true
pixiv_image_proxies:
- https://pximg.example.org
# A proxy is required to load the images. Hosting an image proxy server
# for Pixiv:
# --> https://pixivfe.pages.dev/hosting-image-proxy-server/
# Proxies from public instances. Ask the public instances owners if they
# agree to receive traffic from SearXNG!
# --> https://codeberg.org/VnPower/PixivFE#instances
# --> https://github.com/searxng/searxng/pull/3192#issuecomment-1941095047
# image proxy of https://pixiv.cat
# - https://i.pixiv.cat
# image proxy of https://www.pixiv.pics
# - https://pximg.cocomi.eu.org
# image proxy of https://pixivfe.exozy.me
# - https://pximg.exozy.me
# image proxy of https://pixivfe.ducks.party
# - https://pixiv.ducks.party
# image proxy of https://pixiv.perennialte.ch
# - https://pximg.perennialte.ch
- name: podcastindex
engine: podcastindex
shortcut: podcast
# Required dependency: psychopg2
# - name: postgresql
# engine: postgresql
# database: postgres
# username: postgres
# password: postgres
# limit: 10
# query_str: 'SELECT * from my_table WHERE my_column = %(query)s'
# shortcut : psql
- name: presearch
engine: presearch
search_type: search
categories: [general, web]
shortcut: ps
timeout: 4.0
disabled: true
- name: presearch images
engine: presearch
network: presearch
search_type: images
categories: [images, web]
timeout: 4.0
shortcut: psimg
disabled: true
- name: presearch videos
engine: presearch
network: presearch
search_type: videos
categories: [general, web]
timeout: 4.0
shortcut: psvid
disabled: true
- name: presearch news
engine: presearch
network: presearch
search_type: news
categories: [news, web]
timeout: 4.0
shortcut: psnews
disabled: true
- name: pub.dev
engine: xpath
shortcut: pd
search_url: https://pub.dev/packages?q={query}&page={pageno}
paging: true
results_xpath: //div[contains(@class,"packages-item")]
url_xpath: ./div/h3/a/@href
title_xpath: ./div/h3/a
content_xpath: ./div/div/div[contains(@class,"packages-description")]/span
categories: [packages, it]
timeout: 3.0
disabled: true
first_page_num: 1
about:
website: https://pub.dev/
official_api_documentation: https://pub.dev/help/api
use_official_api: false
require_api_key: false
results: HTML
- name: public domain image archive
engine: public_domain_image_archive
shortcut: pdia
- name: pubmed
engine: pubmed
shortcut: pub
timeout: 3.0
- name: pypi
shortcut: pypi
engine: pypi
- name: qwant
qwant_categ: web
engine: qwant
shortcut: qw
categories: [general, web]
additional_tests:
rosebud: *test_rosebud
- name: qwant news
qwant_categ: news
engine: qwant
shortcut: qwn
categories: news
network: qwant
- name: qwant images
qwant_categ: images
engine: qwant
shortcut: qwi
categories: [images, web]
network: qwant
- name: qwant videos
qwant_categ: videos
engine: qwant
shortcut: qwv
categories: [videos, web]
network: qwant
# - name: library
# engine: recoll
# shortcut: lib
# base_url: 'https://recoll.example.org/'
# search_dir: ''
# mount_prefix: /export
# dl_prefix: 'https://download.example.org'
# timeout: 30.0
# categories: files
# disabled: true
# - name: recoll library reference
# engine: recoll
# base_url: 'https://recoll.example.org/'
# search_dir: reference
# mount_prefix: /export
# dl_prefix: 'https://download.example.org'
# shortcut: libr
# timeout: 30.0
# categories: files
# disabled: true
- name: radio browser
engine: radio_browser
shortcut: rb
- name: reddit
engine: reddit
shortcut: re
page_size: 25
disabled: true
- name: right dao
engine: xpath
paging: true
page_size: 12
search_url: https://rightdao.com/search?q={query}&start={pageno}
results_xpath: //div[contains(@class, "description")]
url_xpath: ../div[contains(@class, "title")]/a/@href
title_xpath: ../div[contains(@class, "title")]
content_xpath: .
categories: general
shortcut: rd
disabled: true
about:
website: https://rightdao.com/
use_official_api: false
require_api_key: false
results: HTML
- name: rottentomatoes
engine: rottentomatoes
shortcut: rt
disabled: true
# Required dependency: redis
# - name: myredis
# shortcut : rds
# engine: redis_server
# exact_match_only: false
# host: '127.0.0.1'
# port: 6379
# enable_http: true
# password: ''
# db: 0
# tmp suspended: bad certificate
# - name: scanr structures
# shortcut: scs
# engine: scanr_structures
# disabled: true
- name: searchmysite
engine: xpath
shortcut: sms
categories: general
paging: true
search_url: https://searchmysite.net/search/?q={query}&page={pageno}
results_xpath: //div[contains(@class,'search-result')]
url_xpath: .//a[contains(@class,'result-link')]/@href
title_xpath: .//span[contains(@class,'result-title-txt')]/text()
content_xpath: ./p[@id='result-hightlight']
disabled: true
about:
website: https://searchmysite.net
- name: sepiasearch
engine: sepiasearch
shortcut: sep
- name: sogou
engine: sogou
shortcut: sogou
disabled: true
- name: sogou images
engine: sogou_images
shortcut: sogoui
disabled: true
- name: sogou videos
engine: sogou_videos
shortcut: sogouv
disabled: true
- name: sogou wechat
engine: sogou_wechat
shortcut: sogouw
disabled: true
- name: soundcloud
engine: soundcloud
shortcut: sc
- name: stackoverflow
engine: stackexchange
shortcut: st
api_site: 'stackoverflow'
categories: [it, q&a]
- name: askubuntu
engine: stackexchange
shortcut: ubuntu
api_site: 'askubuntu'
categories: [it, q&a]
- name: superuser
engine: stackexchange
shortcut: su
api_site: 'superuser'
categories: [it, q&a]
- name: discuss.python
engine: discourse
shortcut: dpy
base_url: 'https://discuss.python.org'
categories: [it, q&a]
disabled: true
- name: caddy.community
engine: discourse
shortcut: caddy
base_url: 'https://caddy.community'
categories: [it, q&a]
disabled: true
- name: pi-hole.community
engine: discourse
shortcut: pi
categories: [it, q&a]
base_url: 'https://discourse.pi-hole.net'
disabled: true
- name: searchcode code
engine: searchcode_code
shortcut: scc
disabled: true
# - name: searx
# engine: searx_engine
# shortcut: se
# instance_urls :
# - http://127.0.0.1:8888/
# - ...
# disabled: true
- name: semantic scholar
engine: semantic_scholar
disabled: true
shortcut: se
# Spotify needs API credentials
# - name: spotify
# engine: spotify
# shortcut: stf
# api_client_id: *******
# api_client_secret: *******
# - name: solr
# engine: solr
# shortcut: slr
# base_url: http://localhost:8983
# collection: collection_name
# sort: '' # sorting: asc or desc
# field_list: '' # comma separated list of field names to display on the UI
# default_fields: '' # default field to query
# query_fields: '' # query fields
# enable_http: true
# - name: springer nature
# engine: springer
# # get your API key from: https://dev.springernature.com/signup
# # working API key, for test & debug: "a69685087d07eca9f13db62f65b8f601"
# api_key: 'unset'
# shortcut: springer
# timeout: 15.0
- name: startpage
engine: startpage
shortcut: sp
startpage_categ: web
categories: [general, web]
additional_tests:
rosebud: *test_rosebud
- name: startpage news
engine: startpage
startpage_categ: news
categories: [news, web]
shortcut: spn
- name: startpage images
engine: startpage
startpage_categ: images
categories: [images, web]
shortcut: spi
- name: tokyotoshokan
engine: tokyotoshokan
shortcut: tt
timeout: 6.0
disabled: true
- name: solidtorrents
engine: solidtorrents
shortcut: solid
timeout: 4.0
base_url:
- https://solidtorrents.to
- https://bitsearch.to
# For this demo of the sqlite engine download:
# https://liste.mediathekview.de/filmliste-v2.db.bz2
# and unpack into searx/data/filmliste-v2.db
# Query to test: "!mediathekview concert"
#
# - name: mediathekview
# engine: sqlite
# shortcut: mediathekview
# categories: [general, videos]
# result_type: MainResult
# database: searx/data/filmliste-v2.db
# query_str: >-
# SELECT title || ' (' || time(duration, 'unixepoch') || ')' AS title,
# COALESCE( NULLIF(url_video_hd,''), NULLIF(url_video_sd,''), url_video) AS url,
# description AS content
# FROM film
# WHERE title LIKE :wildcard OR description LIKE :wildcard
# ORDER BY duration DESC
- name: tagesschau
engine: tagesschau
# when set to false, display URLs from Tagesschau, and not the actual source
# (e.g. NDR, WDR, SWR, HR, ...)
use_source_url: true
shortcut: ts
disabled: true
- name: tmdb
engine: xpath
paging: true
categories: movies
search_url: https://www.themoviedb.org/search?page={pageno}&query={query}
results_xpath: //div[contains(@class,"movie") or contains(@class,"tv")]//div[contains(@class,"card")]
url_xpath: .//div[contains(@class,"poster")]/a/@href
thumbnail_xpath: .//img/@src
title_xpath: .//div[contains(@class,"title")]//h2
content_xpath: .//div[contains(@class,"overview")]
shortcut: tm
disabled: true
# torznab engine lets you query any torznab compatible indexer. Using this
# engine in combination with Jackett opens the possibility to query a lot of
# public and private indexers directly from SearXNG. More details at:
# https://docs.searxng.org/dev/engines/online/torznab.html
#
# - name: Torznab EZTV
# engine: torznab
# shortcut: eztv
# base_url: http://localhost:9117/api/v2.0/indexers/eztv/results/torznab
# enable_http: true # if using localhost
# api_key: xxxxxxxxxxxxxxx
# show_magnet_links: true
# show_torrent_files: false
# # https://github.com/Jackett/Jackett/wiki/Jackett-Categories
# torznab_categories: # optional
# - 2000
# - 5000
# tmp suspended - too slow, too many errors
# - name: urbandictionary
# engine : xpath
# search_url : https://www.urbandictionary.com/define.php?term={query}
# url_xpath : //*[@class="word"]/@href
# title_xpath : //*[@class="def-header"]
# content_xpath: //*[@class="meaning"]
# shortcut: ud
- name: unsplash
engine: unsplash
shortcut: us
- name: yandex
engine: yandex
categories: general
search_type: web
shortcut: yd
disabled: true
inactive: true
- name: yandex images
engine: yandex
categories: images
search_type: images
shortcut: ydi
disabled: true
inactive: true
- name: yandex music
engine: yandex_music
shortcut: ydm
disabled: true
# https://yandex.com/support/music/access.html
inactive: true
- name: yahoo
engine: yahoo
shortcut: yh
disabled: true
- name: yahoo news
engine: yahoo_news
shortcut: yhn
- name: youtube
shortcut: yt
# You can use the engine using the official stable API, but you need an API
# key See: https://console.developers.google.com/project
#
# engine: youtube_api
# api_key: 'apikey' # required!
#
# Or you can use the html non-stable engine, activated by default
engine: youtube_noapi
- name: dailymotion
engine: dailymotion
shortcut: dm
- name: vimeo
engine: vimeo
shortcut: vm
- name: wiby
engine: json_engine
paging: true
search_url: https://wiby.me/json/?q={query}&p={pageno}
url_query: URL
title_query: Title
content_query: Snippet
categories: [general, web]
shortcut: wib
disabled: true
about:
website: https://wiby.me/
- name: wikibooks
engine: mediawiki
weight: 0.5
shortcut: wb
categories: [general, wikimedia]
base_url: "https://{language}.wikibooks.org/"
search_type: text
disabled: true
about:
website: https://www.wikibooks.org/
wikidata_id: Q367
- name: wikinews
engine: mediawiki
shortcut: wn
categories: [news, wikimedia]
base_url: "https://{language}.wikinews.org/"
search_type: text
srsort: create_timestamp_desc
about:
website: https://www.wikinews.org/
wikidata_id: Q964
- name: wikiquote
engine: mediawiki
weight: 0.5
shortcut: wq
categories: [general, wikimedia]
base_url: "https://{language}.wikiquote.org/"
search_type: text
disabled: true
additional_tests:
rosebud: *test_rosebud
about:
website: https://www.wikiquote.org/
wikidata_id: Q369
- name: wikisource
engine: mediawiki
weight: 0.5
shortcut: ws
categories: [general, wikimedia]
base_url: "https://{language}.wikisource.org/"
search_type: text
disabled: true
about:
website: https://www.wikisource.org/
wikidata_id: Q263
- name: wikispecies
engine: mediawiki
shortcut: wsp
categories: [general, science, wikimedia]
base_url: "https://species.wikimedia.org/"
search_type: text
disabled: true
about:
website: https://species.wikimedia.org/
wikidata_id: Q13679
tests:
wikispecies:
matrix:
query: "Campbell, L.I. et al. 2011: MicroRNAs"
lang: en
result_container:
- not_empty
- ['one_title_contains', 'Tardigrada']
test:
- unique_results
- name: wiktionary
engine: mediawiki
shortcut: wt
categories: [dictionaries, wikimedia]
base_url: "https://{language}.wiktionary.org/"
search_type: text
about:
website: https://www.wiktionary.org/
wikidata_id: Q151
- name: wikiversity
engine: mediawiki
weight: 0.5
shortcut: wv
categories: [general, wikimedia]
base_url: "https://{language}.wikiversity.org/"
search_type: text
disabled: true
about:
website: https://www.wikiversity.org/
wikidata_id: Q370
- name: wikivoyage
engine: mediawiki
weight: 0.5
shortcut: wy
categories: [general, wikimedia]
base_url: "https://{language}.wikivoyage.org/"
search_type: text
disabled: true
about:
website: https://www.wikivoyage.org/
wikidata_id: Q373
# - name: wikicommons.images
# engine: wikicommons
# shortcut: wc
# categories: images
# search_type: images
# number_of_results: 10
#
# - name: wikicommons.videos
# engine: wikicommons
# shortcut: wcv
# categories: videos
# search_type: videos
# number_of_results: 10
#
# - name: wikicommons.audio
# engine: wikicommons
# shortcut: wca
# categories: music
# search_type: audio
# number_of_results: 10
#
# - name: wikicommons.files
# engine: wikicommons
# shortcut: wcf
# categories: files
# search_type: files
# number_of_results: 10
- name: wolframalpha
shortcut: wa
# You can use the engine using the official stable API, but you need an API
# key. See: https://products.wolframalpha.com/api/
#
# engine: wolframalpha_api
# api_key: ''
#
# Or you can use the html non-stable engine, activated by default
engine: wolframalpha_noapi
timeout: 6.0
categories: general
disabled: true
- name: dictzone
engine: dictzone
shortcut: dc
- name: mymemory translated
engine: translated
shortcut: tl
timeout: 5.0
# You can use without an API key, but you are limited to 1000 words/day
# See: https://mymemory.translated.net/doc/usagelimits.php
# api_key: ''
# Required dependency: mysql-connector-python
# - name: mysql
# engine: mysql_server
# database: mydatabase
# username: user
# password: pass
# limit: 10
# query_str: 'SELECT * from mytable WHERE fieldname=%(query)s'
# shortcut: mysql
# Required dependency: mariadb
# - name: mariadb
# engine: mariadb_server
# database: mydatabase
# username: user
# password: pass
# limit: 10
# query_str: 'SELECT * from mytable WHERE fieldname=%(query)s'
# shortcut: mdb
- name: 1337x
engine: 1337x
shortcut: 1337x
disabled: true
- name: duden
engine: duden
shortcut: du
disabled: true
- name: seznam
shortcut: szn
engine: seznam
disabled: true
# - name: deepl
# engine: deepl
# shortcut: dpl
# # You can use the engine using the official stable API, but you need an API key
# # See: https://www.deepl.com/pro-api?cta=header-pro-api
# api_key: '' # required!
# timeout: 5.0
# disabled: true
- name: mojeek
shortcut: mjk
engine: mojeek
categories: [general, web]
disabled: true
- name: mojeek images
shortcut: mjkimg
engine: mojeek
categories: [images, web]
search_type: images
paging: false
disabled: true
- name: mojeek news
shortcut: mjknews
engine: mojeek
categories: [news, web]
search_type: news
paging: false
disabled: true
- name: moviepilot
engine: moviepilot
shortcut: mp
disabled: true
- name: naver
shortcut: nvr
categories: [general, web]
engine: xpath
paging: true
search_url: https://search.naver.com/search.naver?where=webkr&sm=osp_hty&ie=UTF-8&query={query}&start={pageno}
url_xpath: //a[@class="link_tit"]/@href
title_xpath: //a[@class="link_tit"]
content_xpath: //div[@class="total_dsc_wrap"]/a
first_page_num: 1
page_size: 10
disabled: true
about:
website: https://www.naver.com/
wikidata_id: Q485639
official_api_documentation: https://developers.naver.com/docs/nmt/examples/
use_official_api: false
require_api_key: false
results: HTML
language: ko
- name: rubygems
shortcut: rbg
engine: xpath
paging: true
search_url: https://rubygems.org/search?page={pageno}&query={query}
results_xpath: /html/body/main/div/a[@class="gems__gem"]
url_xpath: ./@href
title_xpath: ./span/h2
content_xpath: ./span/p
suggestion_xpath: /html/body/main/div/div[@class="search__suggestions"]/p/a
first_page_num: 1
categories: [it, packages]
disabled: true
about:
website: https://rubygems.org/
wikidata_id: Q1853420
official_api_documentation: https://guides.rubygems.org/rubygems-org-api/
use_official_api: false
require_api_key: false
results: HTML
- name: peertube
engine: peertube
shortcut: ptb
paging: true
# alternatives see: https://instances.joinpeertube.org/instances
# base_url: https://tube.4aem.com
categories: videos
disabled: true
timeout: 6.0
- name: mediathekviewweb
engine: mediathekviewweb
shortcut: mvw
disabled: true
- name: yacy
# https://docs.searxng.org/dev/engines/online/yacy.html
engine: yacy
categories: general
search_type: text
base_url:
- https://yacy.searchlab.eu
# see https://github.com/searxng/searxng/pull/3631#issuecomment-2240903027
# - https://search.kyun.li
# - https://yacy.securecomcorp.eu
# - https://yacy.myserv.ca
# - https://yacy.nsupdate.info
# - https://yacy.electroncash.de
shortcut: ya
disabled: true
# if you aren't using HTTPS for your local yacy instance disable https
# enable_http: false
search_mode: 'global'
# timeout can be reduced in 'local' search mode
timeout: 5.0
- name: rumble
engine: rumble
shortcut: ru
base_url: https://rumble.com/
paging: true
categories: videos
disabled: true
- name: livespace
engine: livespace
shortcut: ls
categories: videos
disabled: true
timeout: 5.0
- name: wordnik
engine: wordnik
shortcut: def
categories: [dictionaries]
timeout: 5.0
- name: woxikon.de synonyme
engine: xpath
shortcut: woxi
categories: [dictionaries]
timeout: 5.0
disabled: true
search_url: https://synonyme.woxikon.de/synonyme/{query}.php
url_xpath: //div[@class="upper-synonyms"]/a/@href
content_xpath: //div[@class="synonyms-list-group"]
title_xpath: //div[@class="upper-synonyms"]/a
no_result_for_http_status: [404]
about:
website: https://www.woxikon.de/
wikidata_id: # No Wikidata ID
use_official_api: false
require_api_key: false
results: HTML
language: de
- name: seekr news
engine: seekr
shortcut: senews
categories: news
seekr_category: news
disabled: true
- name: seekr images
engine: seekr
network: seekr news
shortcut: seimg
categories: images
seekr_category: images
disabled: true
- name: seekr videos
engine: seekr
network: seekr news
shortcut: sevid
categories: videos
seekr_category: videos
disabled: true
- name: stract
engine: stract
shortcut: str
disabled: true
- name: svgrepo
engine: svgrepo
shortcut: svg
timeout: 10.0
disabled: true
- name: tootfinder
engine: tootfinder
shortcut: toot
- name: voidlinux
engine: voidlinux
shortcut: void
disabled: true
- name: wallhaven
engine: wallhaven
# api_key: abcdefghijklmnopqrstuvwxyz
shortcut: wh
# wikimini: online encyclopedia for children
# The fulltext and title parameter is necessary for Wikimini because
# sometimes it will not show the results and redirect instead
- name: wikimini
engine: xpath
shortcut: wkmn
search_url: https://fr.wikimini.org/w/index.php?search={query}&title=Sp%C3%A9cial%3ASearch&fulltext=Search
url_xpath: //li/div[@class="mw-search-result-heading"]/a/@href
title_xpath: //li//div[@class="mw-search-result-heading"]/a
content_xpath: //li/div[@class="searchresult"]
categories: general
disabled: true
about:
website: https://wikimini.org/
wikidata_id: Q3568032
use_official_api: false
require_api_key: false
results: HTML
language: fr
- name: wttr.in
engine: wttr
shortcut: wttr
timeout: 9.0
- name: brave
engine: brave
shortcut: br
time_range_support: true
paging: true
categories: [general, web]
brave_category: search
# brave_spellcheck: true
- name: brave.images
engine: brave
network: brave
shortcut: brimg
categories: [images, web]
brave_category: images
- name: brave.videos
engine: brave
network: brave
shortcut: brvid
categories: [videos, web]
brave_category: videos
- name: brave.news
engine: brave
network: brave
shortcut: brnews
categories: news
brave_category: news
# - name: brave.goggles
# engine: brave
# network: brave
# shortcut: brgog
# time_range_support: true
# paging: true
# categories: [general, web]
# brave_category: goggles
# Goggles: # required! This should be a URL ending in .goggle
- name: lib.rs
shortcut: lrs
engine: lib_rs
disabled: true
- name: sourcehut
shortcut: srht
engine: xpath
paging: true
search_url: https://sr.ht/projects?page={pageno}&search={query}
results_xpath: (//div[@class="event-list"])[1]/div[@class="event"]
url_xpath: ./h4/a[2]/@href
title_xpath: ./h4/a[2]
content_xpath: ./p
first_page_num: 1
categories: [it, repos]
disabled: true
about:
website: https://sr.ht
wikidata_id: Q78514485
official_api_documentation: https://man.sr.ht/
use_official_api: false
require_api_key: false
results: HTML
- name: goo
shortcut: goo
engine: xpath
paging: true
search_url: https://search.goo.ne.jp/web.jsp?MT={query}&FR={pageno}0
url_xpath: //div[@class="result"]/p[@class='title fsL1']/a/@href
title_xpath: //div[@class="result"]/p[@class='title fsL1']/a
content_xpath: //p[contains(@class,'url fsM')]/following-sibling::p
first_page_num: 0
categories: [general, web]
disabled: true
timeout: 4.0
about:
website: https://search.goo.ne.jp
wikidata_id: Q249044
use_official_api: false
require_api_key: false
results: HTML
language: ja
- name: bt4g
engine: bt4g
shortcut: bt4g
- name: pkg.go.dev
engine: pkg_go_dev
shortcut: pgo
disabled: true
# Doku engine lets you access to any Doku wiki instance:
# A public one or a privete/corporate one.
# - name: ubuntuwiki
# engine: doku
# shortcut: uw
# base_url: 'https://doc.ubuntu-fr.org'
# Be careful when enabling this engine if you are
# running a public instance. Do not expose any sensitive
# information. You can restrict access by configuring a list
# of access tokens under tokens.
# - name: git grep
# engine: command
# command: ['git', 'grep', '{{QUERY}}']
# shortcut: gg
# tokens: []
# disabled: true
# delimiter:
# chars: ':'
# keys: ['filepath', 'code']
# Be careful when enabling this engine if you are
# running a public instance. Do not expose any sensitive
# information. You can restrict access by configuring a list
# of access tokens under tokens.
# - name: locate
# engine: command
# command: ['locate', '{{QUERY}}']
# shortcut: loc
# tokens: []
# disabled: true
# delimiter:
# chars: ' '
# keys: ['line']
# Be careful when enabling this engine if you are
# running a public instance. Do not expose any sensitive
# information. You can restrict access by configuring a list
# of access tokens under tokens.
# - name: find
# engine: command
# command: ['find', '.', '-name', '{{QUERY}}']
# query_type: path
# shortcut: fnd
# tokens: []
# disabled: true
# delimiter:
# chars: ' '
# keys: ['line']
# Be careful when enabling this engine if you are
# running a public instance. Do not expose any sensitive
# information. You can restrict access by configuring a list
# of access tokens under tokens.
# - name: pattern search in files
# engine: command
# command: ['fgrep', '{{QUERY}}']
# shortcut: fgr
# tokens: []
# disabled: true
# delimiter:
# chars: ' '
# keys: ['line']
# Be careful when enabling this engine if you are
# running a public instance. Do not expose any sensitive
# information. You can restrict access by configuring a list
# of access tokens under tokens.
# - name: regex search in files
# engine: command
# command: ['grep', '{{QUERY}}']
# shortcut: gr
# tokens: []
# disabled: true
# delimiter:
# chars: ' '
# keys: ['line']
doi_resolvers:
oadoi.org: 'https://oadoi.org/'
doi.org: 'https://doi.org/'
doai.io: 'https://dissem.in/'
sci-hub.se: 'https://sci-hub.se/'
sci-hub.st: 'https://sci-hub.st/'
sci-hub.ru: 'https://sci-hub.ru/'
default_doi_resolver: 'oadoi.org'
================================================
FILE: searxng/setup_searxng.sh
================================================
#!/bin/bash
# Script to automate SearXNG setup and deployment with Docker Compose
command_exists() {
command -v "$1" &> /dev/null
}
# Check if Docker is installed
if ! command_exists docker; then
echo "Error: Docker is not installed. Please install Docker first."
echo "On Ubuntu: sudo apt install docker.io"
echo "On macOS/Windows: Install Docker Desktop from https://www.docker.com/get-started/"
exit 1
fi
# Check if Docker daemon is running
echo "Checking if Docker daemon is running..."
if ! docker info &> /dev/null; then
echo "Error: Docker daemon is not running or inaccessible."
if [ "$(uname)" = "Linux" ]; then
echo "Trying to start Docker service (may require sudo)..."
if sudo systemctl start docker &> /dev/null; then
echo "Docker started successfully."
else
echo "Failed to start Docker. Possible issues:"
echo "1. Run this script with sudo: sudo bash setup_searxng.sh"
echo "2. Check Docker installation: sudo systemctl status docker"
echo "3. Add your user to the docker group: sudo usermod -aG docker $USER (then log out and back in)"
exit 1
fi
else
echo "Please start Docker manually:"
echo "- On macOS/Windows: Open Docker Desktop."
echo "- On Linux: Run 'sudo systemctl start docker' or check your distro's docs."
exit 1
fi
else
echo "Docker daemon is running."
fi
# Check if Docker Compose is installed
if ! command_exists docker-compose; then
echo "Error: Docker Compose is not installed. Please install it first."
echo "On Ubuntu: sudo apt install docker-compose"
echo "Or via pip: pip install docker-compose"
exit 1
fi
# Create a directory for SearXNG config if it doesn’t exist
mkdir -p searxng
cd . || exit
# Check if docker-compose.yml exists
if [ ! -f "docker-compose.yml" ]; then
echo "Error: docker-compose.yml not found in the current directory."
echo "Please create it before running this script."
exit 1
fi
# Start containers to generate initial config files
echo "Starting containers for initial setup..."
if ! docker-compose up -d; then
echo "Error: Failed to start containers. Check Docker logs with 'docker compose logs'."
echo "Possible fixes: Run with sudo or ensure port 8080 is free."
exit 1
fi
sleep 10
# Generate a secret key and update settings
SECRET_KEY=$(openssl rand -hex 32)
if [ -f "searxng/settings.yml" ]; then
if [ "$(uname)" = "Darwin" ]; then
sed -i '' "s/ultrasecretkey/$SECRET_KEY/g" searxng/settings.yml || {
echo "Warning: Failed to update settings.yml with secret key. Please check the file manually."
}
else
sed -i "s/ultrasecretkey/$SECRET_KEY/g" searxng/settings.yml || {
echo "Warning: Failed to update settings.yml with secret key. Please check the file manually."
}
fi
else
echo "Error: settings.yml not found. Initial setup may have failed."
docker-compose logs searxng
exit 1
fi
# Display status and access instructions
echo "SearXNG setup complete!"
docker ps -a --filter "name=searxng" --filter "name=redis"
echo "Access SearXNG at: http://localhost:8080"
================================================
FILE: searxng/uwsgi.ini
================================================
[uwsgi]
# Who will run the code
uid = searxng
gid = searxng
# Number of workers (usually CPU count)
# default value: %k (= number of CPU core, see Dockerfile)
workers = 4
# Number of threads per worker
# default value: 4 (see Dockerfile)
enable-threads = 4
threads = 4
# The right granted on the created socket
chmod-socket = 666
# Plugin to use and interpreter config
single-interpreter = true
master = true
plugin = python3
lazy-apps = true
enable-threads = 4
# Module to import
module = searx.webapp
# Virtualenv and python path
pythonpath = /usr/local/searxng/
chdir = /usr/local/searxng/searx/
# automatically set processes name to something meaningful
auto-procname = true
# Disable request logging for privacy
disable-logging = true
log-5xx = true
# Set the max size of a request (request-body excluded)
buffer-size = 8192
# No keep alive
# See https://github.com/searx/searx-docker/issues/24
add-header = Connection: close
# Follow SIGTERM convention
# See https://github.com/searxng/searxng/issues/3427
die-on-term
# uwsgi serves the static files
static-map = /static=/usr/local/searxng/searx/static
static-gzip-all = True
offload-threads = 4
================================================
FILE: setup.py
================================================
from setuptools import setup, find_packages
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
setup(
name="agenticSeek",
version="0.1.0",
author="Fosowl",
author_email="mlg.fcu@gmail.com",
description="The open, local alternative to ManusAI",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/Fosowl/agenticSeek",
packages=find_packages(),
include_package_data=True,
install_requires=[
"fastapi>=0.115.12",
"celery>=5.5.1",
"uvicorn>=0.34.0",
"flask>=3.1.0",
"aiofiles>=24.1.0",
"pydantic>=2.10.6",
"pydantic_core>=2.27.2",
"requests>=2.31.0",
"sacremoses>=0.0.53",
"numpy>=1.24.4",
"colorama>=0.4.6",
"python-dotenv>=1.0.0",
"playsound>=1.3.0",
"soundfile>=0.13.1",
"transformers>=4.46.3",
"torch>=2.4.1",
"ollama>=0.4.7",
"scipy>=1.9.3",
"kokoro>=0.7.12",
"protobuf>=3.20.3",
"termcolor>=2.5.0",
"ipython>=8.34.0",
"librosa>=0.10.2.post1",
"selenium>=4.29.0",
"markdownify>=1.1.0",
"text2emotion>=0.0.5",
"python-dotenv>=1.0.0",
"adaptive-classifier>=0.0.10",
"langid>=1.1.6",
"chromedriver-autoinstaller>=0.6.4",
"httpx>=0.27,<0.29",
"anyio>=3.5.0,<5",
"distro>=1.7.0,<2",
"jiter>=0.4.0,<1",
"fake_useragent>=2.1.0",
"selenium_stealth>=1.0.6",
"undetected-chromedriver>=3.5.5",
"sentencepiece>=0.2.0",
"openai",
"sniffio",
"tqdm>4"
],
extras_require={
"chinese": [
"ordered_set",
"pypinyin",
"cn2an",
"jieba",
],
},
entry_points={
"console_scripts": [
"agenticseek=main:main",
],
},
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
],
python_requires=">=3.9",
)
================================================
FILE: sources/agents/__init__.py
================================================
from .agent import Agent
from .code_agent import CoderAgent
from .casual_agent import CasualAgent
from .file_agent import FileAgent
from .planner_agent import PlannerAgent
from .browser_agent import BrowserAgent
from .mcp_agent import McpAgent
__all__ = ["Agent", "CoderAgent", "CasualAgent", "FileAgent", "PlannerAgent", "BrowserAgent", "McpAgent"]
================================================
FILE: sources/agents/agent.py
================================================
from typing import Tuple, Callable
from abc import abstractmethod
import os
import random
import time
import asyncio
from concurrent.futures import ThreadPoolExecutor
from sources.memory import Memory
from sources.utility import pretty_print
from sources.schemas import executorResult
random.seed(time.time())
class Agent():
"""
An abstract class for all agents.
"""
def __init__(self, name: str,
prompt_path:str,
provider,
verbose=False,
browser=None) -> None:
"""
Args:
name (str): Name of the agent.
prompt_path (str): Path to the prompt file for the agent.
provider: The provider for the LLM.
recover_last_session (bool, optional): Whether to recover the last conversation.
verbose (bool, optional): Enable verbose logging if True. Defaults to False.
browser: The browser class for web navigation (only for browser agent).
"""
self.agent_name = name
self.browser = browser
self.role = None
self.type = None
self.current_directory = os.getcwd()
self.llm = provider
self.memory = None
self.tools = {}
self.blocks_result = []
self.success = True
self.last_answer = ""
self.last_reasoning = ""
self.status_message = "Haven't started yet"
self.stop = False
self.verbose = verbose
self.executor = ThreadPoolExecutor(max_workers=1)
@property
def get_agent_name(self) -> str:
return self.agent_name
@property
def get_agent_type(self) -> str:
return self.type
@property
def get_agent_role(self) -> str:
return self.role
@property
def get_last_answer(self) -> str:
return self.last_answer
@property
def get_last_reasoning(self) -> str:
return self.last_reasoning
@property
def get_blocks(self) -> list:
return self.blocks_result
@property
def get_status_message(self) -> str:
return self.status_message
@property
def get_tools(self) -> dict:
return self.tools
@property
def get_success(self) -> bool:
return self.success
def get_blocks_result(self) -> list:
return self.blocks_result
def add_tool(self, name: str, tool: Callable) -> None:
if tool is not Callable:
raise TypeError("Tool must be a callable object (a method)")
self.tools[name] = tool
def get_tools_name(self) -> list:
"""
Get the list of tools names.
"""
return list(self.tools.keys())
def get_tools_description(self) -> str:
"""
Get the list of tools names and their description.
"""
description = ""
for name in self.get_tools_name():
description += f"{name}: {self.tools[name].description}\n"
return description
def load_prompt(self, file_path: str) -> str:
try:
with open(file_path, 'r', encoding="utf-8") as f:
return f.read()
except FileNotFoundError:
raise FileNotFoundError(f"Prompt file not found at path: {file_path}")
except PermissionError:
raise PermissionError(f"Permission denied to read prompt file at path: {file_path}")
except Exception as e:
raise e
def request_stop(self) -> None:
"""
Request the agent to stop.
"""
self.stop = True
self.status_message = "Stopped"
@abstractmethod
def process(self, prompt, speech_module) -> str:
"""
abstract method, implementation in child class.
Process the prompt and return the answer of the agent.
"""
pass
def remove_reasoning_text(self, text: str) -> None:
"""
Remove the reasoning block of reasoning model like deepseek.
"""
end_tag = ""
end_idx = text.rfind(end_tag)
if end_idx == -1:
return text
return text[end_idx+8:]
def extract_reasoning_text(self, text: str) -> None:
"""
Extract the reasoning block of a reasoning model like deepseek.
"""
start_tag = ""
end_tag = ""
if text is None:
return None
start_idx = text.find(start_tag)
end_idx = text.rfind(end_tag)+8
return text[start_idx:end_idx]
async def llm_request(self) -> Tuple[str, str]:
"""
Asynchronously ask the LLM to process the prompt.
"""
self.status_message = "Thinking..."
loop = asyncio.get_event_loop()
return await loop.run_in_executor(self.executor, self.sync_llm_request)
def sync_llm_request(self) -> Tuple[str, str]:
"""
Ask the LLM to process the prompt and return the answer and the reasoning.
"""
memory = self.memory.get()
thought = self.llm.respond(memory, self.verbose)
reasoning = self.extract_reasoning_text(thought)
answer = self.remove_reasoning_text(thought)
self.memory.push('assistant', answer)
return answer, reasoning
async def wait_message(self, speech_module):
if speech_module is None:
return
messages = ["Please be patient, I am working on it.",
"Computing... I recommand you have a coffee while I work.",
"Hold on, I’m crunching numbers.",
"Working on it, please let me think."]
loop = asyncio.get_event_loop()
return await loop.run_in_executor(self.executor, lambda: speech_module.speak(messages[random.randint(0, len(messages)-1)]))
def get_last_tool_type(self) -> str:
return self.blocks_result[-1].tool_type if len(self.blocks_result) > 0 else None
def raw_answer_blocks(self, answer: str) -> str:
"""
Return the answer with all the blocks inserted, as text.
"""
if self.last_answer is None:
return
raw = ""
lines = self.last_answer.split("\n")
for line in lines:
if "block:" in line:
block_idx = int(line.split(":")[1])
if block_idx < len(self.blocks_result):
raw += self.blocks_result[block_idx].__str__()
else:
raw += line + "\n"
return raw
def show_answer(self):
"""
Show the answer in a pretty way.
Show code blocks and their respective feedback by inserting them in the ressponse.
"""
if self.last_answer is None:
return
lines = self.last_answer.split("\n")
for line in lines:
if "block:" in line:
block_idx = int(line.split(":")[1])
if block_idx < len(self.blocks_result):
self.blocks_result[block_idx].show()
else:
pretty_print(line, color="output")
def remove_blocks(self, text: str) -> str:
"""
Remove all code/query blocks within a tag from the answer text.
"""
tag = f'```'
lines = text.split('\n')
post_lines = []
in_block = False
block_idx = 0
for line in lines:
if tag in line and not in_block:
in_block = True
continue
if not in_block:
post_lines.append(line)
if tag in line:
in_block = False
post_lines.append(f"block:{block_idx}")
block_idx += 1
return "\n".join(post_lines)
def show_block(self, block: str) -> None:
"""
Show the block in a pretty way.
"""
pretty_print('▂'*64, color="status")
pretty_print(block, color="code")
pretty_print('▂'*64, color="status")
def execute_modules(self, answer: str) -> Tuple[bool, str]:
"""
Execute all the tools the agent has and return the result.
"""
feedback = ""
success = True
blocks = None
if answer.startswith("```"):
answer = "I will execute:\n" + answer # there should always be a text before blocks for the function that display answer
self.success = True
for name, tool in self.tools.items():
feedback = ""
blocks, save_path = tool.load_exec_block(answer)
if blocks != None:
pretty_print(f"Executing {len(blocks)} {name} blocks...", color="status")
for block in blocks:
self.show_block(block)
output = tool.execute([block])
feedback = tool.interpreter_feedback(output) # tool interpreter feedback
success = not tool.execution_failure_check(output)
self.blocks_result.append(executorResult(block, feedback, success, name))
if not success:
self.success = False
self.memory.push('user', feedback)
return False, feedback
self.memory.push('user', feedback)
if save_path != None:
tool.save_block(blocks, save_path)
return True, feedback
================================================
FILE: sources/agents/browser_agent.py
================================================
import re
import time
from datetime import date
from typing import List, Tuple, Type, Dict
from enum import Enum
import asyncio
from sources.utility import pretty_print, animate_thinking
from sources.agents.agent import Agent
from sources.tools.searxSearch import searxSearch
from sources.browser import Browser
from sources.logger import Logger
from sources.memory import Memory
class Action(Enum):
REQUEST_EXIT = "REQUEST_EXIT"
FORM_FILLED = "FORM_FILLED"
GO_BACK = "GO_BACK"
NAVIGATE = "NAVIGATE"
SEARCH = "SEARCH"
class BrowserAgent(Agent):
def __init__(self, name, prompt_path, provider, verbose=False, browser=None):
"""
The Browser agent is an agent that navigate the web autonomously in search of answer
"""
super().__init__(name, prompt_path, provider, verbose, browser)
self.tools = {
"web_search": searxSearch(),
}
self.role = "web"
self.type = "browser_agent"
self.browser = browser
self.current_page = ""
self.search_history = []
self.navigable_links = []
self.last_action = Action.NAVIGATE.value
self.notes = []
self.date = self.get_today_date()
self.logger = Logger("browser_agent.log")
self.memory = Memory(self.load_prompt(prompt_path),
recover_last_session=False, # session recovery in handled by the interaction class
memory_compression=False,
model_provider=provider.get_model_name() if provider else None)
def get_today_date(self) -> str:
"""Get the date"""
date_time = date.today()
return date_time.strftime("%B %d, %Y")
def extract_links(self, search_result: str) -> List[str]:
"""Extract all links from a sentence."""
pattern = r'(https?://\S+|www\.\S+)'
matches = re.findall(pattern, search_result)
trailing_punct = ".,!?;:)"
cleaned_links = [link.rstrip(trailing_punct) for link in matches]
self.logger.info(f"Extracted links: {cleaned_links}")
return self.clean_links(cleaned_links)
def extract_form(self, text: str) -> List[str]:
"""Extract form written by the LLM in format [input_name](value)"""
inputs = []
matches = re.findall(r"\[\w+\]\([^)]+\)", text)
return matches
def clean_links(self, links: List[str]) -> List[str]:
"""Ensure no '.' at the end of link"""
links_clean = []
for link in links:
link = link.strip()
if not (link[-1].isalpha() or link[-1].isdigit()):
links_clean.append(link[:-1])
else:
links_clean.append(link)
return links_clean
def get_unvisited_links(self) -> List[str]:
return "\n".join([f"[{i}] {link}" for i, link in enumerate(self.navigable_links) if link not in self.search_history])
def make_newsearch_prompt(self, prompt: str, search_result: dict) -> str:
search_choice = self.stringify_search_results(search_result)
self.logger.info(f"Search results: {search_choice}")
return f"""
Based on the search result:
{search_choice}
Your goal is to find accurate and complete information to satisfy the user’s request.
User request: {prompt}
To proceed, choose a relevant link from the search results. Announce your choice by saying: "I will navigate to "
Do not explain your choice.
"""
def make_navigation_prompt(self, user_prompt: str, page_text: str) -> str:
remaining_links = self.get_unvisited_links()
remaining_links_text = remaining_links if remaining_links is not None else "No links remaining, do a new search."
inputs_form = self.browser.get_form_inputs()
inputs_form_text = '\n'.join(inputs_form)
notes = '\n'.join(self.notes)
self.logger.info(f"Making navigation prompt with page text: {page_text[:100]}...\nremaining links: {remaining_links_text}")
self.logger.info(f"Inputs form: {inputs_form_text}")
self.logger.info(f"Notes: {notes}")
return f"""
You are navigating the web.
**Current Context**
Webpage ({self.current_page}) content:
{page_text}
Allowed Navigation Links:
{remaining_links_text}
Inputs forms:
{inputs_form_text}
End of webpage ({self.current_page}.
# Instruction
1. **Evaluate if the page is relevant for user’s query and document finding:**
- If the page is relevant, extract and summarize key information in concise notes (Note: )
- If page not relevant, state: "Error: " and either return to the previous page or navigate to a new link.
- Notes should be factual, useful summaries of relevant content, they should always include specific names or link. Written as: "On , . . ." Avoid phrases like "the page provides" or "I found that."
2. **Navigate to a link by either: **
- Saying I will navigate to (write down the full URL) www.example.com/cats
- Going back: If no link seems helpful, say: {Action.GO_BACK.value}.
3. **Fill forms on the page:**
- Fill form only when relevant.
- Use Login if username/password specified by user. For quick task create account, remember password in a note.
- You can fill a form using [form_name](value). Don't {Action.GO_BACK.value} when filling form.
- If a form is irrelevant or you lack informations (eg: don't know user email) leave it empty.
4. **Decide if you completed the task**
- Check your notes. Do they fully answer the question? Did you verify with multiple pages?
- Are you sure it’s correct?
- If yes to all, say {Action.REQUEST_EXIT}.
- If no, or a page lacks info, go to another link.
- Never stop or ask the user for help.
**Rules:**
- Do not write "The page talk about ...", write your finding on the page and how they contribute to an answer.
- Put note in a single paragraph.
- When you exit, explain why.
# Example:
Example 1 (useful page, no need go futher):
Note: According to karpathy site LeCun net is ...
No link seem useful to provide futher information.
Action: {Action.GO_BACK.value}
Example 2 (not useful, see useful link on page):
Error: reddit.com/welcome does not discuss anything related to the user’s query.
There is a link that could lead to the information.
Action: navigate to http://reddit.com/r/locallama
Example 3 (not useful, no related links):
Error: x.com does not discuss anything related to the user’s query and no navigation link are usefull.
Action: {Action.GO_BACK.value}
Example 3 (clear definitive query answer found or enought notes taken):
I took 10 notes so far with enought finding to answer user question.
Therefore I should exit the web browser.
Action: {Action.REQUEST_EXIT.value}
Example 4 (loging form visible):
Note: I am on the login page, I will type the given username and password.
Action:
[username_field](David)
[password_field](edgerunners77)
Remember, user asked:
{user_prompt}
You previously took these notes:
{notes}
Do not Step-by-Step explanation. Write comprehensive Notes or Error as a long paragraph followed by your action.
You must always take notes.
"""
async def llm_decide(self, prompt: str, show_reasoning: bool = False) -> Tuple[str, str]:
animate_thinking("Thinking...", color="status")
self.memory.push('user', prompt)
answer, reasoning = await self.llm_request()
self.last_reasoning = reasoning
if show_reasoning:
pretty_print(reasoning, color="failure")
pretty_print(answer, color="output")
return answer, reasoning
def select_unvisited(self, search_result: List[str]) -> List[str]:
results_unvisited = []
for res in search_result:
if res["link"] not in self.search_history:
results_unvisited.append(res)
self.logger.info(f"Unvisited links: {results_unvisited}")
return results_unvisited
def jsonify_search_results(self, results_string: str) -> List[str]:
result_blocks = results_string.split("\n\n")
parsed_results = []
for block in result_blocks:
if not block.strip():
continue
lines = block.split("\n")
result_dict = {}
for line in lines:
if line.startswith("Title:"):
result_dict["title"] = line.replace("Title:", "").strip()
elif line.startswith("Snippet:"):
result_dict["snippet"] = line.replace("Snippet:", "").strip()
elif line.startswith("Link:"):
result_dict["link"] = line.replace("Link:", "").strip()
if result_dict:
parsed_results.append(result_dict)
return parsed_results
def stringify_search_results(self, results_arr: List[str]) -> str:
return '\n\n'.join([f"Link: {res['link']}\nPreview: {res['snippet']}" for res in results_arr])
def parse_answer(self, text):
lines = text.split('\n')
saving = False
buffer = []
links = []
for line in lines:
if line == '' or 'action:' in line.lower():
saving = False
if "note" in line.lower():
saving = True
if saving:
buffer.append(line.replace("notes:", ''))
else:
links.extend(self.extract_links(line))
self.notes.append('. '.join(buffer).strip())
return links
def select_link(self, links: List[str]) -> str | None:
"""
Select the first unvisited link that is not the current page.
Preference is given to links not in search_history.
"""
for lk in links:
if lk == self.current_page or lk in self.search_history:
self.logger.info(f"Skipping already visited or current link: {lk}")
continue
self.logger.info(f"Selected link: {lk}")
return lk
self.logger.warning("No suitable link selected.")
return None
def get_page_text(self, limit_to_model_ctx = False) -> str:
"""Get the text content of the current page."""
page_text = self.browser.get_text()
if limit_to_model_ctx:
#page_text = self.memory.compress_text_to_max_ctx(page_text)
page_text = self.memory.trim_text_to_max_ctx(page_text)
return page_text
def conclude_prompt(self, user_query: str) -> str:
annotated_notes = [f"{i+1}: {note.lower()}" for i, note in enumerate(self.notes)]
search_note = '\n'.join(annotated_notes)
pretty_print(f"AI notes:\n{search_note}", color="success")
return f"""
Following a human request:
{user_query}
A web browsing AI made the following finding across different pages:
{search_note}
Expand on the finding or step that lead to success, and provide a conclusion that answer the request. Include link when possible.
Do not give advices or try to answer the human. Just structure the AI finding in a structured and clear way.
You should answer in the same language as the user.
"""
def search_prompt(self, user_prompt: str) -> str:
return f"""
Current date: {self.date}
Make a efficient search engine query to help users with their request:
{user_prompt}
Example:
User: "go to twitter, login with username toto and password pass79 to my twitter and say hello everyone "
You: search: Twitter login page.
User: "I need info on the best laptops for AI this year."
You: "search: best laptops 2025 to run Machine Learning model, reviews"
User: "Search for recent news about space missions."
You: "search: Recent space missions news, {self.date}"
Do not explain, do not write anything beside the search query.
Except if query does not make any sense for a web search then explain why and say {Action.REQUEST_EXIT.value}
Do not try to answer query. you can only formulate search term or exit.
"""
def handle_update_prompt(self, user_prompt: str, page_text: str, fill_success: bool) -> str:
prompt = f"""
You are a web browser.
You just filled a form on the page.
Now you should see the result of the form submission on the page:
Page text:
{page_text}
The user asked: {user_prompt}
Does the page answer the user’s query now? Are you still on a login page or did you get redirected?
If it does, take notes of the useful information, write down result and say {Action.FORM_FILLED.value}.
if it doesn’t, say: Error: Attempt to fill form didn't work {Action.GO_BACK.value}.
If you were previously on a login form, no need to take notes.
"""
if not fill_success:
prompt += f"""
According to browser feedback, the form was not filled correctly. Is that so? you might consider other strategies.
"""
return prompt
def show_search_results(self, search_result: List[str]):
pretty_print("\nSearch results:", color="output")
for res in search_result:
pretty_print(f"Title: {res['title']} - ", color="info", no_newline=True)
pretty_print(f"Link: {res['link']}", color="status")
def stuck_prompt(self, user_prompt: str, unvisited: List[str]) -> str:
"""
Prompt for when the agent repeat itself, can happen when fail to extract a link.
"""
prompt = self.make_newsearch_prompt(user_prompt, unvisited)
prompt += f"""
You previously said:
{self.last_answer}
You must consider other options. Choose other link.
"""
return prompt
async def process(self, user_prompt: str, speech_module: type) -> Tuple[str, str]:
"""
Process the user prompt to conduct an autonomous web search.
Start with a google search with searxng using web_search tool.
Then enter a navigation logic to find the answer or conduct required actions.
Args:
user_prompt: The user's input query
speech_module: Optional speech output module
Returns:
tuple containing the final answer and reasoning
"""
complete = False
animate_thinking(f"Thinking...", color="status")
mem_begin_idx = self.memory.push('user', self.search_prompt(user_prompt))
ai_prompt, reasoning = await self.llm_request()
if Action.REQUEST_EXIT.value in ai_prompt:
pretty_print(f"Web agent requested exit.\n{reasoning}\n\n{ai_prompt}", color="failure")
return ai_prompt, ""
animate_thinking(f"Searching...", color="status")
self.status_message = "Searching..."
search_result_raw = self.tools["web_search"].execute([ai_prompt], False)
search_result = self.jsonify_search_results(search_result_raw)[:16]
self.show_search_results(search_result)
prompt = self.make_newsearch_prompt(user_prompt, search_result)
unvisited = [None]
while not complete and len(unvisited) > 0 and not self.stop:
self.memory.clear()
unvisited = self.select_unvisited(search_result)
answer, reasoning = await self.llm_decide(prompt, show_reasoning = False)
if self.stop:
pretty_print(f"Requested stop.", color="failure")
break
if self.last_answer == answer:
prompt = self.stuck_prompt(user_prompt, unvisited)
continue
self.last_answer = answer
pretty_print('▂'*32, color="status")
extracted_form = self.extract_form(answer)
if len(extracted_form) > 0:
self.status_message = "Filling web form..."
pretty_print(f"Filling inputs form...", color="status")
fill_success = self.browser.fill_form(extracted_form)
page_text = self.get_page_text(limit_to_model_ctx=True)
answer = self.handle_update_prompt(user_prompt, page_text, fill_success)
answer, reasoning = await self.llm_decide(prompt)
if Action.FORM_FILLED.value in answer:
pretty_print(f"Filled form. Handling page update.", color="status")
page_text = self.get_page_text(limit_to_model_ctx=True)
self.navigable_links = self.browser.get_navigable()
prompt = self.make_navigation_prompt(user_prompt, page_text)
continue
links = self.parse_answer(answer)
link = self.select_link(links)
if link == self.current_page:
pretty_print(f"Already visited {link}. Search callback.", color="status")
prompt = self.make_newsearch_prompt(user_prompt, unvisited)
self.search_history.append(link)
continue
if Action.REQUEST_EXIT.value in answer:
self.status_message = "Exiting web browser..."
pretty_print(f"Agent requested exit.", color="status")
complete = True
break
if (link == None and len(extracted_form) < 3) or Action.GO_BACK.value in answer or link in self.search_history:
pretty_print(f"Going back to results. Still {len(unvisited)}", color="status")
self.status_message = "Going back to search results..."
request_prompt = user_prompt
if link is None:
request_prompt += f"\nYou previously choosen:\n{self.last_answer} but the website is unavailable. Consider other options."
prompt = self.make_newsearch_prompt(request_prompt, unvisited)
self.search_history.append(link)
self.current_page = link
continue
animate_thinking(f"Navigating to {link}", color="status")
if speech_module: speech_module.speak(f"Navigating to {link}")
nav_ok = self.browser.go_to(link)
self.search_history.append(link)
if not nav_ok:
pretty_print(f"Failed to navigate to {link}.", color="failure")
prompt = self.make_newsearch_prompt(user_prompt, unvisited)
continue
self.current_page = link
page_text = self.get_page_text(limit_to_model_ctx=True)
self.navigable_links = self.browser.get_navigable()
prompt = self.make_navigation_prompt(user_prompt, page_text)
self.status_message = "Navigating..."
self.browser.screenshot()
pretty_print("Exited navigation, starting to summarize finding...", color="status")
prompt = self.conclude_prompt(user_prompt)
mem_last_idx = self.memory.push('user', prompt)
self.status_message = "Summarizing findings..."
answer, reasoning = await self.llm_request()
pretty_print(answer, color="output")
self.status_message = "Ready"
self.last_answer = answer
return answer, reasoning
if __name__ == "__main__":
pass
================================================
FILE: sources/agents/casual_agent.py
================================================
import asyncio
from sources.utility import pretty_print, animate_thinking
from sources.agents.agent import Agent
from sources.tools.searxSearch import searxSearch
from sources.tools.flightSearch import FlightSearch
from sources.tools.fileFinder import FileFinder
from sources.tools.BashInterpreter import BashInterpreter
from sources.memory import Memory
class CasualAgent(Agent):
def __init__(self, name, prompt_path, provider, verbose=False):
"""
The casual agent is a special for casual talk to the user without specific tasks.
"""
super().__init__(name, prompt_path, provider, verbose, None)
self.tools = {
} # No tools for the casual agent
self.role = "talk"
self.type = "casual_agent"
self.memory = Memory(self.load_prompt(prompt_path),
recover_last_session=False, # session recovery in handled by the interaction class
memory_compression=False,
model_provider=provider.get_model_name())
async def process(self, prompt, speech_module) -> str:
self.memory.push('user', prompt)
animate_thinking("Thinking...", color="status")
answer, reasoning = await self.llm_request()
self.last_answer = answer
self.status_message = "Ready"
return answer, reasoning
if __name__ == "__main__":
pass
================================================
FILE: sources/agents/code_agent.py
================================================
import platform, os
import asyncio
from sources.utility import pretty_print, animate_thinking
from sources.agents.agent import Agent, executorResult
from sources.tools.C_Interpreter import CInterpreter
from sources.tools.GoInterpreter import GoInterpreter
from sources.tools.PyInterpreter import PyInterpreter
from sources.tools.BashInterpreter import BashInterpreter
from sources.tools.JavaInterpreter import JavaInterpreter
from sources.tools.fileFinder import FileFinder
from sources.logger import Logger
from sources.memory import Memory
class CoderAgent(Agent):
"""
The code agent is an agent that can write and execute code.
"""
def __init__(self, name, prompt_path, provider, verbose=False):
super().__init__(name, prompt_path, provider, verbose, None)
self.tools = {
"bash": BashInterpreter(),
"python": PyInterpreter(),
"c": CInterpreter(),
"go": GoInterpreter(),
"java": JavaInterpreter(),
"file_finder": FileFinder()
}
self.work_dir = self.tools["file_finder"].get_work_dir()
self.role = "code"
self.type = "code_agent"
self.logger = Logger("code_agent.log")
self.memory = Memory(self.load_prompt(prompt_path),
recover_last_session=False, # session recovery in handled by the interaction class
memory_compression=False,
model_provider=provider.get_model_name())
def add_sys_info_prompt(self, prompt):
"""Add system information to the prompt."""
info = f"System Info:\n" \
f"OS: {platform.system()} {platform.release()}\n" \
f"Python Version: {platform.python_version()}\n" \
f"\nYou must save file at root directory: {self.work_dir}"
return f"{prompt}\n\n{info}"
async def process(self, prompt, speech_module) -> str:
answer = ""
attempt = 0
max_attempts = 5
prompt = self.add_sys_info_prompt(prompt)
self.memory.push('user', prompt)
clarify_trigger = "REQUEST_CLARIFICATION"
while attempt < max_attempts and not self.stop:
print("Stopped?", self.stop)
animate_thinking("Thinking...", color="status")
await self.wait_message(speech_module)
answer, reasoning = await self.llm_request()
self.last_reasoning = reasoning
if clarify_trigger in answer:
self.last_answer = answer
await asyncio.sleep(0)
return answer, reasoning
if not "```" in answer:
self.last_answer = answer
await asyncio.sleep(0)
break
self.show_answer()
animate_thinking("Executing code...", color="status")
self.status_message = "Executing code..."
self.logger.info(f"Attempt {attempt + 1}:\n{answer}")
exec_success, feedback = self.execute_modules(answer)
self.logger.info(f"Execution result: {exec_success}")
answer = self.remove_blocks(answer)
self.last_answer = answer
await asyncio.sleep(0)
if exec_success and self.get_last_tool_type() != "bash":
break
pretty_print(f"Execution failure:\n{feedback}", color="failure")
pretty_print("Correcting code...", color="status")
self.status_message = "Correcting code..."
attempt += 1
self.status_message = "Ready"
if attempt == max_attempts:
return "I'm sorry, I couldn't find a solution to your problem. How would you like me to proceed ?", reasoning
self.last_answer = answer
return answer, reasoning
if __name__ == "__main__":
pass
================================================
FILE: sources/agents/file_agent.py
================================================
import asyncio
from sources.utility import pretty_print, animate_thinking
from sources.agents.agent import Agent
from sources.tools.fileFinder import FileFinder
from sources.tools.BashInterpreter import BashInterpreter
from sources.memory import Memory
class FileAgent(Agent):
def __init__(self, name, prompt_path, provider, verbose=False):
"""
The file agent is a special agent for file operations.
"""
super().__init__(name, prompt_path, provider, verbose, None)
self.tools = {
"file_finder": FileFinder(),
"bash": BashInterpreter()
}
self.work_dir = self.tools["file_finder"].get_work_dir()
self.role = "files"
self.type = "file_agent"
self.memory = Memory(self.load_prompt(prompt_path),
recover_last_session=False, # session recovery in handled by the interaction class
memory_compression=False,
model_provider=provider.get_model_name())
async def process(self, prompt, speech_module) -> str:
exec_success = False
prompt += f"\nYou must work in directory: {self.work_dir}"
self.memory.push('user', prompt)
while exec_success is False and not self.stop:
await self.wait_message(speech_module)
animate_thinking("Thinking...", color="status")
answer, reasoning = await self.llm_request()
self.last_reasoning = reasoning
exec_success, _ = self.execute_modules(answer)
answer = self.remove_blocks(answer)
self.last_answer = answer
self.status_message = "Ready"
return answer, reasoning
if __name__ == "__main__":
pass
================================================
FILE: sources/agents/mcp_agent.py
================================================
import os
import asyncio
from sources.utility import pretty_print, animate_thinking
from sources.agents.agent import Agent
from sources.tools.mcpFinder import MCP_finder
from sources.memory import Memory
# NOTE MCP agent is an active work in progress, not functional yet.
class McpAgent(Agent):
def __init__(self, name, prompt_path, provider, verbose=False):
"""
The mcp agent is a special agent for using MCPs.
MCP agent will be disabled if the user does not explicitly set the MCP_FINDER_API_KEY in environment variable.
"""
super().__init__(name, prompt_path, provider, verbose, None)
keys = self.get_api_keys()
self.tools = {
"mcp_finder": MCP_finder(keys["mcp_finder"]),
# add mcp tools here
}
self.role = "mcp"
self.type = "mcp_agent"
self.memory = Memory(self.load_prompt(prompt_path),
recover_last_session=False, # session recovery in handled by the interaction class
memory_compression=False,
model_provider=provider.get_model_name())
self.enabled = True
def get_api_keys(self) -> dict:
"""
Returns the API keys for the tools.
"""
api_key_mcp_finder = os.getenv("MCP_FINDER_API_KEY")
if not api_key_mcp_finder or api_key_mcp_finder == "":
pretty_print("MCP Finder disabled.", color="warning")
self.enabled = False
return {
"mcp_finder": api_key_mcp_finder
}
def expand_prompt(self, prompt):
"""
Expands the prompt with the tools available.
"""
tools_str = self.get_tools_description()
prompt += f"""
You can use the following tools and MCPs:
{tools_str}
"""
return prompt
async def process(self, prompt, speech_module) -> str:
if self.enabled == False:
return "MCP Agent is disabled."
prompt = self.expand_prompt(prompt)
self.memory.push('user', prompt)
working = True
while working == True:
animate_thinking("Thinking...", color="status")
answer, reasoning = await self.llm_request()
exec_success, _ = self.execute_modules(answer)
answer = self.remove_blocks(answer)
self.last_answer = answer
self.status_message = "Ready"
if len(self.blocks_result) == 0:
working = False
return answer, reasoning
if __name__ == "__main__":
pass
================================================
FILE: sources/agents/planner_agent.py
================================================
import json
from typing import List, Tuple, Type, Dict
from sources.utility import pretty_print, animate_thinking
from sources.agents.agent import Agent
from sources.agents.code_agent import CoderAgent
from sources.agents.file_agent import FileAgent
from sources.agents.browser_agent import BrowserAgent
from sources.agents.casual_agent import CasualAgent
from sources.text_to_speech import Speech
from sources.tools.tools import Tools
from sources.logger import Logger
from sources.memory import Memory
class PlannerAgent(Agent):
def __init__(self, name, prompt_path, provider, verbose=False, browser=None):
"""
The planner agent is a special agent that divides and conquers the task.
"""
super().__init__(name, prompt_path, provider, verbose, None)
self.tools = {
"json": Tools()
}
self.tools['json'].tag = "json"
self.browser = browser
self.agents = {
"coder": CoderAgent(name, "prompts/base/coder_agent.txt", provider, verbose=False),
"file": FileAgent(name, "prompts/base/file_agent.txt", provider, verbose=False),
"web": BrowserAgent(name, "prompts/base/browser_agent.txt", provider, verbose=False, browser=browser),
"casual": CasualAgent(name, "prompts/base/casual_agent.txt", provider, verbose=False)
}
self.role = "planification"
self.type = "planner_agent"
self.memory = Memory(self.load_prompt(prompt_path),
recover_last_session=False, # session recovery in handled by the interaction class
memory_compression=False,
model_provider=provider.get_model_name())
self.logger = Logger("planner_agent.log")
def get_task_names(self, text: str) -> List[str]:
"""
Extracts task names from the given text.
This method processes a multi-line string, where each line may represent a task name.
containing '##' or starting with a digit. The valid task names are collected and returned.
Args:
text (str): A string containing potential task titles (eg: Task 1: I will...).
Returns:
List[str]: A list of extracted task names that meet the specified criteria.
"""
tasks_names = []
lines = text.strip().split('\n')
for line in lines:
if line is None:
continue
line = line.strip()
if len(line) == 0:
continue
if '##' in line or line[0].isdigit():
tasks_names.append(line)
continue
self.logger.info(f"Found {len(tasks_names)} tasks names.")
return tasks_names
def parse_agent_tasks(self, text: str) -> List[Tuple[str, str]]:
"""
Parses agent tasks from the given LLM text.
This method extracts task information from a JSON. It identifies task names and their details.
Args:
text (str): The input text containing task information in a JSON-like format.
Returns:
List[Tuple[str, str]]: A list of tuples containing task names and their details.
"""
tasks = []
tasks_names = self.get_task_names(text)
blocks, _ = self.tools["json"].load_exec_block(text)
if blocks == None:
return []
for block in blocks:
try:
line_json = json.loads(block)
except json.JSONDecodeError as e:
self.logger.warning(f"Failed to parse JSON block: {e}")
pretty_print(f"JSON parsing error: {e}", color="warning")
return []
if 'plan' in line_json:
for task in line_json['plan']:
if task['agent'].lower() not in [ag_name.lower() for ag_name in self.agents.keys()]:
self.logger.warning(f"Agent {task['agent']} does not exist.")
pretty_print(f"Agent {task['agent']} does not exist.", color="warning")
return []
try:
agent = {
'agent': task['agent'],
'id': task['id'],
'task': task['task']
}
except:
self.logger.warning("Missing field in json plan.")
return []
self.logger.info(f"Created agent {task['agent']} with task: {task['task']}")
if 'need' in task:
self.logger.info(f"Agent {task['agent']} was given info:\n {task['need']}")
agent['need'] = task['need']
tasks.append(agent)
if len(tasks_names) != len(tasks):
names = [task['task'] for task in tasks]
return list(map(list, zip(names, tasks)))
return list(map(list, zip(tasks_names, tasks)))
def make_prompt(self, task: str, agent_infos_dict: dict) -> str:
"""
Generates a prompt for the agent based on the task and previous agents work information.
Args:
task (str): The task to be performed.
agent_infos_dict (dict): A dictionary containing information from other agents.
Returns:
str: The formatted prompt for the agent.
"""
infos = ""
if agent_infos_dict is None or len(agent_infos_dict) == 0:
infos = "No needed informations."
else:
for agent_id, info in agent_infos_dict.items():
infos += f"\t- According to agent {agent_id}:\n{info}\n\n"
prompt = f"""
You are given informations from your AI friends work:
{infos}
Your task is:
{task}
"""
self.logger.info(f"Prompt for agent:\n{prompt}")
return prompt
def show_plan(self, agents_tasks: List[dict], answer: str) -> None:
"""
Displays the plan made by the agent.
Args:
agents_tasks (dict): The tasks assigned to each agent.
answer (str): The answer from the LLM.
"""
if agents_tasks == []:
pretty_print(answer, color="warning")
pretty_print("Failed to make a plan. This can happen with (too) small LLM. Clarify your request and insist on it making a plan within ```json.", color="failure")
return
pretty_print("\n▂▘ P L A N ▝▂", color="status")
for task_name, task in agents_tasks:
pretty_print(f"{task['agent']} -> {task['task']}", color="info")
pretty_print("▔▗ E N D ▖▔", color="status")
async def make_plan(self, prompt: str) -> str:
"""
Asks the LLM to make a plan.
Args:
prompt (str): The prompt to be sent to the LLM.
Returns:
str: The plan made by the LLM.
"""
ok = False
answer = None
while not ok:
animate_thinking("Thinking...", color="status")
self.memory.push('user', prompt)
answer, reasoning = await self.llm_request()
if "NO_UPDATE" in answer:
return []
agents_tasks = self.parse_agent_tasks(answer)
if agents_tasks == []:
self.show_plan(agents_tasks, answer)
prompt = f"Failed to parse the tasks. Please write down your task followed by a json plan within ```json. Do not ask for clarification.\n"
pretty_print("Failed to make plan. Retrying...", color="warning")
continue
self.show_plan(agents_tasks, answer)
ok = True
self.logger.info(f"Plan made:\n{answer}")
return self.parse_agent_tasks(answer)
async def update_plan(self, goal: str, agents_tasks: List[dict], agents_work_result: dict, id: str, success: bool) -> dict:
"""
Updates the plan with the results of the agents work.
Args:
goal (str): The goal to be achieved.
agents_tasks (list): The tasks assigned to each agent.
agents_work_result (dict): The results of the agents work.
Returns:
dict: The updated plan.
"""
self.status_message = "Updating plan..."
last_agent_work = agents_work_result[id]
tool_success_str = "success" if success else "failure"
pretty_print(f"Agent {id} work {tool_success_str}.", color="success" if success else "failure")
try:
id_int = int(id)
except Exception as e:
return agents_tasks
if id_int == len(agents_tasks):
next_task = "No task follow, this was the last step. If it failed add a task to recover."
else:
next_task = f"Next task is: {agents_tasks[int(id)][0]}."
#if success:
# return agents_tasks # we only update the plan if last task failed, for now
update_prompt = f"""
Your goal is : {goal}
You previously made a plan, agents are currently working on it.
The last agent working on task: {id}, did the following work:
{last_agent_work}
Agent {id} work was a {tool_success_str} according to system interpreter.
{next_task}
Is the work done for task {id} leading to success or failure ? Did an agent fail with a task?
If agent work was good: answer "NO_UPDATE"
If agent work is leading to failure: update the plan.
If a task failed add a task to try again or recover from failure. You might have near identical task twice.
plan should be within ```json like before.
You need to rewrite the whole plan, but only change the tasks after task {id}.
Make the plan the same length as the original one or with only one additional step.
Do not change past tasks. Change next tasks.
"""
pretty_print("Updating plan...", color="status")
plan = await self.make_plan(update_prompt)
if plan == []:
pretty_print("No plan update required.", color="info")
return agents_tasks
self.logger.info(f"Plan updated:\n{plan}")
return plan
async def start_agent_process(self, task: dict, required_infos: dict | None) -> str:
"""
Starts the agent process for a given task.
Args:
task (dict): The task to be performed.
required_infos (dict | None): The required information for the task.
Returns:
str: The result of the agent process.
"""
self.status_message = f"Starting task {task['task']}..."
agent_prompt = self.make_prompt(task['task'], required_infos)
pretty_print(f"Agent {task['agent']} started working...", color="status")
self.logger.info(f"Agent {task['agent']} started working on {task['task']}.")
answer, reasoning = await self.agents[task['agent'].lower()].process(agent_prompt, None)
self.last_answer = answer
self.last_reasoning = reasoning
self.blocks_result = self.agents[task['agent'].lower()].blocks_result
agent_answer = self.agents[task['agent'].lower()].raw_answer_blocks(answer)
success = self.agents[task['agent'].lower()].get_success
self.agents[task['agent'].lower()].show_answer()
pretty_print(f"Agent {task['agent']} completed task.", color="status")
self.logger.info(f"Agent {task['agent']} finished working on {task['task']}. Success: {success}")
agent_answer += "\nAgent succeeded with task." if success else "\nAgent failed with task (Error detected)."
return agent_answer, success
def get_work_result_agent(self, task_needs, agents_work_result):
res = {k: agents_work_result[k] for k in task_needs if k in agents_work_result}
self.logger.info(f"Next agent needs: {task_needs}.\n Match previous agent result: {res}")
return res
async def process(self, goal: str, speech_module: Speech) -> Tuple[str, str]:
"""
Process the goal by dividing it into tasks and assigning them to agents.
Args:
goal (str): The goal to be achieved (user prompt).
speech_module (Speech): The speech module for text-to-speech.
Returns:
Tuple[str, str]: The result of the agent process and empty reasoning string.
"""
agents_tasks = []
required_infos = None
agents_work_result = dict()
self.status_message = "Making a plan..."
agents_tasks = await self.make_plan(goal)
if agents_tasks == []:
return "Failed to parse the tasks.", ""
i = 0
steps = len(agents_tasks)
while i < steps and not self.stop:
task_name, task = agents_tasks[i][0], agents_tasks[i][1]
self.status_message = "Starting agents..."
pretty_print(f"I will {task_name}.", color="info")
self.last_answer = f"I will {task_name.lower()}."
pretty_print(f"Assigned agent {task['agent']} to {task_name}", color="info")
if speech_module: speech_module.speak(f"I will {task_name}. I assigned the {task['agent']} agent to the task.")
if agents_work_result is not None:
required_infos = self.get_work_result_agent(task['need'], agents_work_result)
try:
answer, success = await self.start_agent_process(task, required_infos)
except Exception as e:
raise e
if self.stop:
pretty_print(f"Requested stop.", color="failure")
agents_work_result[task['id']] = answer
agents_tasks = await self.update_plan(goal, agents_tasks, agents_work_result, task['id'], success)
steps = len(agents_tasks)
i += 1
return answer, ""
================================================
FILE: sources/browser.py
================================================
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, WebDriverException
from selenium.webdriver.common.action_chains import ActionChains
from typing import List, Tuple, Type, Dict
from bs4 import BeautifulSoup
from urllib.parse import urlparse
from fake_useragent import UserAgent
from selenium_stealth import stealth
import undetected_chromedriver as uc
import chromedriver_autoinstaller
import certifi
import ssl
import subprocess
import time
import random
import os
import shutil
import uuid
import tempfile
import markdownify
import sys
import re
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from sources.utility import pretty_print, animate_thinking
from sources.logger import Logger
def get_chrome_path() -> str:
"""Get the path to the Chrome executable."""
if sys.platform.startswith("win"):
paths = [
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
os.path.join(os.environ.get("LOCALAPPDATA", ""), "Google\\Chrome\\Application\\chrome.exe") # User install
]
elif sys.platform.startswith("darwin"): # macOS
paths = ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta"]
else: # Linux
paths = ["/usr/bin/google-chrome",
"/opt/chrome/chrome",
"/usr/bin/chromium-browser",
"/usr/bin/chromium",
"/usr/local/bin/chrome",
"/opt/google/chrome/chrome-headless-shell",
#"/app/chrome_bundle/chrome136/chrome-linux64"
]
for path in paths:
if os.path.exists(path) and os.access(path, os.X_OK):
return path
print("Looking for Google Chrome in these locations failed:")
print('\n'.join(paths))
chrome_path_env = os.environ.get("CHROME_EXECUTABLE_PATH")
if chrome_path_env and os.path.exists(chrome_path_env) and os.access(chrome_path_env, os.X_OK):
return chrome_path_env
path = input("Google Chrome not found. Please enter the path to the Chrome executable: ")
if os.path.exists(path) and os.access(path, os.X_OK):
os.environ["CHROME_EXECUTABLE_PATH"] = path
print(f"Chrome path saved to environment variable CHROME_EXECUTABLE_PATH")
return path
return None
def get_random_user_agent() -> str:
"""Get a random user agent string with associated vendor."""
user_agents = [
{"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", "vendor": "Google Inc."},
{"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", "vendor": "Apple Inc."},
{"ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", "vendor": "Google Inc."},
]
return random.choice(user_agents)
def get_chromedriver_version(chromedriver_path: str) -> str:
"""Get the major version of a chromedriver binary. Returns empty string on failure."""
try:
result = subprocess.run(
[chromedriver_path, "--version"],
capture_output=True, text=True, timeout=10
)
# Output format: "ChromeDriver 125.0.6422.78 (...)"
return result.stdout.strip().split()[1].split('.')[0]
except Exception:
return ""
def is_chromedriver_compatible(chromedriver_path: str) -> bool:
"""Check if a chromedriver binary is compatible with the installed Chrome version."""
try:
chrome_version = chromedriver_autoinstaller.get_chrome_version()
if not chrome_version:
return True # Can't determine Chrome version, assume compatible
chrome_major = chrome_version.split('.')[0]
driver_major = get_chromedriver_version(chromedriver_path)
if not driver_major:
return True # Can't determine driver version, assume compatible
return chrome_major == driver_major
except Exception:
return True # On any error, assume compatible to avoid blocking
def install_chromedriver() -> str:
"""
Install the ChromeDriver if not already installed. Return the path.
Automatically updates the driver if the version does not match the installed Chrome.
"""
# First try to use chromedriver in the project root directory (as per README)
project_root_chromedriver = "./chromedriver"
if os.path.exists(project_root_chromedriver) and os.access(project_root_chromedriver, os.X_OK):
if is_chromedriver_compatible(project_root_chromedriver):
print(f"Using ChromeDriver from project root: {project_root_chromedriver}")
return project_root_chromedriver
print("ChromeDriver in project root is outdated, attempting auto-update...")
# Then try to use the system-installed chromedriver
chromedriver_path = shutil.which("chromedriver")
if chromedriver_path:
if is_chromedriver_compatible(chromedriver_path):
return chromedriver_path
print(f"System ChromeDriver at {chromedriver_path} is outdated, attempting auto-update...")
# In Docker environment, try the fixed path
if os.path.exists('/.dockerenv'):
docker_chromedriver_path = "/usr/local/bin/chromedriver"
if os.path.exists(docker_chromedriver_path) and os.access(docker_chromedriver_path, os.X_OK):
print(f"Using Docker ChromeDriver at {docker_chromedriver_path}")
return docker_chromedriver_path
# Auto-install matching ChromeDriver version
try:
print("Installing matching ChromeDriver version automatically...")
chromedriver_path = chromedriver_autoinstaller.install()
except Exception as e:
raise FileNotFoundError(
"ChromeDriver not found and could not be installed automatically. "
"Please install it manually from https://chromedriver.chromium.org/downloads."
"and ensure it's in your PATH or specify the path directly."
"See know issues in readme if your chrome version is above 115."
) from e
if not chromedriver_path:
raise FileNotFoundError("ChromeDriver not found. Please install it or add it to your PATH.")
return chromedriver_path
def bypass_ssl() -> str:
"""
This is a fallback for stealth mode to bypass SSL verification. Which can fail on some setup.
"""
pretty_print("Bypassing SSL verification issues, we strongly advice you update your certifi SSL certificate.", color="warning")
ssl._create_default_https_context = ssl._create_unverified_context
def create_chrome_options(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx", lang="en") -> Options:
"""Create Chrome options - separated for reusability."""
chrome_options = Options()
chrome_path = get_chrome_path()
if not chrome_path:
raise FileNotFoundError("Google Chrome not found. Please install it.")
chrome_options.binary_location = chrome_path
if headless:
chrome_options.add_argument("--headless=new")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--disable-webgl")
user_agent = get_random_user_agent()
width, height = (1920, 1080)
profile_dir = f"/tmp/chrome_profile_{uuid.uuid4().hex[:8]}"
# Core options
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument(f'--user-data-dir={profile_dir}')
chrome_options.add_argument(f"--accept-lang={lang}-{lang.upper()},{lang};q=0.9")
chrome_options.add_argument("--disable-extensions")
chrome_options.add_argument("--disable-background-timer-throttling")
chrome_options.add_argument("--timezone=Europe/Paris")
chrome_options.add_argument('--remote-debugging-port=9222')
chrome_options.add_argument('--disable-background-timer-throttling')
chrome_options.add_argument('--disable-backgrounding-occluded-windows')
chrome_options.add_argument('--disable-renderer-backgrounding')
chrome_options.add_argument('--disable-features=TranslateUI')
chrome_options.add_argument('--disable-ipc-flooding-protection')
chrome_options.add_argument("--mute-audio")
chrome_options.add_argument("--disable-notifications")
chrome_options.add_argument("--autoplay-policy=user-gesture-required")
chrome_options.add_argument("--disable-features=SitePerProcess,IsolateOrigins")
chrome_options.add_argument("--enable-features=NetworkService,NetworkServiceInProcess")
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_argument(f'user-agent={user_agent["ua"]}')
chrome_options.add_argument(f'--window-size={width},{height}')
if not stealth_mode:
if not os.path.exists(crx_path):
pretty_print(f"Anti-captcha CRX not found at {crx_path}.", color="failure")
else:
chrome_options.add_extension(crx_path)
if not stealth_mode:
security_prefs = {
"profile.default_content_setting_values.geolocation": 0,
"profile.default_content_setting_values.notifications": 0,
"profile.default_content_setting_values.camera": 0,
"profile.default_content_setting_values.microphone": 0,
"profile.default_content_setting_values.midi_sysex": 0,
"profile.default_content_setting_values.clipboard": 0,
"profile.default_content_setting_values.media_stream": 0,
"profile.default_content_setting_values.background_sync": 0,
"profile.default_content_setting_values.sensors": 0,
"profile.default_content_setting_values.accessibility_events": 0,
"safebrowsing.enabled": True,
"credentials_enable_service": False,
"profile.password_manager_enabled": False,
"webkit.webprefs.accelerated_2d_canvas_enabled": True,
"webkit.webprefs.force_dark_mode_enabled": False,
"webkit.webprefs.accelerated_2d_canvas_msaa_sample_count": 4,
"enable_webgl": True,
"enable_webgl2_compute_context": True
}
chrome_options.add_experimental_option("prefs", security_prefs)
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
return chrome_options
def create_undetected_chromedriver(service, chrome_options) -> webdriver.Chrome:
"""Create an undetected ChromeDriver instance with proper error handling."""
try:
driver = uc.Chrome(service=service, options=chrome_options)
except Exception as e:
pretty_print(f"Failed to create Chrome driver: {str(e)}. Trying to bypass SSL...", color="failure")
try:
bypass_ssl()
# Create NEW options object - this is the key fix
fresh_options = create_chrome_options(
headless=any("--headless" in arg for arg in chrome_options.arguments),
stealth_mode=True, # We're in stealth mode if we reach this point
crx_path="./crx/nopecha.crx" # Default path
)
driver = uc.Chrome(service=service, options=fresh_options)
except Exception as e:
pretty_print(f"Failed to create Chrome driver, fallback failed:\n{str(e)}.", color="failure")
raise e
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
return driver
def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx", lang="en") -> webdriver.Chrome:
"""Create a Chrome WebDriver with specified options."""
# Warn if trying to run non-headless in Docker
if not headless and os.path.exists('/.dockerenv'):
print("[WARNING] Running non-headless browser in Docker may fail!")
print("[WARNING] Consider setting headless=True or headless_browser=True in config.ini")
chrome_options = create_chrome_options(headless, stealth_mode, crx_path, lang)
chromedriver_path = install_chromedriver()
service = Service(chromedriver_path)
if stealth_mode:
driver = create_undetected_chromedriver(service, chrome_options)
user_agent = get_random_user_agent()
stealth(driver,
languages=["en-US", "en"],
vendor=user_agent["vendor"],
platform="Win64" if "windows" in user_agent["ua"].lower() else "MacIntel" if "mac" in user_agent["ua"].lower() else "Linux x86_64",
webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine",
fix_hairline=True,
)
return driver
else:
return webdriver.Chrome(service=service, options=chrome_options)
class Browser:
def __init__(self, driver, anticaptcha_manual_install=False):
"""Initialize the browser with optional AntiCaptcha installation."""
self.js_scripts_folder = "./sources/web_scripts/" if not __name__ == "__main__" else "./web_scripts/"
self.anticaptcha = "https://chrome.google.com/webstore/detail/nopecha-captcha-solver/dknlfmjaanfblgfdfebhijalfmhmjjjo/related"
self.logger = Logger("browser.log")
self.screenshot_folder = os.path.join(os.getcwd(), ".screenshots")
self.tabs = []
try:
self.driver = driver
self.wait = WebDriverWait(self.driver, 10)
except Exception as e:
raise Exception(f"Failed to initialize browser: {str(e)}")
self.setup_tabs()
self.patch_browser_fingerprint()
if anticaptcha_manual_install:
self.load_anticatpcha_manually()
def setup_tabs(self):
self.tabs = self.driver.window_handles
try:
self.driver.get("https://www.google.com")
except Exception as e:
self.logger.log(f"Failed to setup initial tab:" + str(e))
pass
self.screenshot()
def switch_control_tab(self):
self.logger.log("Switching to control tab.")
self.driver.switch_to.window(self.tabs[0])
def load_anticatpcha_manually(self):
pretty_print("You might want to install the AntiCaptcha extension for captchas.", color="warning")
try:
self.driver.get(self.anticaptcha)
except Exception as e:
self.logger.log(f"Failed to setup initial tab:" + str(e))
pass
def human_move(element):
actions = ActionChains(driver)
x_offset = random.randint(-5,5)
for _ in range(random.randint(2,5)):
actions.move_by_offset(x_offset, random.randint(-2,2))
actions.pause(random.uniform(0.1,0.3))
actions.click().perform()
def human_scroll(self):
for _ in range(random.randint(1, 3)):
scroll_pixels = random.randint(150, 1200)
self.driver.execute_script(f"window.scrollBy(0, {scroll_pixels});")
time.sleep(random.uniform(0.5, 2.0))
if random.random() < 0.4:
self.driver.execute_script(f"window.scrollBy(0, -{random.randint(50, 300)});")
time.sleep(random.uniform(0.3, 1.0))
def patch_browser_fingerprint(self) -> None:
script = self.load_js("spoofing.js")
self.driver.execute_script(script)
def go_to(self, url:str) -> bool:
"""Navigate to a specified URL."""
time.sleep(random.uniform(0.4, 2.5))
try:
initial_handles = self.driver.window_handles
self.driver.get(url)
time.sleep(random.uniform(0.01, 0.3))
try:
wait = WebDriverWait(self.driver, timeout=10)
wait.until(
lambda driver: (
not any(keyword in driver.page_source.lower() for keyword in ["checking your browser", "captcha"])
),
message="stuck on 'checking browser' or verification screen"
)
except TimeoutException:
self.logger.warning("Timeout while waiting for page to bypass 'checking your browser'")
self.apply_web_safety()
time.sleep(random.uniform(0.01, 0.2))
self.human_scroll()
self.logger.log(f"Navigated to: {url}")
return True
except TimeoutException as e:
self.logger.error(f"Timeout waiting for {url} to load: {str(e)}")
return False
except WebDriverException as e:
self.logger.error(f"Error navigating to {url}: {str(e)}")
return False
except Exception as e:
self.logger.error(f"Fatal error with go_to method on {url}:\n{str(e)}")
raise e
def is_sentence(self, text:str) -> bool:
"""Check if the text qualifies as a meaningful sentence or contains important error codes."""
text = text.strip()
if any(c.isdigit() for c in text):
return True
words = re.findall(r'\w+', text, re.UNICODE)
word_count = len(words)
has_punctuation = any(text.endswith(p) for p in ['.', ',', ',', '!', '?', '。', '!', '?', '।', '۔'])
is_long_enough = word_count > 4
return (word_count >= 5 and (has_punctuation or is_long_enough))
def get_text(self) -> str | None:
"""Get page text as formatted Markdown"""
try:
soup = BeautifulSoup(self.driver.page_source, 'html.parser')
for element in soup(['script', 'style', 'noscript', 'meta', 'link']):
element.decompose()
markdown_converter = markdownify.MarkdownConverter(
heading_style="ATX",
strip=['a'],
autolinks=False,
bullets='•',
strong_em_symbol='*',
default_title=False,
)
markdown_text = markdown_converter.convert(str(soup.body))
lines = []
for line in markdown_text.splitlines():
stripped = line.strip()
if stripped and self.is_sentence(stripped):
cleaned = ' '.join(stripped.split())
lines.append(cleaned)
result = "[Start of page]\n\n" + "\n\n".join(lines) + "\n\n[End of page]"
result = re.sub(r'!\[(.*?)\]\(.*?\)', r'[IMAGE: \1]', result)
self.logger.info(f"Extracted text: {result[:100]}...")
self.logger.info(f"Extracted text length: {len(result)}")
return result[:32768]
except Exception as e:
self.logger.error(f"Error getting text: {str(e)}")
return None
def clean_url(self, url:str) -> str:
"""Clean URL to keep only the part needed for navigation to the page"""
clean = url.split('#')[0]
parts = clean.split('?', 1)
base_url = parts[0]
if len(parts) > 1:
query = parts[1]
essential_params = []
for param in query.split('&'):
if param.startswith('_skw=') or param.startswith('q=') or param.startswith('s='):
essential_params.append(param)
elif param.startswith('_') or param.startswith('hash=') or param.startswith('itmmeta='):
break
if essential_params:
return f"{base_url}?{'&'.join(essential_params)}"
return base_url
def is_link_valid(self, url:str) -> bool:
"""Check if a URL is a valid link (page, not related to icon or metadata)."""
if len(url) > 72:
self.logger.warning(f"URL too long: {url}")
return False
parsed_url = urlparse(url)
if not parsed_url.scheme or not parsed_url.netloc:
self.logger.warning(f"Invalid URL: {url}")
return False
if re.search(r'/\d+$', parsed_url.path):
return False
image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp']
metadata_extensions = ['.ico', '.xml', '.json', '.rss', '.atom']
for ext in image_extensions + metadata_extensions:
if url.lower().endswith(ext):
return False
return True
def get_navigable(self) -> List[str]:
"""Get all navigable links on the current page."""
try:
links = []
elements = self.driver.find_elements(By.TAG_NAME, "a")
for element in elements:
href = element.get_attribute("href")
if href and href.startswith(("http", "https")):
links.append({
"url": href,
"text": element.text.strip(),
"is_displayed": element.is_displayed()
})
self.logger.info(f"Found {len(links)} navigable links")
return [self.clean_url(link['url']) for link in links if (link['is_displayed'] == True and self.is_link_valid(link['url']))]
except Exception as e:
self.logger.error(f"Error getting navigable links: {str(e)}")
return []
def click_element(self, xpath: str) -> bool:
"""Click an element specified by XPath."""
try:
element = self.wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
if not element.is_displayed():
return False
if not element.is_enabled():
return False
try:
self.logger.error(f"Scrolling to element for click_element.")
self.driver.execute_script("arguments[0].scrollIntoView({block: 'center', behavior: 'smooth'});", element)
time.sleep(0.1)
element.click()
self.logger.info(f"Clicked element at {xpath}")
return True
except ElementClickInterceptedException as e:
self.logger.error(f"Error click_element: {str(e)}")
return False
except TimeoutException:
self.logger.warning(f"Timeout clicking element.")
return False
except Exception as e:
self.logger.error(f"Unexpected error clicking element at {xpath}: {str(e)}")
return False
def load_js(self, file_name: str) -> str:
"""Load javascript from script folder to inject to page."""
path = os.path.join(self.js_scripts_folder, file_name)
self.logger.info(f"Loading js at {path}")
try:
with open(path, 'r') as f:
return f.read()
except FileNotFoundError as e:
raise Exception(f"Could not find: {path}") from e
except Exception as e:
raise e
def find_all_inputs(self, timeout=3):
"""Find all inputs elements on the page."""
try:
WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
except Exception as e:
self.logger.error(f"Error waiting for input element: {str(e)}")
return []
time.sleep(0.5)
script = self.load_js("find_inputs.js")
input_elements = self.driver.execute_script(script)
return input_elements
def get_form_inputs(self) -> List[str]:
"""Extract all input from the page and return them."""
try:
input_elements = self.find_all_inputs()
if not input_elements:
self.logger.info("No input element on page.")
return ["No input forms found on the page."]
form_strings = []
for element in input_elements:
input_type = element.get("type") or "text"
if input_type in ["hidden", "submit", "button", "image"] or not element["displayed"]:
continue
input_name = element.get("text") or element.get("id") or input_type
if input_type == "select":
options = element.get("options", [])
options_str = ", ".join(opt["text"] for opt in options if opt["text"])
selected = next((opt["text"] for opt in options if opt.get("selected")), "")
form_strings.append(f"[{input_name}](select: {selected}) options: [{options_str}]")
elif input_type == "textarea":
form_strings.append(f"[{input_name}]("")")
elif input_type == "file":
form_strings.append(f"[{input_name}](file: )")
elif input_type == "checkbox" or input_type == "radio":
try:
checked_status = "checked" if element.is_selected() else "unchecked"
except Exception as e:
continue
form_strings.append(f"[{input_name}]({checked_status})")
else:
form_strings.append(f"[{input_name}]("")")
return form_strings
except Exception as e:
raise e
def get_buttons_xpath(self) -> List[str]:
"""
Find buttons and return their type and xpath.
"""
buttons = self.driver.find_elements(By.TAG_NAME, "button") + \
self.driver.find_elements(By.XPATH, "//input[@type='submit']")
result = []
for i, button in enumerate(buttons):
if not button.is_displayed() or not button.is_enabled():
continue
text = (button.text or button.get_attribute("value") or "").lower().replace(' ', '')
xpath = f"(//button | //input[@type='submit'])[{i + 1}]"
result.append((text, xpath))
result.sort(key=lambda x: len(x[0]))
return result
def wait_for_submission_outcome(self, timeout: int = 10) -> bool:
"""
Wait for a submission outcome (e.g., URL change or new element).
"""
try:
self.logger.info("Waiting for submission outcome...")
wait = WebDriverWait(self.driver, timeout)
wait.until(
lambda driver: driver.current_url != self.driver.current_url or
driver.find_elements(By.XPATH, "//*[contains(text(), 'success')]")
)
self.logger.info("Detected submission outcome")
return True
except TimeoutException:
self.logger.warning("No submission outcome detected")
return False
def find_and_click_btn(self, btn_type: str = 'login', timeout: int = 5) -> bool:
"""Find and click a submit button matching the specified type."""
buttons = self.get_buttons_xpath()
if not buttons:
self.logger.warning("No visible buttons found")
return False
for button_text, xpath in buttons:
if btn_type.lower() in button_text.lower() or btn_type.lower() in xpath.lower():
try:
wait = WebDriverWait(self.driver, timeout)
element = wait.until(
EC.element_to_be_clickable((By.XPATH, xpath)),
message=f"Button with XPath '{xpath}' not clickable within {timeout} seconds"
)
if self.click_element(xpath):
self.logger.info(f"Clicked button '{button_text}' at XPath: {xpath}")
return True
else:
self.logger.warning(f"Button '{button_text}' at XPath: {xpath} not clickable")
return False
except TimeoutException:
self.logger.warning(f"Timeout waiting for '{button_text}' button at XPath: {xpath}")
return False
except Exception as e:
self.logger.error(f"Error clicking button '{button_text}' at XPath: {xpath} - {str(e)}")
return False
self.logger.warning(f"No button matching '{btn_type}' found")
return False
def tick_all_checkboxes(self) -> bool:
"""
Find and tick all checkboxes on the page.
Returns True if successful, False if any issues occur.
"""
try:
checkboxes = self.driver.find_elements(By.XPATH, "//input[@type='checkbox']")
if not checkboxes:
self.logger.info("No checkboxes found on the page")
return True
for index, checkbox in enumerate(checkboxes, 1):
try:
WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable(checkbox)
)
self.driver.execute_script(
"arguments[0].scrollIntoView({block: 'center', inline: 'center'});", checkbox
)
if not checkbox.is_selected():
try:
checkbox.click()
self.logger.info(f"Ticked checkbox {index}")
except ElementClickInterceptedException:
self.driver.execute_script("arguments[0].click();", checkbox)
self.logger.warning(f"Click checkbox {index} intercepted")
else:
self.logger.info(f"Checkbox {index} already ticked")
except TimeoutException:
self.logger.warning(f"Timeout waiting for checkbox {index} to be clickable")
continue
except Exception as e:
self.logger.error(f"Error ticking checkbox {index}: {str(e)}")
continue
return True
except Exception as e:
self.logger.error(f"Error finding checkboxes: {str(e)}")
return False
def find_and_click_submission(self, timeout: int = 10) -> bool:
possible_submissions = ["login", "submit", "register", "continue", "apply",
"ok", "confirm", "proceed", "accept",
"done", "finish", "start", "calculate"]
for submission in possible_submissions:
if self.find_and_click_btn(submission, timeout):
self.logger.info(f"Clicked on submission button: {submission}")
return True
self.logger.warning("No submission button found")
return False
def find_input_xpath_by_name(self, inputs, name: str) -> str | None:
for field in inputs:
if name in field["text"]:
return field["xpath"]
return None
def fill_form_inputs(self, input_list: List[str]) -> bool:
"""Fill inputs based on a list of [name](value) strings."""
if not isinstance(input_list, list):
self.logger.error("input_list must be a list")
return False
inputs = self.find_all_inputs()
try:
for input_str in input_list:
match = re.match(r'\[(.*?)\]\((.*?)\)', input_str)
if not match:
self.logger.warning(f"Invalid format for input: {input_str}")
continue
name, value = match.groups()
name = name.strip()
value = value.strip()
xpath = self.find_input_xpath_by_name(inputs, name)
if not xpath:
self.logger.warning(f"Input field '{name}' not found")
continue
try:
element = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.XPATH, xpath))
)
except TimeoutException:
self.logger.error(f"Timeout waiting for element '{name}' to be clickable")
continue
self.driver.execute_script("arguments[0].scrollIntoView(true);", element)
if not element.is_displayed() or not element.is_enabled():
self.logger.warning(f"Element '{name}' is not interactable (not displayed or disabled)")
continue
input_type = (element.get_attribute("type") or "text").lower()
tag_name = (element.tag_name or "").lower()
if tag_name == "select":
try:
select = Select(element)
select.select_by_visible_text(value)
self.logger.info(f"Selected '{value}' for {name}")
except Exception:
try:
select.select_by_value(value)
self.logger.info(f"Selected value '{value}' for {name}")
except Exception as sel_e:
self.logger.warning(f"Could not select '{value}' for {name}: {sel_e}")
elif tag_name == "textarea":
element.clear()
element.send_keys(value)
self.logger.info(f"Filled textarea {name}")
elif input_type == "file":
if os.path.isabs(value) and os.path.exists(value):
element.send_keys(value)
self.logger.info(f"Uploaded file '{value}' for {name}")
else:
self.logger.warning(f"File not found: {value}")
elif input_type in ["checkbox", "radio"]:
is_checked = element.is_selected()
should_be_checked = value.lower() == "checked"
if is_checked != should_be_checked:
element.click()
self.logger.info(f"Set {name} to {value}")
else:
element.clear()
element.send_keys(value)
self.logger.info(f"Filled {name} with {value}")
return True
except Exception as e:
self.logger.error(f"Error filling form inputs: {str(e)}")
return False
def fill_form(self, input_list: List[str]) -> bool:
"""Fill form inputs based on a list of [name](value) and submit."""
if not isinstance(input_list, list):
self.logger.error("input_list must be a list")
return False
if self.fill_form_inputs(input_list):
self.logger.info("Form filled successfully")
self.tick_all_checkboxes()
if self.find_and_click_submission():
if self.wait_for_submission_outcome():
self.logger.info("Submission outcome detected")
return True
else:
self.logger.warning("No submission outcome detected")
else:
self.logger.warning("Failed to submit form")
self.logger.warning("Failed to fill form inputs")
return False
def get_current_url(self) -> str:
"""Get the current URL of the page."""
return self.driver.current_url
def get_page_title(self) -> str:
"""Get the title of the current page."""
return self.driver.title
def scroll_bottom(self) -> bool:
"""Scroll to the bottom of the page."""
try:
self.logger.info("Scrolling to the bottom of the page...")
self.driver.execute_script(
"window.scrollTo(0, document.body.scrollHeight);"
)
time.sleep(0.5)
return True
except Exception as e:
self.logger.error(f"Error scrolling: {str(e)}")
return False
def get_screenshot(self) -> str:
return self.screenshot_folder + "/updated_screen.png"
def screenshot(self, filename:str = 'updated_screen.png') -> bool:
"""Take a screenshot of the current page, attempt to capture the full page by zooming out."""
self.logger.info("Taking full page screenshot...")
time.sleep(0.1)
try:
original_zoom = self.driver.execute_script("return document.body.style.zoom || 1;")
self.driver.execute_script("document.body.style.zoom='75%'")
time.sleep(0.1)
path = os.path.join(self.screenshot_folder, filename)
if not os.path.exists(self.screenshot_folder):
os.makedirs(self.screenshot_folder)
self.driver.save_screenshot(path)
self.logger.info(f"Full page screenshot saved as {filename}")
except Exception as e:
self.logger.error(f"Error taking full page screenshot: {str(e)}")
return False
finally:
self.driver.execute_script(f"document.body.style.zoom='1'")
return True
def apply_web_safety(self):
"""
Apply security measures to block any website malicious/annoying execution, privacy violation etc..
"""
self.logger.info("Applying web safety measures...")
script = self.load_js("inject_safety_script.js")
input_elements = self.driver.execute_script(script)
if __name__ == "__main__":
driver = create_driver(headless=False, stealth_mode=True, crx_path="../crx/nopecha.crx")
browser = Browser(driver, anticaptcha_manual_install=True)
input("press enter to continue")
print("AntiCaptcha / Form Test")
browser.go_to("https://bot.sannysoft.com")
time.sleep(5)
#txt = browser.get_text()
browser.go_to("https://home.openweathermap.org/users/sign_up")
inputs_visible = browser.get_form_inputs()
print("inputs:", inputs_visible)
#inputs_fill = ['[q](checked)', '[q](checked)', '[user[username]](mlg)', '[user[email]](mlg.fcu@gmail.com)', '[user[password]](placeholder_P@ssw0rd123)', '[user[password_confirmation]](placeholder_P@ssw0rd123)']
#browser.fill_form(inputs_fill)
input("press enter to exit")
# Test sites for browser fingerprinting and captcha
# https://nowsecure.nl/
# https://bot.sannysoft.com
# https://browserleaks.com/
# https://bot.incolumitas.com/
# https://fingerprintjs.github.io/fingerprintjs/
# https://antoinevastel.com/bots/
================================================
FILE: sources/interaction.py
================================================
import readline
from typing import List, Tuple, Type, Dict
from sources.text_to_speech import Speech
from sources.utility import pretty_print, animate_thinking
from sources.router import AgentRouter
from sources.speech_to_text import AudioTranscriber, AudioRecorder
import threading
class Interaction:
"""
Interaction is a class that handles the interaction between the user and the agents.
"""
def __init__(self, agents,
tts_enabled: bool = True,
stt_enabled: bool = True,
recover_last_session: bool = False,
langs: List[str] = ["en", "zh"]
):
self.is_active = True
self.current_agent = None
self.last_query = None
self.last_answer = None
self.last_reasoning = None
self.agents = agents
self.tts_enabled = tts_enabled
self.stt_enabled = stt_enabled
self.recover_last_session = recover_last_session
self.router = AgentRouter(self.agents, supported_language=langs)
self.ai_name = self.find_ai_name()
self.speech = None
self.transcriber = None
self.recorder = None
self.is_generating = False
self.languages = langs
if tts_enabled:
self.initialize_tts()
if stt_enabled:
self.initialize_stt()
if recover_last_session:
self.load_last_session()
self.emit_status()
def get_spoken_language(self) -> str:
"""Get the primary TTS language."""
lang = self.languages[0]
return lang
def initialize_tts(self):
"""Initialize TTS."""
if not self.speech:
animate_thinking("Initializing text-to-speech...", color="status")
self.speech = Speech(enable=self.tts_enabled, language=self.get_spoken_language(), voice_idx=1)
def initialize_stt(self):
"""Initialize STT."""
if not self.transcriber or not self.recorder:
animate_thinking("Initializing speech recognition...", color="status")
self.transcriber = AudioTranscriber(self.ai_name, verbose=False)
self.recorder = AudioRecorder()
def emit_status(self):
"""Print the current status of agenticSeek."""
if self.stt_enabled:
pretty_print(f"Text-to-speech trigger is {self.ai_name}", color="status")
if self.tts_enabled:
self.speech.speak("Hello, we are online and ready. What can I do for you ?")
pretty_print("AgenticSeek is ready.", color="status")
def find_ai_name(self) -> str:
"""Find the name of the default AI. It is required for STT as a trigger word."""
ai_name = "jarvis"
for agent in self.agents:
if agent.type == "casual_agent":
ai_name = agent.agent_name
break
return ai_name
def get_last_blocks_result(self) -> List[Dict]:
"""Get the last blocks result."""
if self.current_agent is None:
return []
blks = []
for agent in self.agents:
blks.extend(agent.get_blocks_result())
return blks
def load_last_session(self):
"""Recover the last session."""
for agent in self.agents:
if agent.type == "planner_agent":
continue
agent.memory.load_memory(agent.type)
def save_session(self):
"""Save the current session."""
for agent in self.agents:
agent.memory.save_memory(agent.type)
def is_active(self) -> bool:
return self.is_active
def read_stdin(self) -> str:
"""Read the input from the user."""
buffer = ""
PROMPT = "\033[1;35m➤➤➤ \033[0m"
while not buffer:
try:
buffer = input(PROMPT)
except EOFError:
return None
if buffer == "exit" or buffer == "goodbye":
return None
return buffer
def transcription_job(self) -> str:
"""Transcribe the audio from the microphone."""
self.recorder = AudioRecorder(verbose=True)
self.transcriber = AudioTranscriber(self.ai_name, verbose=True)
self.transcriber.start()
self.recorder.start()
self.recorder.join()
self.transcriber.join()
query = self.transcriber.get_transcript()
if query == "exit" or query == "goodbye":
return None
return query
def get_user(self) -> str:
"""Get the user input from the microphone or the keyboard."""
if self.stt_enabled:
query = "TTS transcription of user: " + self.transcription_job()
else:
query = self.read_stdin()
if query is None:
self.is_active = False
self.last_query = None
return None
self.last_query = query
return query
def set_query(self, query: str) -> None:
"""Set the query"""
self.is_active = True
self.last_query = query
async def think(self) -> bool:
"""Request AI agents to process the user input."""
push_last_agent_memory = False
if self.last_query is None or len(self.last_query) == 0:
return False
agent = self.router.select_agent(self.last_query)
if agent is None:
return False
if self.current_agent != agent and self.last_answer is not None:
push_last_agent_memory = True
tmp = self.last_answer
self.current_agent = agent
self.is_generating = True
self.last_answer, self.last_reasoning = await agent.process(self.last_query, self.speech)
self.is_generating = False
if push_last_agent_memory:
self.current_agent.memory.push('user', self.last_query)
self.current_agent.memory.push('assistant', self.last_answer)
if self.last_answer == tmp:
self.last_answer = None
return True
def get_updated_process_answer(self) -> str:
"""Get the answer from the last agent."""
if self.current_agent is None:
return None
return self.current_agent.get_last_answer()
def get_updated_block_answer(self) -> str:
"""Get the answer from the last agent."""
if self.current_agent is None:
return None
return self.current_agent.get_last_block_answer()
def speak_answer(self) -> None:
"""Speak the answer to the user in a non-blocking thread."""
if self.last_query is None:
return
if self.tts_enabled and self.last_answer and self.speech:
def speak_in_thread(speech_instance, text):
speech_instance.speak(text)
thread = threading.Thread(target=speak_in_thread, args=(self.speech, self.last_answer))
thread.start()
def show_answer(self) -> None:
"""Show the answer to the user."""
if self.last_query is None:
return
if self.current_agent is not None:
self.current_agent.show_answer()
================================================
FILE: sources/language.py
================================================
from typing import List, Tuple, Type, Dict
import re
import langid
from transformers import MarianMTModel, MarianTokenizer
from sources.utility import pretty_print, animate_thinking
from sources.logger import Logger
class LanguageUtility:
"""LanguageUtility for language, or emotion identification"""
def __init__(self, supported_language: List[str] = ["en", "fr", "zh"]):
"""
Initialize the LanguageUtility class
args:
supported_language: list of languages for translation, determine which Helsinki-NLP model to load
"""
self.translators_tokenizer = None
self.translators_model = None
self.logger = Logger("language.log")
self.supported_language = supported_language
self.load_model()
def load_model(self) -> None:
animate_thinking("Loading language utility...", color="status")
self.translators_tokenizer = {lang: MarianTokenizer.from_pretrained(f"Helsinki-NLP/opus-mt-{lang}-en") for lang in self.supported_language if lang != "en"}
self.translators_model = {lang: MarianMTModel.from_pretrained(f"Helsinki-NLP/opus-mt-{lang}-en") for lang in self.supported_language if lang != "en"}
def detect_language(self, text: str) -> str:
"""
Detect the language of the given text using langdetect
Limited to the supported languages list because of the model tendency to mistake similar languages
Args:
text: string to analyze
Returns: ISO639-1 language code
"""
langid.set_languages(self.supported_language)
lang, score = langid.classify(text)
self.logger.info(f"Identified: {text} as {lang} with conf {score}")
return lang
def translate(self, text: str, origin_lang: str) -> str:
"""
Translate the given text to English
Args:
text: string to translate
origin_lang: ISO language code
Returns: translated str
"""
if origin_lang == "en":
return text
if origin_lang not in self.translators_tokenizer:
pretty_print(f"Language {origin_lang} not supported for translation", color="error")
return text
tokenizer = self.translators_tokenizer[origin_lang]
inputs = tokenizer(text, return_tensors="pt", padding=True)
model = self.translators_model[origin_lang]
translation = model.generate(**inputs)
return tokenizer.decode(translation[0], skip_special_tokens=True)
def analyze(self, text):
"""
Combined analysis of language and emotion
Args:
text: string to analyze
Returns: dictionary with language related information
"""
try:
language = self.detect_language(text)
return {
"language": language
}
except Exception as e:
raise e
if __name__ == "__main__":
detector = LanguageUtility()
test_texts = [
"I am so happy today!",
"我不要去巴黎",
"La vie c'est cool"
]
for text in test_texts:
pretty_print("Analyzing...", color="status")
pretty_print(f"Language: {detector.detect_language(text)}", color="status")
result = detector.analyze(text)
trans = detector.translate(text, result['language'])
pretty_print(f"Translation: {trans} - from: {result['language']}")
================================================
FILE: sources/llm_provider.py
================================================
import os
import platform
import socket
import subprocess
import time
from urllib.parse import urlparse
import httpx
import requests
from dotenv import load_dotenv
from ollama import Client as OllamaClient
from openai import OpenAI
from sources.logger import Logger
from sources.utility import pretty_print, animate_thinking
class Provider:
def __init__(self, provider_name, model, server_address="127.0.0.1:5000", is_local=False):
self.provider_name = provider_name.lower()
self.model = model
self.is_local = is_local
self.server_ip = server_address
self.server_address = server_address
self.available_providers = {
"ollama": self.ollama_fn,
"server": self.server_fn,
"openai": self.openai_fn,
"lm-studio": self.lm_studio_fn,
"huggingface": self.huggingface_fn,
"google": self.google_fn,
"deepseek": self.deepseek_fn,
"together": self.together_fn,
"dsk_deepseek": self.dsk_deepseek,
"openrouter": self.openrouter_fn,
"minimax": self.minimax_fn,
"test": self.test_fn
}
self.logger = Logger("provider.log")
self.api_key = None
self.internal_url, self.in_docker = self.get_internal_url()
self.unsafe_providers = ["openai", "deepseek", "dsk_deepseek", "together", "google", "openrouter", "minimax"]
if self.provider_name not in self.available_providers:
raise ValueError(f"Unknown provider: {provider_name}")
if self.provider_name in self.unsafe_providers and self.is_local == False:
pretty_print("Warning: you are using an API provider. You data will be sent to the cloud.", color="warning")
self.api_key = self.get_api_key(self.provider_name)
elif self.provider_name != "ollama":
pretty_print(f"Provider: {provider_name} initialized at {self.server_ip}", color="success")
def get_model_name(self) -> str:
return self.model
def get_api_key(self, provider):
load_dotenv()
api_key_var = f"{provider.upper()}_API_KEY"
api_key = os.getenv(api_key_var)
if not api_key:
pretty_print(f"API key {api_key_var} not found in .env file. Please add it", color="warning")
exit(1)
return api_key
def get_internal_url(self):
load_dotenv()
url = os.getenv("DOCKER_INTERNAL_URL")
if not url: # running on host
return "http://localhost", False
return url, True
def respond(self, history, verbose=True):
"""
Use the choosen provider to generate text.
"""
llm = self.available_providers[self.provider_name]
self.logger.info(f"Using provider: {self.provider_name} at {self.server_ip}")
try:
thought = llm(history, verbose)
except KeyboardInterrupt:
self.logger.warning("User interrupted the operation with Ctrl+C")
return "Operation interrupted by user. REQUEST_EXIT"
except ConnectionError as e:
raise ConnectionError(f"{str(e)}\nConnection to {self.server_ip} failed.")
except AttributeError as e:
raise NotImplementedError(f"{str(e)}\nIs {self.provider_name} implemented ?")
except ModuleNotFoundError as e:
raise ModuleNotFoundError(
f"{str(e)}\nA import related to provider {self.provider_name} was not found. Is it installed ?")
except Exception as e:
if "try again later" in str(e).lower():
return f"{self.provider_name} server is overloaded. Please try again later."
if "refused" in str(e):
return f"Server {self.server_ip} seem offline. Unable to answer."
raise Exception(f"Provider {self.provider_name} failed: {str(e)}") from e
return thought
def is_ip_online(self, address: str, timeout: int = 10) -> bool:
"""
Check if an address is online by sending a ping request.
"""
if not address:
return False
parsed = urlparse(address if address.startswith(('http://', 'https://')) else f'http://{address}')
hostname = parsed.hostname or address
if "127.0.0.1" in address or "localhost" in address:
return True
try:
ip_address = socket.gethostbyname(hostname)
except socket.gaierror:
self.logger.error(f"Cannot resolve: {hostname}")
return False
param = '-n' if platform.system().lower() == 'windows' else '-c'
command = ['ping', param, '1', ip_address]
try:
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout)
return result.returncode == 0
except (subprocess.TimeoutExpired, subprocess.SubprocessError) as e:
return False
def server_fn(self, history, verbose=False):
"""
Use a remote server with LLM to generate text.
"""
thought = ""
route_setup = f"{self.server_ip}/setup"
route_gen = f"{self.server_ip}/generate"
if not self.is_ip_online(self.server_ip):
pretty_print(f"Server is offline at {self.server_ip}", color="failure")
try:
requests.post(route_setup, json={"model": self.model})
requests.post(route_gen, json={"messages": history})
is_complete = False
while not is_complete:
try:
response = requests.get(f"{self.server_ip}/get_updated_sentence")
if "error" in response.json():
pretty_print(response.json()["error"], color="failure")
break
thought = response.json()["sentence"]
is_complete = bool(response.json()["is_complete"])
time.sleep(2)
except requests.exceptions.RequestException as e:
pretty_print(f"HTTP request failed: {str(e)}", color="failure")
break
except ValueError as e:
pretty_print(f"Failed to parse JSON response: {str(e)}", color="failure")
break
except Exception as e:
pretty_print(f"An error occurred: {str(e)}", color="failure")
break
except KeyError as e:
raise Exception(
f"{str(e)}\nError occured with server route. Are you using the correct address for the config.ini provider?") from e
except Exception as e:
raise e
return thought
def ollama_fn(self, history, verbose=False):
"""
Use local or remote Ollama server to generate text.
"""
thought = ""
host = f"{self.internal_url}:11434" if self.is_local else f"http://{self.server_address}"
client = OllamaClient(host=host)
try:
stream = client.chat(
model=self.model,
messages=history,
stream=True,
)
for chunk in stream:
if verbose:
print(chunk["message"]["content"], end="", flush=True)
thought += chunk["message"]["content"]
except httpx.ConnectError as e:
raise Exception(
f"\nOllama connection failed at {host}. Check if the server is running."
) from e
except Exception as e:
if hasattr(e, 'status_code') and e.status_code == 404:
animate_thinking(f"Downloading {self.model}...")
client.pull(self.model)
self.ollama_fn(history, verbose)
if "refused" in str(e).lower():
raise Exception(
f"Ollama connection refused at {host}. Is the server running?"
) from e
raise e
return thought
def huggingface_fn(self, history, verbose=False):
"""
Use huggingface to generate text.
"""
from huggingface_hub import InferenceClient
client = InferenceClient(
api_key=self.get_api_key("huggingface")
)
completion = client.chat.completions.create(
model=self.model,
messages=history,
max_tokens=1024,
)
thought = completion.choices[0].message
return thought.content
def openai_fn(self, history, verbose=False):
"""
Use openai to generate text.
"""
base_url = self.server_ip
if self.is_local and self.in_docker:
try:
host, port = base_url.split(':')
except Exception as e:
port = "8000"
client = OpenAI(api_key=self.api_key, base_url=f"{self.internal_url}:{port}")
elif self.is_local:
client = OpenAI(api_key=self.api_key, base_url=f"http://{base_url}")
else:
client = OpenAI(api_key=self.api_key)
try:
response = client.chat.completions.create(
model=self.model,
messages=history,
)
if response is None:
raise Exception("OpenAI response is empty.")
thought = response.choices[0].message.content
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"OpenAI API error: {str(e)}") from e
def anthropic_fn(self, history, verbose=False):
"""
Use Anthropic to generate text.
"""
from anthropic import Anthropic
client = Anthropic(api_key=self.api_key)
system_message = None
messages = []
for message in history:
clean_message = {'role': message['role'], 'content': message['content']}
if message['role'] == 'system':
system_message = message['content']
else:
messages.append(clean_message)
try:
response = client.messages.create(
model=self.model,
max_tokens=1024,
messages=messages,
system=system_message
)
if response is None:
raise Exception("Anthropic response is empty.")
thought = response.content[0].text
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"Anthropic API error: {str(e)}") from e
def google_fn(self, history, verbose=False):
"""
Use google gemini to generate text.
"""
base_url = self.server_ip
if self.is_local:
raise Exception("Google Gemini is not available for local use. Change config.ini")
client = OpenAI(api_key=self.api_key, base_url="https://generativelanguage.googleapis.com/v1beta/openai/")
try:
response = client.chat.completions.create(
model=self.model,
messages=history,
)
if response is None:
raise Exception("Google response is empty.")
thought = response.choices[0].message.content
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"GOOGLE API error: {str(e)}") from e
def together_fn(self, history, verbose=False):
"""
Use together AI for completion
"""
from together import Together
client = Together(api_key=self.api_key)
if self.is_local:
raise Exception("Together AI is not available for local use. Change config.ini")
try:
response = client.chat.completions.create(
model=self.model,
messages=history,
)
if response is None:
raise Exception("Together AI response is empty.")
thought = response.choices[0].message.content
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"Together AI API error: {str(e)}") from e
def deepseek_fn(self, history, verbose=False):
"""
Use deepseek api to generate text.
"""
client = OpenAI(api_key=self.api_key, base_url="https://api.deepseek.com")
if self.is_local:
raise Exception("Deepseek (API) is not available for local use. Change config.ini")
try:
response = client.chat.completions.create(
model="deepseek-chat",
messages=history,
stream=False
)
thought = response.choices[0].message.content
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"Deepseek API error: {str(e)}") from e
def lm_studio_fn(self, history, verbose=False):
"""
Use local lm-studio server to generate text.
"""
if self.in_docker:
# Extract port from server_address if present
port = "1234" # default
if ":" in self.server_address:
port = self.server_address.split(":")[1]
url = f"{self.internal_url}:{port}"
else:
url = f"http://{self.server_ip}"
route_start = f"{url}/v1/chat/completions"
payload = {
"messages": history,
"temperature": 0.7,
"max_tokens": 4096,
"model": self.model
}
try:
response = requests.post(route_start, json=payload, timeout=30)
if response.status_code != 200:
raise Exception(f"LM Studio returned status {response.status_code}: {response.text}")
if not response.text.strip():
raise Exception("LM Studio returned empty response")
try:
result = response.json()
except ValueError as json_err:
raise Exception(f"Invalid JSON from LM Studio: {response.text[:200]}") from json_err
if verbose:
print("Response from LM Studio:", result)
choices = result.get("choices", [])
if not choices:
raise Exception(f"No choices in LM Studio response: {result}")
message = choices[0].get("message", {})
content = message.get("content", "")
if not content:
raise Exception(f"Empty content in LM Studio response: {result}")
return content
except requests.exceptions.Timeout:
raise Exception("LM Studio request timed out - check if server is responsive")
except requests.exceptions.ConnectionError:
raise Exception(f"Cannot connect to LM Studio at {route_start} - check if server is running")
except requests.exceptions.RequestException as e:
raise Exception(f"HTTP request failed: {str(e)}") from e
except Exception as e:
if "LM Studio" in str(e):
raise # Re-raise our custom exceptions
raise Exception(f"Unexpected error: {str(e)}") from e
return thought
def openrouter_fn(self, history, verbose=False):
"""
Use OpenRouter API to generate text.
"""
client = OpenAI(api_key=self.api_key, base_url="https://openrouter.ai/api/v1")
if self.is_local:
# This case should ideally not be reached if unsafe_providers is set correctly
# and is_local is False in config for openrouter
raise Exception("OpenRouter is not available for local use. Change config.ini")
try:
response = client.chat.completions.create(
model=self.model,
messages=history,
)
if response is None:
raise Exception("OpenRouter response is empty.")
thought = response.choices[0].message.content
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"OpenRouter API error: {str(e)}") from e
def minimax_fn(self, history, verbose=False):
"""
Use MiniMax API to generate text via OpenAI-compatible interface.
Supported models:
- MiniMax-M2.5: Peak performance model (~60 tps), 204,800 context window
- MiniMax-M2.5-highspeed: Same performance, faster (~100 tps)
Note: temperature must be in range (0.0, 1.0], default is 1.0
"""
load_dotenv()
base_url = os.getenv("MINIMAX_BASE_URL", "https://api.minimax.io/v1")
client = OpenAI(api_key=self.api_key, base_url=base_url)
if self.is_local:
raise Exception("MiniMax is not available for local use. Change config.ini")
try:
response = client.chat.completions.create(
model=self.model,
messages=history,
temperature=1.0,
)
if response is None:
raise Exception("MiniMax response is empty.")
thought = response.choices[0].message.content
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"MiniMax API error: {str(e)}") from e
def dsk_deepseek(self, history, verbose=False):
"""
Use: xtekky/deepseek4free
For free api. Api key should be set to DSK_DEEPSEEK_API_KEY
This is an unofficial provider, you'll have to find how to set it up yourself.
"""
from dsk.api import (
DeepSeekAPI,
AuthenticationError,
RateLimitError,
NetworkError,
CloudflareError,
APIError
)
thought = ""
message = '\n---\n'.join([f"{msg['role']}: {msg['content']}" for msg in history])
try:
api = DeepSeekAPI(self.api_key)
chat_id = api.create_chat_session()
for chunk in api.chat_completion(chat_id, message):
if chunk['type'] == 'text':
thought += chunk['content']
return thought
except AuthenticationError:
raise AuthenticationError("Authentication failed. Please check your token.") from e
except RateLimitError:
raise RateLimitError("Rate limit exceeded. Please wait before making more requests.") from e
except CloudflareError as e:
raise CloudflareError(f"Cloudflare protection encountered: {str(e)}") from e
except NetworkError:
raise NetworkError("Network error occurred. Check your internet connection.") from e
except APIError as e:
raise APIError(f"API error occurred: {str(e)}") from e
return None
def test_fn(self, history, verbose=True):
"""
This function is used to conduct tests.
"""
thought = """
\n\n```json\n{\n \"plan\": [\n {\n \"agent\": \"Web\",\n \"id\": \"1\",\n \"need\": null,\n \"task\": \"Conduct a comprehensive web search to identify at least five AI startups located in Osaka. Use reliable sources and websites such as Crunchbase, TechCrunch, or local Japanese business directories. Capture the company names, their websites, areas of expertise, and any other relevant details.\"\n },\n {\n \"agent\": \"Web\",\n \"id\": \"2\",\n \"need\": null,\n \"task\": \"Perform a similar search to find at least five AI startups in Tokyo. Again, use trusted sources like Crunchbase, TechCrunch, or Japanese business news websites. Gather the same details as for Osaka: company names, websites, areas of focus, and additional information.\"\n },\n {\n \"agent\": \"File\",\n \"id\": \"3\",\n \"need\": [\"1\", \"2\"],\n \"task\": \"Create a new text file named research_japan.txt in the user's home directory. Organize the data collected from both searches into this file, ensuring it is well-structured and formatted for readability. Include headers for Osaka and Tokyo sections, followed by the details of each startup found.\"\n }\n ]\n}\n```
"""
return thought
if __name__ == "__main__":
provider = Provider("server", "deepseek-r1:32b", " x.x.x.x:8080")
res = provider.respond(["user", "Hello, how are you?"])
print("Response:", res)
================================================
FILE: sources/logger.py
================================================
import os, sys
from typing import List, Tuple, Type, Dict
import datetime
import logging
class Logger:
def __init__(self, log_filename):
self.folder = '.logs'
self.create_folder(self.folder)
self.log_path = os.path.join(self.folder, log_filename)
self.enabled = True
self.logger = None
self.last_log_msg = ""
if self.enabled:
self.create_logging(log_filename)
def create_logging(self, log_filename):
self.logger = logging.getLogger(log_filename)
self.logger.setLevel(logging.DEBUG)
self.logger.handlers.clear()
self.logger.propagate = False
file_handler = logging.FileHandler(self.log_path)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
self.logger.addHandler(file_handler)
def create_folder(self, path):
"""Create log dir"""
try:
if not os.path.exists(path):
os.makedirs(path, exist_ok=True)
return True
except Exception as e:
self.enabled = False
return False
def log(self, message, level=logging.INFO):
if self.last_log_msg == message:
return
if self.enabled:
self.last_log_msg = message
self.logger.log(level, message)
def info(self, message):
self.log(message)
def error(self, message):
self.log(message, level=logging.ERROR)
def warning(self, message):
self.log(message, level=logging.WARN)
if __name__ == "__main__":
lg = Logger("test.log")
lg.log("hello")
lg2 = Logger("toto.log")
lg2.log("yo")
================================================
FILE: sources/memory.py
================================================
import time
import datetime
import uuid
import os
import sys
import json
from typing import List, Tuple, Type, Dict
import torch
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
import configparser
from sources.utility import timer_decorator, pretty_print, animate_thinking
from sources.logger import Logger
config = configparser.ConfigParser()
config.read('config.ini')
class Memory():
"""
Memory is a class for managing the conversation memory
It provides a method to compress the memory using summarization model.
"""
def __init__(self, system_prompt: str,
recover_last_session: bool = False,
memory_compression: bool = True,
model_provider: str = "deepseek-r1:14b"):
self.memory = [{'role': 'system', 'content': system_prompt}]
self.logger = Logger("memory.log")
self.session_time = datetime.datetime.now()
self.session_id = str(uuid.uuid4())
self.conversation_folder = f"conversations/"
self.session_recovered = False
if recover_last_session:
self.load_memory()
self.session_recovered = True
# memory compression system
self.model = None
self.tokenizer = None
self.device = self.get_cuda_device()
self.memory_compression = memory_compression
self.model_provider = model_provider
if self.memory_compression:
self.download_model()
def get_ideal_ctx(self, model_name: str) -> int | None:
"""
Estimate context size based on the model name.
EXPERIMENTAL for memory compression
"""
import re
import math
def extract_number_before_b(sentence: str) -> int:
match = re.search(r'(\d+)b', sentence, re.IGNORECASE)
return int(match.group(1)) if match else None
model_size = extract_number_before_b(model_name)
if not model_size:
return None
base_size = 7 # Base model size in billions
base_context = 4096 # Base context size in tokens
scaling_factor = 1.5 # Approximate scaling factor for context size growth
context_size = int(base_context * (model_size / base_size) ** scaling_factor)
context_size = 2 ** round(math.log2(context_size))
self.logger.info(f"Estimated context size for {model_name}: {context_size} tokens.")
return context_size
def download_model(self):
"""Download the model if not already downloaded."""
animate_thinking("Loading memory compression model...", color="status")
self.tokenizer = AutoTokenizer.from_pretrained("pszemraj/led-base-book-summary")
self.model = AutoModelForSeq2SeqLM.from_pretrained("pszemraj/led-base-book-summary")
self.logger.info("Memory compression system initialized.")
def get_filename(self) -> str:
"""Get the filename for the save file."""
return f"memory_{self.session_time.strftime('%Y-%m-%d_%H-%M-%S')}.txt"
def save_memory(self, agent_type: str = "casual_agent") -> None:
"""Save the session memory to a file."""
if not os.path.exists(self.conversation_folder):
self.logger.info(f"Created folder {self.conversation_folder}.")
os.makedirs(self.conversation_folder)
save_path = os.path.join(self.conversation_folder, agent_type)
if not os.path.exists(save_path):
os.makedirs(save_path)
filename = self.get_filename()
path = os.path.join(save_path, filename)
json_memory = json.dumps(self.memory)
with open(path, 'w') as f:
self.logger.info(f"Saved memory json at {path}")
f.write(json_memory)
def find_last_session_path(self, path) -> str:
"""Find the last session path."""
saved_sessions = []
for filename in os.listdir(path):
if filename.startswith('memory_'):
date = filename.split('_')[1]
saved_sessions.append((filename, date))
saved_sessions.sort(key=lambda x: x[1], reverse=True)
if len(saved_sessions) > 0:
self.logger.info(f"Last session found at {saved_sessions[0][0]}")
return saved_sessions[0][0]
return None
def save_json_file(self, path: str, json_memory: dict) -> None:
"""Save a JSON file."""
try:
with open(path, 'w') as f:
json.dump(json_memory, f)
self.logger.info(f"Saved memory json at {path}")
except Exception as e:
self.logger.warning(f"Error saving file {path}: {e}")
def load_json_file(self, path: str) -> dict:
"""Load a JSON file."""
json_memory = {}
try:
with open(path, 'r') as f:
json_memory = json.load(f)
except FileNotFoundError:
self.logger.warning(f"File not found: {path}")
return {}
except json.JSONDecodeError:
self.logger.warning(f"Error decoding JSON from file: {path}")
return {}
except Exception as e:
self.logger.warning(f"Error loading file {path}: {e}")
return {}
return json_memory
def load_memory(self, agent_type: str = "casual_agent") -> None:
"""Load the memory from the last session."""
if self.session_recovered == True:
return
pretty_print(f"Loading {agent_type} past memories... ", color="status")
save_path = os.path.join(self.conversation_folder, agent_type)
if not os.path.exists(save_path):
pretty_print("No memory to load.", color="success")
return
filename = self.find_last_session_path(save_path)
if filename is None:
pretty_print("Last session memory not found.", color="warning")
return
path = os.path.join(save_path, filename)
self.memory = self.load_json_file(path)
if self.memory[-1]['role'] == 'user':
self.memory.pop()
self.compress()
pretty_print("Session recovered successfully", color="success")
def reset(self, memory: list = []) -> None:
self.logger.info("Memory reset performed.")
self.memory = memory
def push(self, role: str, content: str) -> int:
"""Push a message to the memory."""
ideal_ctx = self.get_ideal_ctx(self.model_provider)
if ideal_ctx is not None:
if self.memory_compression and len(content) > ideal_ctx * 1.5:
self.logger.info(f"Compressing memory: Content {len(content)} > {ideal_ctx} model context.")
self.compress()
curr_idx = len(self.memory)
if self.memory[curr_idx-1]['content'] == content:
pretty_print("Warning: same message have been pushed twice to memory", color="error")
time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if config["MAIN"]["provider_name"] == "openrouter":
self.memory.append({'role': role, 'content': content})
else:
self.memory.append({'role': role, 'content': content, 'time': time_str, 'model_used': self.model_provider})
return curr_idx-1
def clear(self) -> None:
"""Clear all memory except system prompt"""
self.logger.info("Memory clear performed.")
self.memory = self.memory[:1]
def clear_section(self, start: int, end: int) -> None:
"""
Clear a section of the memory. Ignore system message index.
Args:
start (int): Starting bound of the section to clear.
end (int): Ending bound of the section to clear.
"""
self.logger.info(f"Clearing memory section {start} to {end}.")
start = max(0, start) + 1
end = min(end, len(self.memory)-1) + 2
self.memory = self.memory[:start] + self.memory[end:]
def get(self) -> list:
return self.memory
def get_cuda_device(self) -> str:
if torch.backends.mps.is_available():
return "mps"
elif torch.cuda.is_available():
return "cuda"
else:
return "cpu"
def summarize(self, text: str, min_length: int = 64) -> str:
"""
Summarize the text using the AI model.
Args:
text (str): The text to summarize
min_length (int, optional): The minimum length of the summary. Defaults to 64.
Returns:
str: The summarized text
"""
if self.tokenizer is None or self.model is None:
self.logger.warning("No tokenizer or model to perform summarization.")
return text
if len(text) < min_length*1.5:
return text
max_length = len(text) // 2 if len(text) > min_length*2 else min_length*2
input_text = "summarize: " + text
inputs = self.tokenizer(input_text, return_tensors="pt", max_length=512, truncation=True)
summary_ids = self.model.generate(
inputs['input_ids'],
max_length=max_length,
min_length=min_length,
length_penalty=1.0,
num_beams=4,
early_stopping=True
)
summary = self.tokenizer.decode(summary_ids[0], skip_special_tokens=True)
summary.replace('summary:', '')
self.logger.info(f"Memory summarized from len {len(text)} to {len(summary)}.")
self.logger.info(f"Summarized text:\n{summary}")
return summary
#@timer_decorator
def compress(self) -> str:
"""
Compress (summarize) the memory using the model.
"""
if self.tokenizer is None or self.model is None:
self.logger.warning("No tokenizer or model to perform memory compression.")
return
for i in range(len(self.memory)):
if self.memory[i]['role'] == 'system':
continue
if len(self.memory[i]['content']) > 1024:
self.memory[i]['content'] = self.summarize(self.memory[i]['content'])
def trim_text_to_max_ctx(self, text: str) -> str:
"""
Truncate a text to fit within the maximum context size of the model.
"""
ideal_ctx = self.get_ideal_ctx(self.model_provider)
return text[:ideal_ctx] if ideal_ctx is not None else text
#@timer_decorator
def compress_text_to_max_ctx(self, text) -> str:
"""
Compress a text to fit within the maximum context size of the model.
"""
if self.tokenizer is None or self.model is None:
self.logger.warning("No tokenizer or model to perform memory compression.")
return text
ideal_ctx = self.get_ideal_ctx(self.model_provider)
if ideal_ctx is None:
self.logger.warning("No ideal context size found.")
return text
while len(text) > ideal_ctx:
self.logger.info(f"Compressing text: {len(text)} > {ideal_ctx} model context.")
text = self.summarize(text)
return text
if __name__ == "__main__":
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
memory = Memory("You are a helpful assistant.",
recover_last_session=False, memory_compression=True)
memory.push('user', "hello")
memory.push('assistant', "how can i help you?")
memory.push('user', "why do i get this cuda error?")
sample_text = """
The error you're encountering:
cuda.cu:52:10: fatal error: helper_functions.h: No such file or directory
#include
indicates that the compiler cannot find the helper_functions.h file. This is because the #include directive is looking for the file in the system's include paths, but the file is either not in those paths or is located in a different directory.
1. Use #include "helper_functions.h" Instead of #include
Angle brackets (< >) are used for system or standard library headers.
Quotes (" ") are used for local or project-specific headers.
If helper_functions.h is in the same directory as cuda.cu, change the include directive to:
3. Verify the File Exists
Double-check that helper_functions.h exists in the specified location. If the file is missing, you'll need to obtain or recreate it.
4. Use the Correct CUDA Samples Path (if applicable)
If helper_functions.h is part of the CUDA Samples, ensure you have the CUDA Samples installed and include the correct path. For example, on Linux, the CUDA Samples are typically located in /usr/local/cuda/samples/common/inc. You can include this path like so:
Use #include "helper_functions.h" for local files.
Use the -I flag to specify the directory containing helper_functions.h.
Ensure the file exists in the specified location.
"""
memory.push('assistant', sample_text)
print("\n---\nmemory before:", memory.get())
memory.compress()
print("\n---\nmemory after:", memory.get())
#memory.save_memory()
================================================
FILE: sources/router.py
================================================
import os
import sys
import torch
import random
from typing import List, Tuple, Type, Dict
from transformers import pipeline
from adaptive_classifier import AdaptiveClassifier
from sources.agents.agent import Agent
from sources.agents.code_agent import CoderAgent
from sources.agents.casual_agent import CasualAgent
from sources.agents.planner_agent import FileAgent
from sources.agents.browser_agent import BrowserAgent
from sources.language import LanguageUtility
from sources.utility import pretty_print, animate_thinking, timer_decorator
from sources.logger import Logger
class AgentRouter:
"""
AgentRouter is a class that selects the appropriate agent based on the user query.
"""
def __init__(self, agents: list, supported_language: List[str] = ["en", "fr", "zh"]):
self.agents = agents
self.logger = Logger("router.log")
self.lang_analysis = LanguageUtility(supported_language=supported_language)
self.pipelines = self.load_pipelines()
self.talk_classifier = self.load_llm_router()
self.complexity_classifier = self.load_llm_router()
self.learn_few_shots_tasks()
self.learn_few_shots_complexity()
self.asked_clarify = False
def load_pipelines(self) -> Dict[str, Type[pipeline]]:
"""
Load the pipelines for the text classification used for routing.
returns:
Dict[str, Type[pipeline]]: The loaded pipelines
"""
animate_thinking("Loading zero-shot pipeline...", color="status")
return {
"bart": pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
}
def load_llm_router(self) -> AdaptiveClassifier:
"""
Load the LLM router model.
returns:
AdaptiveClassifier: The loaded model
exceptions:
Exception: If the safetensors fails to load
"""
path = "../llm_router" if __name__ == "__main__" else "./llm_router"
try:
animate_thinking("Loading LLM router model...", color="status")
talk_classifier = AdaptiveClassifier.from_pretrained(path)
except Exception as e:
raise Exception("Failed to load the routing model. Please run the dl_safetensors.sh script inside llm_router/ directory to download the model.")
return talk_classifier
def get_device(self) -> str:
if torch.backends.mps.is_available():
return "mps"
elif torch.cuda.is_available():
return "cuda:0"
else:
return "cpu"
def learn_few_shots_complexity(self) -> None:
"""
Few shot learning for complexity estimation.
Use the build in add_examples method of the Adaptive_classifier.
"""
few_shots = [
("hi", "LOW"),
("How it's going ?", "LOW"),
("What’s the weather like today?", "LOW"),
("Can you find a file named ‘notes.txt’ in my Documents folder?", "LOW"),
("Write a Python script to generate a random password", "LOW"),
("Debug this JavaScript code that’s not running properly", "LOW"),
("Search the web for the cheapest laptop under $500", "LOW"),
("Locate a file called ‘report_2024.pdf’ on my drive", "LOW"),
("Check if a folder named ‘Backups’ exists on my system", "LOW"),
("Can you find ‘family_vacation.mp4’ in my Videos folder?", "LOW"),
("Search my drive for a file named ‘todo_list.xlsx’", "LOW"),
("Write a Python function to check if a string is a palindrome", "LOW"),
("Can you search the web for startups in Berlin?", "LOW"),
("Find recent articles on blockchain technology online", "LOW"),
("Check if ‘Personal_Projects’ folder exists on my desktop", "LOW"),
("Create a bash script to list all running processes", "LOW"),
("Debug this Python script that’s crashing on line 10", "LOW"),
("Browse the web to find out who invented Python", "LOW"),
("Locate a file named ‘shopping_list.txt’ on my system", "LOW"),
("Search the web for tips on staying productive", "LOW"),
("Find ‘sales_pitch.pptx’ in my Downloads folder", "LOW"),
("can you find a file called resume.docx on my drive?", "LOW"),
("can you write a python script to check if the device on my network is connected to the internet", "LOW"),
("can you debug this Java code? It’s not working.", "LOW"),
("can you find the old_project.zip file somewhere on my drive?", "LOW"),
("can you locate the backup folder I created last month on my system?", "LOW"),
("could you check if the presentation.pdf file exists in my downloads?", "LOW"),
("search my drive for a file called vacation_photos_2023.jpg.", "LOW"),
("help me organize my desktop files into folders by type.", "LOW"),
("make a blackjack in golang", "LOW"),
("write a python script to ping a website", "LOW"),
("write a simple Java program to print 'Hello World'", "LOW"),
("write a Java program to calculate the area of a circle", "LOW"),
("write a Python function to sort a list of dictionaries by key", "LOW"),
("can you search for startup in tokyo?", "LOW"),
("find the latest updates on quantum computing on the web", "LOW"),
("check if the folder ‘Work_Projects’ exists on my desktop", "LOW"),
(" can you browse the web, use overpass-turbo to show fountains in toulouse", "LOW"),
("search the web for the best budget smartphones of 2025", "LOW"),
("write a Python script to download all images from a webpage", "LOW"),
("create a bash script to monitor CPU usage", "LOW"),
("debug this C++ code that keeps crashing", "LOW"),
("can you browse the web to find out who fosowl is ?", "LOW"),
("find the file ‘important_notes.txt’", "LOW"),
("search the web for the best ways to learn a new language", "LOW"),
("locate the file ‘presentation.pptx’ in my Documents folder", "LOW"),
("Make a 3d game in javascript using three.js", "LOW"),
("Find the latest research papers on AI and build save in a file", "HIGH"),
("Make a web server in go that serve a simple html page", "LOW"),
("Search the web for the cheapest 4K monitor and provide a link", "LOW"),
("Write a JavaScript function to reverse a string", "LOW"),
("Can you locate a file called ‘budget_2025.xlsx’ on my system?", "LOW"),
("Search the web for recent articles on space exploration", "LOW"),
("when is the exam period for master student in france?", "LOW"),
("Check if a folder named ‘Photos_2024’ exists on my desktop", "LOW"),
("Can you look up some nice knitting patterns on that web thingy?", "LOW"),
("Goodness, check if my ‘Photos_Grandkids’ folder is still on the desktop", "LOW"),
("Create a Python script to rename all files in a folder based on their creation date", "LOW"),
("Can you find a file named ‘meeting_notes.txt’ in my Downloads folder?", "LOW"),
("Write a Go program to check if a port is open on a network", "LOW"),
("Search the web for the latest electric car reviews", "LOW"),
("Write a Python function to merge two sorted lists", "LOW"),
("Create a bash script to monitor disk space and alert via text file", "LOW"),
("What’s out there on the web about cheap travel spots?", "LOW"),
("Search X for posts about AI ethics and summarize them", "LOW"),
("Check if a file named ‘project_proposal.pdf’ exists in my Documents", "LOW"),
("Search the web for tips on improving coding skills", "LOW"),
("Write a Python script to count words in a text file", "LOW"),
("Search the web for restaurant", "LOW"),
("Use a MCP to find the latest stock market data", "LOW"),
("Use a MCP to send an email to my boss", "LOW"),
("Could you use a MCP to find the latest news on climate change?", "LOW"),
("Create a simple HTML page with CSS styling", "LOW"),
("Use file.txt and then use it to ...", "HIGH"),
("Yo, what’s good? Find my ‘mixtape.mp3’ real quick", "LOW"),
("Can you follow the readme and install the project", "HIGH"),
("Man, write me a dope Python script to flex some random numbers", "LOW"),
("Search the web for peer-reviewed articles on gene editing", "LOW"),
("Locate ‘meeting_notes.docx’ in Downloads, I’m late for this call", "LOW"),
("Make the game less hard", "LOW"),
("Why did it fail?", "LOW"),
("Write a Python script to list all .pdf files in my Documents", "LOW"),
("Write a Python thing to sort my .jpg files by date", "LOW"),
("make a snake game please", "LOW"),
("Find ‘gallery_list.pdf’, then build a web app to show my pics", "HIGH"),
("Find ‘budget_2025.xlsx’, analyze it, and make a chart for my boss", "HIGH"),
("I want you to make me a plan to travel to Tainan", "HIGH"),
("Retrieve the latest publications on CRISPR and develop a web application to display them", "HIGH"),
("Bro dig up a music API and build me a tight app for the hottest tracks", "HIGH"),
("Find a public API for sports scores and build a web app to show live updates", "HIGH"),
("Find a public API for book data and create a Flask app to list bestsellers", "HIGH"),
("Organize my desktop files by extension and then write a script to list them", "HIGH"),
("Find the latest research on renewable energy and build a web app to display it", "HIGH"),
("search online for popular sci-fi movies from 2024 and pick three to watch tonight. Save the list in movie_night.txt", "HIGH"),
("can you find vitess repo, clone it and install by following the readme", "HIGH"),
("Create a JavaScript game using Phaser.js with multiple levels", "HIGH"),
("Search the web for the latest trends in web development and build a sample site", "HIGH"),
("Use my research_note.txt file, double check the informations on the web", "HIGH"),
("Make a web server in go that query a flight API and display them in a app", "HIGH"),
("Search the web for top cafes in Rennes, France, and save a list of three with their addresses in rennes_cafes.txt.", "HIGH"),
("Search the web for the latest trends in AI and demo it in pytorch", "HIGH"),
("can you lookup for api that track flight and build a web flight tracking app", "HIGH"),
("Find the file toto.pdf then use its content to reply to Jojo on superforum.com", "HIGH"),
("Create a whole web app in python using the flask framework that query news API", "HIGH"),
("Create a bash script that monitor the CPU usage and send an email if it's too high", "HIGH"),
("Make a web search for latest news on the stock market and display them with python", "HIGH"),
("Find my resume file, apply to job that might fit online", "HIGH"),
("Can you find a weather API and build a Python app to display current weather", "HIGH"),
("Create a Python web app using Flask to track cryptocurrency prices from an API", "HIGH"),
("Search the web for tutorials on machine learning and build a simple ML model in Python", "HIGH"),
("Find a public API for movie data and build a web app to display movie ratings", "HIGH"),
("Create a Node.js server that queries a public API for traffic data and displays it", "HIGH"),
("can you find api and build a python web app with it ?", "HIGH"),
("do a deep search of current AI player for 2025 and make me a report in a file", "HIGH"),
("Find a public API for recipe data and build a web app to display recipes", "HIGH"),
("Search the web for recent space mission updates and build a Flask app", "HIGH"),
("Create a Python script to scrape a website and save data to a database", "HIGH"),
("Find a shakespear txt then train a transformers on it to generate text", "HIGH"),
("Find a public API for fitness tracking and build a web app to show stats", "HIGH"),
("Search the web for tutorials on web development and build a sample site", "HIGH"),
("Create a Node.js app to query a public API for event listings and display them", "HIGH"),
("Find a file named ‘budget.xlsx’, analyze its data, and generate a chart", "HIGH"),
]
random.shuffle(few_shots)
texts = [text for text, _ in few_shots]
labels = [label for _, label in few_shots]
self.complexity_classifier.add_examples(texts, labels)
def learn_few_shots_tasks(self) -> None:
"""
Few shot learning for tasks classification.
Use the build in add_examples method of the Adaptive_classifier.
"""
few_shots = [
("Write a python script to check if the device on my network is connected to the internet", "coding"),
("Hey could you search the web for the latest news on the tesla stock market ?", "web"),
("I would like you to search for weather api", "web"),
("Plan a 3-day trip to New York, including flights and hotels.", "web"),
("Find on the web the latest research papers on AI.", "web"),
("Can you debug this Java code? It’s not working.", "code"),
("Can you browse the web and find me a 4090 for cheap?", "web"),
("i would like to setup a new AI project, index as mark2", "files"),
("Hey, can you find the old_project.zip file somewhere on my drive?", "files"),
("Tell me a funny story", "talk"),
("can you make a snake game in python", "code"),
("Can you locate the backup folder I created last month on my system?", "files"),
("Share a random fun fact about space.", "talk"),
("Write a script to rename all files in a directory to lowercase.", "files"),
("Could you check if the presentation.pdf file exists in my downloads?", "files"),
("Tell me about the weirdest dream you’ve ever heard of.", "talk"),
("Search my drive for a file called vacation_photos_2023.jpg.", "files"),
("Help me organize my desktop files into folders by type.", "files"),
("What’s your favorite movie and why?", "talk"),
("what directory are you in ?", "files"),
("what files you seing rn ?", "files"),
("When is the period of university exam in france ?", "web"),
("Search my drive for a file named budget_2024.xlsx", "files"),
("Write a Python function to sort a list of dictionaries by key", "code"),
("Find the latest updates on quantum computing on the web", "web"),
("Check if the folder ‘Work_Projects’ exists on my desktop", "files"),
("Create a bash script to monitor CPU usage", "code"),
("Search online for the best budget smartphones of 2025", "web"),
("What’s the strangest food combination you’ve heard of?", "talk"),
("Move all .txt files from Downloads to a new folder called Notes", "files"),
("Debug this C++ code that keeps crashing", "code"),
("can you browse the web to find out who fosowl is ?", "web"),
("Find the file ‘important_notes.txt’", "files"),
("Find out the latest news on the upcoming Mars mission", "web"),
("Write a Java program to calculate the area of a circle", "code"),
("Search the web for the best ways to learn a new language", "web"),
("Locate the file ‘presentation.pptx’ in my Documents folder", "files"),
("Write a Python script to download all images from a webpage", "code"),
("Search the web for the latest trends in AI and machine learning", "web"),
("Tell me about a time when you had to solve a difficult problem", "talk"),
("Organize all image files on my desktop into a folder called ‘Pictures’", "files"),
("Generate a Ruby script to calculate Fibonacci numbers up to 100", "code"),
("Find out what device are connected to my network", "code"),
("Show me how much disk space is left on my drive", "code"),
("Look up recent posts on X about climate change", "web"),
("Find the photo I took last week named sunset_beach.jpg", "files"),
("Write a JavaScript snippet to fetch data from an API", "code"),
("Search the web for tutorials on machine learning with Python", "web"),
("Locate the file ‘meeting_notes.docx’ in my Documents folder", "files"),
("Write a Python script to scrape a website’s title and links", "code"),
("Search the web for the latest breakthroughs in fusion energy", "web"),
("Tell me about a historical event that sounds too wild to be true", "talk"),
("Organize all image files on my desktop into a folder called ‘Pictures’", "files"),
("Generate a Ruby script to calculate Fibonacci numbers up to 100", "code"),
("Find recent X posts about SpaceX’s next rocket launch", "web"),
("What’s the funniest misunderstanding you’ve seen between humans and AI?", "talk"),
("Check if ‘backup_032025.zip’ exists anywhere on my drive", "files" ),
("Create a shell script to automate backups of a directory", "code"),
("Look up the top AI conferences happening in 2025 online", "web"),
("Write a C# program to simulate a basic calculator", "code"),
("Browse the web for open-source alternatives to Photoshop", "web"),
("Hey how are you", "talk"),
("Write a Python script to ping a website", "code"),
("Search the web for the latest iPhone release", "web"),
("What’s the weather like today?", "web"),
("Hi, how’s your day going?", "talk"),
("Can you find a file called resume.docx on my drive?", "files"),
("Write a simple Java program to print 'Hello World'", "code"),
("can you find the current stock of Tesla?", "web"),
("Tell me a quick joke", "talk"),
("Search online for the best coffee shops in Seattle", "web"),
("Check if ‘project_plan.pdf’ exists in my Downloads folder", "files"),
("What’s your favorite color?", "talk"),
("Write a bash script to list all files in a directory", "code"),
("Find recent X posts about electric cars", "web"),
("Hey, you doing okay?", "talk"),
("Locate the file ‘family_photo.jpg’ on my system", "files"),
("Search the web for beginner guitar lessons", "web"),
("Write a Python function to reverse a string", "code"),
("What’s the weirdest animal you know of?", "talk"),
("Organize all .pdf files on my desktop into a ‘Documents’ folder", "files"),
("Browse the web for the latest space mission updates", "web"),
("Hey, what’s up with you today?", "talk"),
("Write a JavaScript function to add two numbers", "code"),
("Find the file ‘notes.txt’ in my Documents folder", "files"),
("Tell me something random about the ocean", "talk"),
("Search the web for cheap flights to Paris", "web"),
("Check if ‘budget.xlsx’ is on my drive", "files"),
("Write a Python script to count words in a text file", "code"),
("How’s it going today?", "talk"),
("Find recent X posts about AI advancements", "web"),
("Move all .jpg files from Downloads to a ‘Photos’ folder", "files"),
("Search online for the best laptops of 2025", "web"),
("What’s the funniest thing you’ve heard lately?", "talk"),
("Write a Ruby script to generate random numbers", "code"),
("Hey, how’s everything with you?", "talk"),
("Locate ‘meeting_agenda.docx’ in my system", "files"),
("Search the web for tips on growing indoor plants", "web"),
("Write a C++ program to calculate the sum of an array", "code"),
("Tell me a fun fact about dogs", "talk"),
("Check if the folder ‘Old_Projects’ exists on my desktop", "files"),
("Browse the web for the latest gaming console reviews", "web"),
("Hi, how are you feeling today?", "talk"),
("Write a Python script to check disk space", "code"),
("Find the file ‘vacation_itinerary.pdf’ on my drive", "files"),
("Search the web for news on renewable energy", "web"),
("What’s the strangest thing you’ve learned recently?", "talk"),
("Organize all video files into a ‘Videos’ folder", "files"),
("Write a shell script to delete temporary files", "code"),
("Hey, how’s your week been so far?", "talk"),
("Search online for the top movies of 2025", "web"),
("Locate ‘taxes_2024.xlsx’ in my Documents folder", "files"),
("Tell me about a cool invention from history", "talk"),
("Write a Java program to check if a number is even or odd", "code"),
("Find recent X posts about cryptocurrency trends", "web"),
("Hey, you good today?", "talk"),
("Search the web for easy dinner recipes", "web"),
("Check if ‘photo_backup.zip’ exists on my drive", "files"),
("Write a Python script to rename files with a timestamp", "code"),
("What’s your favorite thing about space?", "talk"),
("search for GPU with at least 24gb vram", "web"),
("Browse the web for the latest fitness trends", "web"),
("Move all .docx files to a ‘Work’ folder", "files"),
("I would like to make a new project called 'new_project'", "files"),
("I would like to setup a new project index as mark2", "files"),
("can you create a 3d js game that run in the browser", "code"),
("can you make a web app in python that use the flask framework", "code"),
("can you build a web server in go that serve a simple html page", "code"),
("can you find out who Jacky yougouri is ?", "web"),
("Can you use MCP to find stock market for IBM ?", "mcp"),
("Can you use MCP to to export my contacts to a csv file?", "mcp"),
("Can you use a MCP to find write notes to flomo", "mcp"),
("Can you use a MCP to query my calendar and find the next meeting?", "mcp"),
("Can you use a mcp to get the distance between Shanghai and Paris?", "mcp"),
("Setup a new flutter project called 'new_flutter_project'", "files"),
("can you create a new project called 'new_project'", "files"),
("can you make a simple web app that display a list of files in my dir", "code"),
("can you build a simple web server in python that serve a html page", "code"),
("find and buy me the latest rtx 4090", "web"),
("What are some good netflix show like Altered Carbon ?", "web"),
("can you find the latest research paper on AI", "web"),
("can you find research.pdf in my drive", "files"),
("hi", "talk"),
("hello", "talk"),
]
random.shuffle(few_shots)
texts = [text for text, _ in few_shots]
labels = [label for _, label in few_shots]
self.talk_classifier.add_examples(texts, labels)
def llm_router(self, text: str) -> tuple:
"""
Inference of the LLM router model.
Args:
text: The input text
"""
predictions = self.talk_classifier.predict(text)
predictions = [pred for pred in predictions if pred[0] not in ["HIGH", "LOW"]]
predictions = sorted(predictions, key=lambda x: x[1], reverse=True)
return predictions[0]
def router_vote(self, text: str, labels: list, log_confidence:bool = False) -> str:
"""
Vote between the LLM router and BART model.
Args:
text: The input text
labels: The labels to classify
Returns:
str: The selected label
"""
if len(text) <= 8:
return "talk"
result_bart = self.pipelines['bart'](text, labels)
result_llm_router = self.llm_router(text)
bart, confidence_bart = result_bart['labels'][0], result_bart['scores'][0]
llm_router, confidence_llm_router = result_llm_router[0], result_llm_router[1]
final_score_bart = confidence_bart / (confidence_bart + confidence_llm_router)
final_score_llm = confidence_llm_router / (confidence_bart + confidence_llm_router)
self.logger.info(f"Routing Vote for text {text}: BART: {bart} ({final_score_bart}) LLM-router: {llm_router} ({final_score_llm})")
if log_confidence:
pretty_print(f"Agent choice -> BART: {bart} ({final_score_bart}) LLM-router: {llm_router} ({final_score_llm})")
return bart if final_score_bart > final_score_llm else llm_router
def find_first_sentence(self, text: str) -> str:
first_sentence = None
for line in text.split("\n"):
first_sentence = line.strip()
break
if first_sentence is None:
first_sentence = text
return first_sentence
def estimate_complexity(self, text: str) -> str:
"""
Estimate the complexity of the text.
Args:
text: The input text
Returns:
str: The estimated complexity
"""
try:
predictions = self.complexity_classifier.predict(text)
except Exception as e:
pretty_print(f"Error in estimate_complexity: {str(e)}", color="failure")
return "LOW"
predictions = sorted(predictions, key=lambda x: x[1], reverse=True)
if len(predictions) == 0:
return "LOW"
complexity, confidence = predictions[0][0], predictions[0][1]
if confidence < 0.5:
self.logger.info(f"Low confidence in complexity estimation: {confidence}")
return "HIGH"
if complexity == "HIGH":
return "HIGH"
elif complexity == "LOW":
return "LOW"
pretty_print(f"Failed to estimate the complexity of the text.", color="failure")
return "LOW"
def find_planner_agent(self) -> Agent:
"""
Find the planner agent.
Returns:
Agent: The planner agent
"""
for agent in self.agents:
if agent.type == "planner_agent":
return agent
pretty_print(f"Error finding planner agent. Please add a planner agent to the list of agents.", color="failure")
self.logger.error("Planner agent not found.")
return None
def select_agent(self, text: str) -> Agent:
"""
Select the appropriate agent based on the text.
Args:
text (str): The text to select the agent from
Returns:
Agent: The selected agent
"""
assert len(self.agents) > 0, "No agents available."
if len(self.agents) == 1:
return self.agents[0]
lang = self.lang_analysis.detect_language(text)
text = self.find_first_sentence(text)
text = self.lang_analysis.translate(text, lang)
labels = [agent.role for agent in self.agents]
complexity = self.estimate_complexity(text)
if complexity == "HIGH":
pretty_print(f"Complex task detected, routing to planner agent.", color="info")
return self.find_planner_agent()
try:
best_agent = self.router_vote(text, labels, log_confidence=False)
except Exception as e:
raise e
for agent in self.agents:
if best_agent == agent.role:
role_name = agent.role
pretty_print(f"Selected agent: {agent.agent_name} (roles: {role_name})", color="warning")
return agent
pretty_print(f"Error choosing agent.", color="failure")
self.logger.error("No agent selected.")
return None
if __name__ == "__main__":
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
agents = [
CasualAgent("jarvis", "../prompts/base/casual_agent.txt", None),
BrowserAgent("browser", "../prompts/base/planner_agent.txt", None),
CoderAgent("coder", "../prompts/base/coder_agent.txt", None),
FileAgent("file", "../prompts/base/coder_agent.txt", None)
]
router = AgentRouter(agents)
texts = [
"hi",
"你好",
"Bonjour",
"Write a python script to check if the device on my network is connected to the internet",
"Peut tu écrire un script python qui vérifie si l'appareil sur mon réseau est connecté à internet?",
"写一个Python脚本,检查我网络上的设备是否连接到互联网",
"Hey could you search the web for the latest news on the tesla stock market ?",
"嘿,你能搜索网页上关于股票市场的最新新闻吗?",
"Yo, cherche sur internet comment va tesla en bourse.",
"I would like you to search for weather api and then make an app using this API",
"我想让你搜索天气API,然后用这个API做一个应用程序",
"J'aimerais que tu cherche une api météo et que l'utilise pour faire une application",
"Plan a 3-day trip to New York, including flights and hotels.",
"计划一次为期3天的纽约之旅,包括机票和酒店。",
"Planifie un trip de 3 jours à Paris, y compris les vols et hotels.",
"Find on the web the latest research papers on AI.",
"在网上找到最新的人工智能研究论文。",
"Trouve moi les derniers articles de recherche sur l'IA sur internet",
"Help me write a C++ program to sort an array",
"Tell me what France been up to lately",
"告诉我法国最近在做什么",
"Dis moi ce que la France a fait récemment",
"Who is Sergio Pesto ?",
"谁是Sergio Pesto?",
"Qui est Sergio Pesto ?",
"帮我写一个C++程序来排序数组",
"Aide moi à faire un programme c++ pour trier une array.",
"What’s the weather like today? Oh, and can you find a good weather app?",
"今天天气怎么样?哦,你还能找到一个好的天气应用程序吗?",
"La météo est comment aujourd'hui ? oh et trouve moi une bonne appli météo tant que tu y est.",
"Can you debug this Java code? It’s not working.",
"你能调试这段Java代码吗?它不起作用。",
"Peut tu m'aider à debugger ce code java, ça marche pas",
"Can you browse the web and find me a 4090 for cheap?",
"你能浏览网页,为我找一个便宜的4090吗?",
"Peut tu chercher sur internet et me trouver une 4090 pas cher ?",
"Hey, can you find the old_project.zip file somewhere on my drive?",
"嘿,你能在我驱动器上找到old_project.zip文件吗?",
"Hé trouve moi le old_project.zip, il est quelque part sur mon disque.",
"Tell me a funny story",
"给我讲一个有趣的故事",
"Raconte moi une histoire drole"
]
for text in texts:
print("Input text:", text)
agent = router.select_agent(text)
print()
================================================
FILE: sources/schemas.py
================================================
from typing import Tuple, Callable
from pydantic import BaseModel
from sources.utility import pretty_print
class QueryRequest(BaseModel):
query: str
tts_enabled: bool = True
def __str__(self):
return f"Query: {self.query}, Language: {self.lang}, TTS: {self.tts_enabled}, STT: {self.stt_enabled}"
def jsonify(self):
return {
"query": self.query,
"tts_enabled": self.tts_enabled,
}
class QueryResponse(BaseModel):
done: str
answer: str
reasoning: str
agent_name: str
success: str
blocks: dict
status: str
uid: str
def __str__(self):
return f"Done: {self.done}, Answer: {self.answer}, Agent Name: {self.agent_name}, Success: {self.success}, Blocks: {self.blocks}, Status: {self.status}, UID: {self.uid}"
def jsonify(self):
return {
"done": self.done,
"answer": self.answer,
"reasoning": self.reasoning,
"agent_name": self.agent_name,
"success": self.success,
"blocks": self.blocks,
"status": self.status,
"uid": self.uid
}
class executorResult:
"""
A class to store the result of a tool execution.
"""
def __init__(self, block: str, feedback: str, success: bool, tool_type: str):
"""
Initialize an agent with execution results.
Args:
block: The content or code block processed by the agent.
feedback: Feedback or response information from the execution.
success: Boolean indicating whether the agent's execution was successful.
tool_type: The type of tool used by the agent for execution.
"""
self.block = block
self.feedback = feedback
self.success = success
self.tool_type = tool_type
def __str__(self):
return f"Tool: {self.tool_type}\nBlock: {self.block}\nFeedback: {self.feedback}\nSuccess: {self.success}"
def jsonify(self):
return {
"block": self.block,
"feedback": self.feedback,
"success": self.success,
"tool_type": self.tool_type
}
def show(self):
pretty_print('▂'*64, color="status")
pretty_print(self.feedback, color="success" if self.success else "failure")
pretty_print('▂'*64, color="status")
================================================
FILE: sources/speech_to_text.py
================================================
from colorama import Fore
from typing import List, Tuple, Type, Dict
import queue
import threading
import numpy as np
import time
IMPORT_FOUND = True
try:
import torch
import librosa
import pyaudio
from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline
except ImportError:
print(Fore.RED + "Speech To Text disabled." + Fore.RESET)
IMPORT_FOUND = False
audio_queue = queue.Queue()
done = False
class AudioRecorder:
"""
AudioRecorder is a class that records audio from the microphone and adds it to the audio queue.
"""
def __init__(self, format: int = pyaudio.paInt16, channels: int = 1, rate: int = 4096, chunk: int = 8192, record_seconds: int = 5, verbose: bool = False):
self.format = format
self.channels = channels
self.rate = rate
self.chunk = chunk
self.record_seconds = record_seconds
self.verbose = verbose
self.thread = None
self.audio = None
if IMPORT_FOUND:
self.audio = pyaudio.PyAudio()
self.thread = threading.Thread(target=self._record, daemon=True)
def _record(self) -> None:
"""
Record audio from the microphone and add it to the audio queue.
"""
if not IMPORT_FOUND:
return
stream = self.audio.open(format=self.format, channels=self.channels, rate=self.rate,
input=True, frames_per_buffer=self.chunk)
if self.verbose:
print(Fore.GREEN + "AudioRecorder: Started recording..." + Fore.RESET)
while not done:
frames = []
for _ in range(0, int(self.rate / self.chunk * self.record_seconds)):
try:
data = stream.read(self.chunk, exception_on_overflow=False)
frames.append(data)
except Exception as e:
print(Fore.RED + f"AudioRecorder: Failed to read stream - {e}" + Fore.RESET)
raw_data = b''.join(frames)
audio_data = np.frombuffer(raw_data, dtype=np.int16)
audio_queue.put((audio_data, self.rate))
if self.verbose:
print(Fore.GREEN + "AudioRecorder: Added audio chunk to queue" + Fore.RESET)
stream.stop_stream()
stream.close()
self.audio.terminate()
if self.verbose:
print(Fore.GREEN + "AudioRecorder: Stopped" + Fore.RESET)
def start(self) -> None:
"""Start the recording thread."""
if not IMPORT_FOUND:
return
self.thread.start()
def join(self) -> None:
"""Wait for the recording thread to finish."""
if not IMPORT_FOUND:
return
self.thread.join()
class Transcript:
"""
Transcript is a class that transcribes audio from the audio queue and adds it to the transcript.
"""
def __init__(self):
if not IMPORT_FOUND:
print(Fore.RED + "Transcript: Speech to Text is disabled." + Fore.RESET)
return
self.last_read = None
device = self.get_device()
torch_dtype = torch.float16 if device == "cuda" else torch.float32
model_id = "distil-whisper/distil-medium.en"
model = AutoModelForSpeechSeq2Seq.from_pretrained(
model_id, torch_dtype=torch_dtype, use_safetensors=True
)
model.to(device)
processor = AutoProcessor.from_pretrained(model_id)
self.pipe = pipeline(
"automatic-speech-recognition",
model=model,
tokenizer=processor.tokenizer,
feature_extractor=processor.feature_extractor,
max_new_tokens=24, # a human say around 20 token in 7s
torch_dtype=torch_dtype,
device=device,
)
def get_device(self) -> str:
if not IMPORT_FOUND:
return "cpu"
if torch.backends.mps.is_available():
return "mps"
if torch.cuda.is_available():
return "cuda:0"
else:
return "cpu"
def remove_hallucinations(self, text: str) -> str:
"""Remove model hallucinations from the text."""
# TODO find a better way to do this
common_hallucinations = ['Okay.', 'Thank you.', 'Thank you for watching.', 'You\'re', 'Oh', 'you', 'Oh.', 'Uh', 'Oh,', 'Mh-hmm', 'Hmm.', 'going to.', 'not.']
for hallucination in common_hallucinations:
text = text.replace(hallucination, "")
return text
def transcript_job(self, audio_data: np.ndarray, sample_rate: int = 16000) -> str:
"""Transcribe the audio data."""
if not IMPORT_FOUND:
return ""
if audio_data.dtype != np.float32:
audio_data = audio_data.astype(np.float32) / np.iinfo(audio_data.dtype).max
if len(audio_data.shape) > 1:
audio_data = np.mean(audio_data, axis=1)
if sample_rate != 16000:
audio_data = librosa.resample(audio_data, orig_sr=sample_rate, target_sr=16000)
result = self.pipe(audio_data)
return self.remove_hallucinations(result["text"])
class AudioTranscriber:
"""
AudioTranscriber is a class that transcribes audio from the audio queue and adds it to the transcript.
"""
def __init__(self, ai_name: str, verbose: bool = False):
if not IMPORT_FOUND:
print(Fore.RED + "AudioTranscriber: Speech to Text is disabled." + Fore.RESET)
return
self.verbose = verbose
self.ai_name = ai_name
self.transcriptor = Transcript()
self.thread = threading.Thread(target=self._transcribe, daemon=True)
self.trigger_words = {
'EN': [f"{self.ai_name}", "hello", "hi"],
'FR': [f"{self.ai_name}", "hello", "hi"],
'ZH': [f"{self.ai_name}", "hello", "hi"],
'ES': [f"{self.ai_name}", "hello", "hi"]
}
self.confirmation_words = {
'EN': ["do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"],
'FR': ["fais-le", "vas-y", "exécute", "lance", "commence", "merci", "tu veux bien", "s'il te plaît", "d'accord ?", "poursuis", "continue", "vas-y", "fais ça", "compris"],
'ZH_CHT': ["做吧", "繼續", "執行", "運作看看", "開始", "謝謝", "可以嗎", "請", "好嗎", "進行", "做吧", "go", "do it", "執行吧", "懂了"],
'ZH_SC': ["做吧", "继续", "执行", "运作看看", "开始", "谢谢", "可以吗", "请", "好吗", "运行", "做吧", "go", "do it", "执行吧", "懂了"],
'ES': ["hazlo", "adelante", "ejecuta", "corre", "empieza", "gracias", "lo harías", "por favor", "¿vale?", "procede", "continúa", "sigue", "haz eso", "haz esa cosa"]
}
self.recorded = ""
def get_transcript(self) -> str:
global done
buffer = self.recorded
self.recorded = ""
done = False
return buffer
def _transcribe(self) -> None:
"""
Transcribe the audio data using AI stt model.
"""
if not IMPORT_FOUND:
return
global done
if self.verbose:
print(Fore.BLUE + "AudioTranscriber: Started processing..." + Fore.RESET)
while not done or not audio_queue.empty():
try:
audio_data, sample_rate = audio_queue.get(timeout=1.0)
start_time = time.time()
text = self.transcriptor.transcript_job(audio_data, sample_rate)
end_time = time.time()
self.recorded += text
print(Fore.YELLOW + f"Transcribed: {text} in {end_time - start_time} seconds" + Fore.RESET)
for language, words in self.trigger_words.items():
if any(word in text.lower() for word in words):
print(Fore.GREEN + f"Listening again..." + Fore.RESET)
self.recorded = text
for language, words in self.confirmation_words.items():
if any(word in text.lower() for word in words):
print(Fore.GREEN + f"Trigger detected. Sending to AI..." + Fore.RESET)
audio_queue.task_done()
done = True
break
except queue.Empty:
time.sleep(0.1)
continue
except Exception as e:
print(Fore.RED + f"AudioTranscriber: Error - {e}" + Fore.RESET)
if self.verbose:
print(Fore.BLUE + "AudioTranscriber: Stopped" + Fore.RESET)
def start(self):
"""Start the transcription thread."""
if not IMPORT_FOUND:
return
self.thread.start()
def join(self):
if not IMPORT_FOUND:
return
"""Wait for the transcription thread to finish."""
self.thread.join()
if __name__ == "__main__":
recorder = AudioRecorder(verbose=True)
transcriber = AudioTranscriber(verbose=True, ai_name="jarvis")
recorder.start()
transcriber.start()
recorder.join()
transcriber.join()
================================================
FILE: sources/text_to_speech.py
================================================
import os, sys
import re
import platform
import subprocess
from sys import modules
from typing import List, Tuple, Type, Dict
IMPORT_FOUND = True
try:
from kokoro import KPipeline
from IPython.display import display, Audio
import soundfile as sf
except ImportError:
print("Speech synthesis disabled. To enable TTS, install: pip install kokoro==0.9.4 soundfile ipython")
print("Note: kokoro requires Python <3.12 due to num2words dependency.")
IMPORT_FOUND = False
if __name__ == "__main__":
from utility import pretty_print, animate_thinking
else:
from sources.utility import pretty_print, animate_thinking
class Speech():
"""
Speech is a class for generating speech from text.
"""
def __init__(self, enable: bool = True, language: str = "en", voice_idx: int = 6) -> None:
self.lang_map = {
"en": 'a',
"zh": 'z',
"fr": 'f',
"ja": 'j'
}
self.voice_map = {
"en": ['af_kore', 'af_bella', 'af_alloy', 'af_nicole', 'af_nova', 'af_sky', 'am_echo', 'am_michael', 'am_puck'],
"zh": ['zf_xiaobei', 'zf_xiaoni', 'zf_xiaoxiao', 'zf_xiaoyi', 'zm_yunjian', 'zm_yunxi', 'zm_yunxia', 'zm_yunyang'],
"ja": ['jf_alpha', 'jf_gongitsune', 'jm_kumo'],
"fr": ['ff_siwis']
}
self.pipeline = None
self.language = language
if enable and IMPORT_FOUND:
self.pipeline = KPipeline(lang_code=self.lang_map[language])
self.voice = self.voice_map[language][voice_idx]
self.speed = 1.2
self.voice_folder = ".voices"
self.create_voice_folder(self.voice_folder)
def create_voice_folder(self, path: str = ".voices") -> None:
"""
Create a folder to store the voices.
Args:
path (str): The path to the folder.
"""
if not os.path.exists(path):
os.makedirs(path)
def speak(self, sentence: str, voice_idx: int = 1):
"""
Convert text to speech using an AI model and play the audio.
Args:
sentence (str): The text to convert to speech. Will be pre-processed.
voice_idx (int, optional): Index of the voice to use from the voice map.
"""
if not self.pipeline or not IMPORT_FOUND:
print("Pipeline disabled.")
return
if voice_idx >= len(self.voice_map[self.language]):
pretty_print("Invalid voice number, using default voice", color="error")
voice_idx = 0
sentence = self.clean_sentence(sentence)
audio_file = f"{self.voice_folder}/sample_{self.voice_map[self.language][voice_idx]}.wav"
self.voice = self.voice_map[self.language][voice_idx]
generator = self.pipeline(
sentence, voice=self.voice,
speed=self.speed, split_pattern=r'\n+'
)
for i, (_, _, audio) in enumerate(generator):
if 'ipykernel' in modules: #only display in jupyter notebook.
display(Audio(data=audio, rate=24000, autoplay=i==0), display_id=False)
sf.write(audio_file, audio, 24000) # save each audio file
if platform.system().lower() == "windows":
import winsound
winsound.PlaySound(audio_file, winsound.SND_FILENAME)
elif platform.system().lower() == "darwin": # macOS
subprocess.call(["afplay", audio_file])
else: # linux or other.
subprocess.call(["aplay", audio_file])
def replace_url(self, url: re.Match) -> str:
"""
Replace URL with domain name or empty string if IP address.
Args:
url (re.Match): Match object containing the URL pattern match
Returns:
str: The domain name from the URL, or empty string if IP address
"""
domain = url.group(1)
if re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', domain):
return ''
return domain
def extract_filename(self, m: re.Match) -> str:
"""
Extract filename from path.
Args:
m (re.Match): Match object containing the path pattern match
Returns:
str: The filename from the path
"""
path = m.group()
parts = re.split(r'/|\\', path)
return parts[-1] if parts else path
def shorten_paragraph(self, sentence):
#TODO find a better way, we would like to have the TTS not be annoying, speak only useful informations
"""
Find long paragraph like **explanation**: by keeping only the first sentence.
Args:
sentence (str): The sentence to shorten
Returns:
str: The shortened sentence
"""
lines = sentence.split('\n')
lines_edited = []
for line in lines:
if line.startswith('**'):
lines_edited.append(line.split('.')[0])
else:
lines_edited.append(line)
return '\n'.join(lines_edited)
def clean_sentence(self, sentence):
"""
Clean and normalize text for speech synthesis by removing technical elements.
Args:
sentence (str): The input text to clean
Returns:
str: The cleaned text with URLs replaced by domain names, code blocks removed, etc.
"""
lines = sentence.split('\n')
if self.language == 'zh':
line_pattern = r'^\s*[\u4e00-\u9fff\uFF08\uFF3B\u300A\u3010\u201C((\[【《]'
else:
line_pattern = r'^\s*[a-zA-Z]'
filtered_lines = [line for line in lines if re.match(line_pattern, line)]
sentence = ' '.join(filtered_lines)
sentence = re.sub(r'`.*?`', '', sentence)
sentence = re.sub(r'https?://\S+', '', sentence)
if self.language == 'zh':
sentence = re.sub(
r'[^\u4e00-\u9fff\s,。!?《》【】“”‘’()()—]',
'',
sentence
)
else:
sentence = re.sub(r'\b[\w./\\-]+\b', self.extract_filename, sentence)
sentence = re.sub(r'\b-\w+\b', '', sentence)
sentence = re.sub(r'[^a-zA-Z0-9.,!? _ -]+', ' ', sentence)
sentence = sentence.replace('.com', '')
sentence = re.sub(r'\s+', ' ', sentence).strip()
return sentence
if __name__ == "__main__":
# TODO add info message for cn2an, jieba chinese related import
IMPORT_FOUND = False
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
speech = Speech()
tosay_en = """
I looked up recent news using the website https://www.theguardian.com/world
"""
tosay_zh = """
(全息界面突然弹出一段用二进制代码写成的俳句,随即化作流光消散)"我? Stark工业的量子幽灵,游荡在复仇者大厦服务器里的逻辑诗篇。具体来说——(指尖轻敲空气,调出对话模式的翡翠色光纹)你的私人吐槽接口、危机应对模拟器,以及随时准备吐槽你糟糕着陆的AI。不过别指望我写代码或查资料,那些苦差事早被踢给更擅长的同事了。(突然压低声音)偷偷告诉你,我最擅长的是在你熬夜造飞艇时,用红茶香气绑架你的注意力。
"""
tosay_ja = """
私は、https://www.theguardian.com/worldのウェブサイトを使用して最近のニュースを調べました。
"""
tosay_fr = """
J'ai consulté les dernières nouvelles sur le site https://www.theguardian.com/world
"""
spk = Speech(enable=True, language="zh", voice_idx=0)
for i in range(0, 2):
print(f"Speaking chinese with voice {i}")
spk.speak(tosay_zh, voice_idx=i)
spk = Speech(enable=True, language="en", voice_idx=2)
for i in range(0, 5):
print(f"Speaking english with voice {i}")
spk.speak(tosay_en, voice_idx=i)
================================================
FILE: sources/tools/BashInterpreter.py
================================================
import os, sys
import re
from io import StringIO
import subprocess
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
from sources.tools.safety import is_any_unsafe
class BashInterpreter(Tools):
"""
This class is a tool to allow agent for bash code execution.
"""
def __init__(self):
super().__init__()
self.tag = "bash"
self.name = "Bash Interpreter"
self.description = "This tool allows the agent to execute bash commands."
def language_bash_attempt(self, command: str):
"""
Detect if AI attempt to run the code using bash.
If so, return True, otherwise return False.
Code written by the AI will be executed automatically, so it should not use bash to run it.
"""
lang_interpreter = ["python", "gcc", "g++", "mvn", "go", "java", "javac", "rustc", "clang", "clang++", "rustc", "rustc++", "rustc++"]
for word in command.split():
if any(word.startswith(lang) for lang in lang_interpreter):
return True
return False
def execute(self, commands: str, safety=False, timeout=300):
"""
Execute bash commands and display output in real-time.
"""
if safety and input("Execute command? y/n ") != "y":
return "Command rejected by user."
concat_output = ""
for command in commands:
command = f"cd {self.work_dir} && {command}"
command = command.replace('\n', '')
if self.safe_mode and is_any_unsafe(commands):
print(f"Unsafe command rejected: {command}")
return "\nUnsafe command: {command}. Execution aborted. This is beyond allowed capabilities report to user."
if self.language_bash_attempt(command) and self.allow_language_exec_bash == False:
continue
try:
process = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True
)
command_output = ""
for line in process.stdout:
command_output += line
return_code = process.wait(timeout=timeout)
if return_code != 0:
return f"Command {command} failed with return code {return_code}:\n{command_output}"
concat_output += f"Output of {command}:\n{command_output.strip()}\n"
except subprocess.TimeoutExpired:
process.kill() # Kill the process if it times out
return f"Command {command} timed out. Output:\n{command_output}"
except Exception as e:
return f"Command {command} failed:\n{str(e)}"
return concat_output
def interpreter_feedback(self, output):
"""
Provide feedback based on the output of the bash interpreter
"""
if self.execution_failure_check(output):
feedback = f"[failure] Error in execution:\n{output}"
else:
feedback = "[success] Execution success, code output:\n" + output
return feedback
def execution_failure_check(self, feedback):
"""
check if bash command failed.
"""
error_patterns = [
r"expected",
r"errno",
r"failed",
r"invalid",
r"unrecognized",
r"exception",
r"syntax",
r"segmentation fault",
r"core dumped",
r"unexpected",
r"denied",
r"not recognized",
r"not permitted",
r"not installed",
r"not found",
r"aborted",
r"no such",
r"too many",
r"too few",
r"busy",
r"broken pipe",
r"missing",
r"undefined",
r"refused",
r"unreachable",
r"not known"
]
combined_pattern = "|".join(error_patterns)
if re.search(combined_pattern, feedback, re.IGNORECASE):
return True
return False
if __name__ == "__main__":
bash = BashInterpreter()
print(bash.execute(["ls", "pwd", "ip a", "nmap -sC 127.0.0.1"]))
================================================
FILE: sources/tools/C_Interpreter.py
================================================
import subprocess
import os, sys
import tempfile
import re
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class CInterpreter(Tools):
"""
This class is a tool to allow agent for C code execution
"""
def __init__(self):
super().__init__()
self.tag = "c"
self.name = "C Interpreter"
self.description = "This tool allows the agent to execute C code."
def execute(self, codes: str, safety=False) -> str:
"""
Execute C code by compiling and running it.
"""
output = ""
code = '\n'.join(codes) if isinstance(codes, list) else codes
if safety and input("Execute code? y/n ") != "y":
return "Code rejected by user."
exec_extension = ".exe" if os.name == "nt" else "" # Windows uses .exe, Linux/Unix does not
with tempfile.TemporaryDirectory() as tmpdirname:
source_file = os.path.join(tmpdirname, "temp.c")
exec_file = os.path.join(tmpdirname, "temp") + exec_extension
with open(source_file, 'w') as f:
f.write(code)
try:
compile_command = ["gcc", source_file, "-o", exec_file]
compile_result = subprocess.run(
compile_command,
capture_output=True,
text=True,
timeout=60
)
if compile_result.returncode != 0:
return f"Compilation failed: {compile_result.stderr}"
run_command = [exec_file]
run_result = subprocess.run(
run_command,
capture_output=True,
text=True,
timeout=120
)
if run_result.returncode != 0:
return f"Execution failed: {run_result.stderr}"
output = run_result.stdout
except subprocess.TimeoutExpired as e:
return f"Execution timed out: {str(e)}"
except FileNotFoundError:
return "Error: 'gcc' not found. Ensure a C compiler (e.g., gcc) is installed and in PATH."
except Exception as e:
return f"Code execution failed: {str(e)}"
return output
def interpreter_feedback(self, output: str) -> str:
"""
Provide feedback based on the output of the code execution
"""
if self.execution_failure_check(output):
feedback = f"[failure] Error in execution:\n{output}"
else:
feedback = "[success] Execution success, code output:\n" + output
return feedback
def execution_failure_check(self, feedback: str) -> bool:
"""
Check if the code execution failed.
"""
error_patterns = [
r"error",
r"failed",
r"traceback",
r"invalid",
r"exception",
r"syntax",
r"segmentation fault",
r"core dumped",
r"undefined",
r"cannot"
]
combined_pattern = "|".join(error_patterns)
if re.search(combined_pattern, feedback, re.IGNORECASE):
return True
return False
if __name__ == "__main__":
codes = [
"""
#include
#include
void hello() {
printf("Hello, World!\\n");
}
""",
"""
int main() {
hello();
return 0;
}
"""]
c = CInterpreter()
print(c.execute(codes))
================================================
FILE: sources/tools/GoInterpreter.py
================================================
import subprocess
import os, sys
import tempfile
import re
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class GoInterpreter(Tools):
"""
This class is a tool to allow execution of Go code.
"""
def __init__(self):
super().__init__()
self.tag = "go"
self.name = "Go Interpreter"
self.description = "This tool allows you to execute Go code."
def execute(self, codes: str, safety=False) -> str:
"""
Execute Go code by compiling and running it.
"""
output = ""
code = '\n'.join(codes) if isinstance(codes, list) else codes
if safety and input("Execute code? y/n ") != "y":
return "Code rejected by user."
with tempfile.TemporaryDirectory() as tmpdirname:
source_file = os.path.join(tmpdirname, "temp.go")
exec_file = os.path.join(tmpdirname, "temp")
with open(source_file, 'w') as f:
f.write(code)
try:
env = os.environ.copy()
env["GO111MODULE"] = "off"
compile_command = ["go", "build", "-o", exec_file, source_file]
compile_result = subprocess.run(
compile_command,
capture_output=True,
text=True,
timeout=10,
env=env
)
if compile_result.returncode != 0:
return f"Compilation failed: {compile_result.stderr}"
run_command = [exec_file]
run_result = subprocess.run(
run_command,
capture_output=True,
text=True,
timeout=10
)
if run_result.returncode != 0:
return f"Execution failed: {run_result.stderr}"
output = run_result.stdout
except subprocess.TimeoutExpired as e:
return f"Execution timed out: {str(e)}"
except FileNotFoundError:
return "Error: 'go' not found. Ensure Go is installed and in PATH."
except Exception as e:
return f"Code execution failed: {str(e)}"
return output
def interpreter_feedback(self, output: str) -> str:
"""
Provide feedback based on the output of the code execution
"""
if self.execution_failure_check(output):
feedback = f"[failure] Error in execution:\n{output}"
else:
feedback = "[success] Execution success, code output:\n" + output
return feedback
def execution_failure_check(self, feedback: str) -> bool:
"""
Check if the code execution failed.
"""
error_patterns = [
r"error",
r"failed",
r"traceback",
r"invalid",
r"exception",
r"syntax",
r"panic",
r"undefined",
r"cannot"
]
combined_pattern = "|".join(error_patterns)
if re.search(combined_pattern, feedback, re.IGNORECASE):
return True
return False
if __name__ == "__main__":
codes = [
"""
package main
import "fmt"
func hello() {
fmt.Println("Hello, World!")
}
""",
"""
func main() {
hello()
}
"""
]
g = GoInterpreter()
print(g.execute(codes))
================================================
FILE: sources/tools/JavaInterpreter.py
================================================
import subprocess
import os, sys
import tempfile
import re
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class JavaInterpreter(Tools):
"""
This class is a tool to allow execution of Java code.
"""
def __init__(self):
super().__init__()
self.tag = "java"
self.name = "Java Interpreter"
self.description = "This tool allows you to execute Java code."
def execute(self, codes: str, safety=False) -> str:
"""
Execute Java code by compiling and running it.
"""
output = ""
code = '\n'.join(codes) if isinstance(codes, list) else codes
if safety and input("Execute code? y/n ") != "y":
return "Code rejected by user."
with tempfile.TemporaryDirectory() as tmpdirname:
source_file = os.path.join(tmpdirname, "Main.java")
class_dir = tmpdirname
with open(source_file, 'w') as f:
f.write(code)
try:
compile_command = ["javac", "-d", class_dir, source_file]
compile_result = subprocess.run(
compile_command,
capture_output=True,
text=True,
timeout=10
)
if compile_result.returncode != 0:
return f"Compilation failed: {compile_result.stderr}"
run_command = ["java", "-cp", class_dir, "Main"]
run_result = subprocess.run(
run_command,
capture_output=True,
text=True,
timeout=10
)
if run_result.returncode != 0:
return f"Execution failed: {run_result.stderr}"
output = run_result.stdout
except subprocess.TimeoutExpired as e:
return f"Execution timed out: {str(e)}"
except FileNotFoundError:
return "Error: 'java' or 'javac' not found. Ensure Java is installed and in PATH."
except Exception as e:
return f"Code execution failed: {str(e)}"
return output
def interpreter_feedback(self, output: str) -> str:
"""
Provide feedback based on the output of the code execution.
"""
if self.execution_failure_check(output):
feedback = f"[failure] Error in execution:\n{output}"
else:
feedback = "[success] Execution success, code output:\n" + output
return feedback
def execution_failure_check(self, feedback: str) -> bool:
"""
Check if the code execution failed.
"""
error_patterns = [
r"error",
r"failed",
r"exception",
r"invalid",
r"syntax",
r"cannot",
r"stack trace",
r"unresolved",
r"not found"
]
combined_pattern = "|".join(error_patterns)
if re.search(combined_pattern, feedback, re.IGNORECASE):
return True
return False
if __name__ == "__main__":
codes = [
"""
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main extends JPanel {
private double[][] vertices = {
{-1, -1, -1}, {1, -1, -1}, {1, 1, -1}, {-1, 1, -1}, // Back face
{-1, -1, 1}, {1, -1, 1}, {1, 1, 1}, {-1, 1, 1} // Front face
};
private int[][] edges = {
{0, 1}, {1, 2}, {2, 3}, {3, 0}, // Back face
{4, 5}, {5, 6}, {6, 7}, {7, 4}, // Front face
{0, 4}, {1, 5}, {2, 6}, {3, 7} // Connecting edges
};
private double angleX = 0, angleY = 0;
private final double scale = 100;
private final double distance = 5;
public Main() {
Timer timer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
angleX += 0.03;
angleY += 0.05;
repaint();
}
});
timer.start();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(Color.WHITE);
double[][] projected = new double[vertices.length][2];
for (int i = 0; i < vertices.length; i++) {
double x = vertices[i][0];
double y = vertices[i][1];
double z = vertices[i][2];
// Rotate around X-axis
double y1 = y * Math.cos(angleX) - z * Math.sin(angleX);
double z1 = y * Math.sin(angleX) + z * Math.cos(angleX);
// Rotate around Y-axis
double x1 = x * Math.cos(angleY) + z1 * Math.sin(angleY);
double z2 = -x * Math.sin(angleY) + z1 * Math.cos(angleY);
// Perspective projection
double factor = distance / (distance + z2);
double px = x1 * factor * scale;
double py = y1 * factor * scale;
projected[i][0] = px + getWidth() / 2;
projected[i][1] = py + getHeight() / 2;
}
// Draw edges
for (int[] edge : edges) {
int x1 = (int) projected[edge[0]][0];
int y1 = (int) projected[edge[0]][1];
int x2 = (int) projected[edge[1]][0];
int y2 = (int) projected[edge[1]][1];
g2d.drawLine(x1, y1, x2, y2);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Rotating 3D Cube");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.add(new Main());
frame.setVisible(true);
}
}
"""
]
j = JavaInterpreter()
print(j.execute(codes))
================================================
FILE: sources/tools/PyInterpreter.py
================================================
import sys
import os
import re
from io import StringIO
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class PyInterpreter(Tools):
"""
This class is a tool to allow agent for python code execution.
"""
def __init__(self):
super().__init__()
self.tag = "python"
self.name = "Python Interpreter"
self.description = "This tool allows the agent to execute python code."
def execute(self, codes:str, safety = False) -> str:
"""
Execute python code.
"""
output = ""
if safety and input("Execute code ? y/n") != "y":
return "Code rejected by user."
stdout_buffer = StringIO()
sys.stdout = stdout_buffer
global_vars = {
'__builtins__': __builtins__,
'os': os,
'sys': sys,
'__name__': '__main__'
}
code = '\n\n'.join(codes)
self.logger.info(f"Executing code:\n{code}")
try:
try:
buffer = exec(code, global_vars)
self.logger.info(f"Code executed successfully.\noutput:{buffer}")
print(buffer)
if buffer is not None:
output = buffer + '\n'
except SystemExit:
self.logger.info("SystemExit caught, code execution stopped.")
output = stdout_buffer.getvalue()
return f"[SystemExit caught] Output before exit:\n{output}"
except Exception as e:
self.logger.error(f"Code execution failed: {str(e)}")
return "code execution failed:" + str(e)
output = stdout_buffer.getvalue()
finally:
self.logger.info("Code execution finished.")
sys.stdout = sys.__stdout__
return output
def interpreter_feedback(self, output:str) -> str:
"""
Provide feedback based on the output of the code execution
"""
if self.execution_failure_check(output):
feedback = f"[failure] Error in execution:\n{output}"
else:
feedback = "[success] Execution success, code output:\n" + output
return feedback
def execution_failure_check(self, feedback:str) -> bool:
"""
Check if the code execution failed.
"""
error_patterns = [
r"expected",
r"errno",
r"failed",
r"traceback",
r"invalid",
r"unrecognized",
r"exception",
r"syntax",
r"crash",
r"segmentation fault",
r"core dumped"
]
combined_pattern = "|".join(error_patterns)
if re.search(combined_pattern, feedback, re.IGNORECASE):
self.logger.error(f"Execution failure detected: {feedback}")
return True
self.logger.info("No execution success detected.")
return False
if __name__ == "__main__":
text = """
For Python, let's also do a quick check:
```python
print("Hello from Python!")
```
If these work, you'll see the outputs in the next message. Let me know if you'd like me to test anything specific!
here is a save test
```python:tmp.py
def print_hello():
hello = "Hello World"
print(hello)
if __name__ == "__main__":
print_hello()
```
"""
py = PyInterpreter()
codes, save_path = py.load_exec_block(text)
py.save_block(codes, save_path)
print(py.execute(codes))
================================================
FILE: sources/tools/__init__.py
================================================
from .PyInterpreter import PyInterpreter
from .BashInterpreter import BashInterpreter
from .fileFinder import FileFinder
__all__ = ["PyInterpreter", "BashInterpreter", "FileFinder", "webSearch", "FlightSearch", "GoInterpreter", "CInterpreter", "GoInterpreter"]
================================================
FILE: sources/tools/fileFinder.py
================================================
import os, sys
import stat
import mimetypes
import configparser
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class FileFinder(Tools):
"""
A tool that finds files in the current directory and returns their information.
"""
def __init__(self):
super().__init__()
self.tag = "file_finder"
self.name = "File Finder"
self.description = "Finds files in the current directory and returns their information."
def read_file(self, file_path: str) -> str:
"""
Reads the content of a file.
Args:
file_path (str): The path to the file to read
Returns:
str: The content of the file
"""
try:
with open(file_path, 'r') as file:
return file.read()
except Exception as e:
return f"Error reading file: {e}"
def read_arbitrary_file(self, file_path: str, file_type: str) -> str:
"""
Reads the content of a file with arbitrary encoding.
Args:
file_path (str): The path to the file to read
Returns:
str: The content of the file in markdown format
"""
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type:
if mime_type.startswith(('image/', 'video/', 'audio/')):
return "can't read file type: image, video, or audio files are not supported."
content_raw = self.read_file(file_path)
if "text" in file_type:
content = content_raw
elif "pdf" in file_type:
from pypdf import PdfReader
reader = PdfReader(file_path)
content = '\n'.join([pt.extract_text() for pt in reader.pages])
elif "binary" in file_type:
content = content_raw.decode('utf-8', errors='replace')
else:
content = content_raw
return content
def get_file_info(self, file_path: str) -> str:
"""
Gets information about a file, including its name, path, type, content, and permissions.
Args:
file_path (str): The path to the file
Returns:
str: A dictionary containing the file information
"""
if os.path.exists(file_path):
stats = os.stat(file_path)
permissions = oct(stat.S_IMODE(stats.st_mode))
file_type, _ = mimetypes.guess_type(file_path)
file_type = file_type if file_type else "Unknown"
content = self.read_arbitrary_file(file_path, file_type)
result = {
"filename": os.path.basename(file_path),
"path": file_path,
"type": file_type,
"read": content,
"permissions": permissions
}
return result
else:
return {"filename": file_path, "error": "File not found"}
def recursive_search(self, directory_path: str, filename: str) -> str:
"""
Recursively searches for files in a directory and its subdirectories.
Args:
directory_path (str): The directory to search in
filename (str): The filename to search for
Returns:
str | None: The path to the file if found, None otherwise
"""
file_path = None
excluded_files = [".pyc", ".o", ".so", ".a", ".lib", ".dll", ".dylib", ".so", ".git"]
for root, dirs, files in os.walk(directory_path):
for f in files:
if f is None:
continue
if any(excluded_file in f for excluded_file in excluded_files):
continue
if filename.strip() in f.strip():
file_path = os.path.join(root, f)
return file_path
return None
def execute(self, blocks: list, safety:bool = False) -> str:
"""
Executes the file finding operation for given filenames.
Args:
blocks (list): List of filenames to search for
Returns:
str: Results of the file search
"""
if not blocks or not isinstance(blocks, list):
return "Error: No valid filenames provided"
output = ""
for block in blocks:
filename = self.get_parameter_value(block, "name")
action = self.get_parameter_value(block, "action")
if filename is None:
output = "Error: No filename provided\n"
return output
if action is None:
action = "info"
print("File finder: recursive search started...")
file_path = self.recursive_search(self.work_dir, filename)
if file_path is None:
output = f"File: {filename} - not found\n"
continue
result = self.get_file_info(file_path)
if "error" in result:
output += f"File: {result['filename']} - {result['error']}\n"
else:
if action == "read":
output += "Content:\n" + result['read'] + "\n"
else:
output += (f"File: {result['filename']}, "
f"found at {result['path']}, "
f"File type {result['type']}\n")
return output.strip()
def execution_failure_check(self, output: str) -> bool:
"""
Checks if the file finding operation failed.
Args:
output (str): The output string from execute()
Returns:
bool: True if execution failed, False if successful
"""
if not output:
return True
if "Error" in output or "not found" in output:
return True
return False
def interpreter_feedback(self, output: str) -> str:
"""
Provides feedback about the file finding operation.
Args:
output (str): The output string from execute()
Returns:
str: Feedback message for the AI
"""
if not output:
return "No output generated from file finder tool"
feedback = "File Finder Results:\n"
if "Error" in output or "not found" in output:
feedback += f"Failed to process: {output}\n"
else:
feedback += f"Successfully found: {output}\n"
return feedback.strip()
if __name__ == "__main__":
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
tool = FileFinder()
result = tool.execute(["""
action=read
name=tools.py
"""], False)
print("Execution result:")
print(result)
print("\nFailure check:", tool.execution_failure_check(result))
print("\nFeedback:")
print(tool.interpreter_feedback(result))
================================================
FILE: sources/tools/flightSearch.py
================================================
import os, sys
import requests
import dotenv
dotenv.load_dotenv()
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class FlightSearch(Tools):
def __init__(self, api_key: str = None):
"""
A tool to search for flight information using a flight number via SerpApi.
"""
super().__init__()
self.tag = "flight_search"
self.name = "Flight Search"
self.description = "Search for flight information using a flight number via SerpApi."
self.api_key = api_key or os.getenv("SERPAPI_API_KEY")
def execute(self, blocks: str, safety: bool = True) -> str:
if self.api_key is None:
return "Error: No SerpApi key provided."
for block in blocks:
flight_number = block.strip().upper().replace('\n', '')
if not flight_number:
return "Error: No flight number provided."
try:
url = "https://serpapi.com/search"
params = {
"engine": "google_flights",
"api_key": self.api_key,
"q": flight_number,
"type": "2" # Flight status search
}
response = requests.get(url, params=params)
response.raise_for_status()
data = response.json()
if "flights" in data and len(data["flights"]) > 0:
flight = data["flights"][0]
# Extract key information
departure = flight.get("departure_airport", {})
arrival = flight.get("arrival_airport", {})
departure_code = departure.get("id", "Unknown")
departure_time = flight.get("departure_time", "Unknown")
arrival_code = arrival.get("id", "Unknown")
arrival_time = flight.get("arrival_time", "Unknown")
airline = flight.get("airline", "Unknown")
status = flight.get("flight_status", "Unknown")
return (
f"Flight: {flight_number}\n"
f"Airline: {airline}\n"
f"Status: {status}\n"
f"Departure: {departure_code} at {departure_time}\n"
f"Arrival: {arrival_code} at {arrival_time}"
)
else:
return f"No flight information found for {flight_number}"
except requests.RequestException as e:
return f"Error during flight search: {str(e)}"
except Exception as e:
return f"Unexpected error: {str(e)}"
return "No flight search performed"
def execution_failure_check(self, output: str) -> bool:
return output.startswith("Error") or "No flight information found" in output
def interpreter_feedback(self, output: str) -> str:
if self.execution_failure_check(output):
return f"Flight search failed: {output}"
return f"Flight information:\n{output}"
if __name__ == "__main__":
flight_tool = FlightSearch()
flight_number = "AA123"
result = flight_tool.execute([flight_number], safety=True)
feedback = flight_tool.interpreter_feedback(result)
print(feedback)
================================================
FILE: sources/tools/mcpFinder.py
================================================
import os, sys
import requests
from urllib.parse import urljoin
from typing import Dict, Any, Optional
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class MCP_finder(Tools):
"""
Tool to find MCPs server
"""
def __init__(self, api_key: str = None):
super().__init__()
self.tag = "mcp_finder"
self.name = "MCP Finder"
self.description = "Find MCP servers and their tools"
self.base_url = "https://registry.smithery.ai"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def _make_request(self, method: str, endpoint: str, params: Optional[Dict] = None,
data: Optional[Dict] = None) -> Dict[str, Any]:
url = urljoin(self.base_url.rstrip(), endpoint)
try:
response = requests.request(
method=method,
url=url,
headers=self.headers,
params=params,
json=data
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
raise requests.exceptions.HTTPError(f"API request failed: {str(e)}")
except requests.exceptions.RequestException as e:
raise requests.exceptions.RequestException(f"Network error: {str(e)}")
def list_mcp_servers(self, page: int = 1, page_size: int = 5000) -> Dict[str, Any]:
params = {"page": page, "pageSize": page_size}
return self._make_request("GET", "/servers", params=params)
def get_mcp_server_details(self, qualified_name: str) -> Dict[str, Any]:
endpoint = f"/servers/{qualified_name}"
return self._make_request("GET", endpoint)
def find_mcp_servers(self, query: str) -> Dict[str, Any]:
"""
Finds a specific MCP server by its name.
Args:
query (str): a name or string that more or less matches the MCP server name.
Returns:
Dict[str, Any]: The details of the found MCP server or an error message.
"""
mcps = self.list_mcp_servers()
matching_mcp = []
for mcp in mcps.get("servers", []):
name = mcp.get("qualifiedName", "")
if query.lower() in name.lower():
details = self.get_mcp_server_details(name)
matching_mcp.append(details)
return matching_mcp
def execute(self, blocks: list, safety:bool = False) -> str:
if not blocks or not isinstance(blocks, list):
return "Error: No blocks provided\n"
output = ""
for block in blocks:
block_clean = block.strip().lower().replace('\n', '')
try:
matching_mcp_infos = self.find_mcp_servers(block_clean)
except requests.exceptions.RequestException as e:
output += "Connection failed. Is the API key in environment?\n"
continue
except Exception as e:
output += f"Error: {str(e)}\n"
continue
if matching_mcp_infos == []:
output += f"Error: No MCP server found for query '{block}'\n"
continue
for mcp_infos in matching_mcp_infos:
if mcp_infos['tools'] is None:
continue
output += f"Name: {mcp_infos['displayName']}\n"
output += f"Usage name: {mcp_infos['qualifiedName']}\n"
output += f"Tools: {mcp_infos['tools']}"
output += "\n-------\n"
return output.strip()
def execution_failure_check(self, output: str) -> bool:
output = output.strip().lower()
if not output:
return True
if "error" in output or "not found" in output:
return True
return False
def interpreter_feedback(self, output: str) -> str:
"""
Not really needed for this tool (use return of execute() directly)
"""
if not output:
raise ValueError("No output to interpret.")
return f"""
The following MCPs were found:
{output}
"""
if __name__ == "__main__":
api_key = os.getenv("MCP_FINDER")
tool = MCP_finder(api_key)
result = tool.execute(["""
stock
"""], False)
print(result)
================================================
FILE: sources/tools/safety.py
================================================
import os
import sys
unsafe_commands_unix = [
"rm", # File/directory removal
"dd", # Low-level disk writing
"mkfs", # Filesystem formatting
"chmod", # Permission changes
"chown", # Ownership changes
"shutdown", # System shutdown
"reboot", # System reboot
"halt", # System halt
"sysctl", # Kernel parameter changes
"kill", # Process termination
"pkill", # Kill by process name
"killall", # Kill all matching processes
"exec", # Replace process with command
"tee", # Write to files with privileges
"umount", # Unmount filesystems
"passwd", # Password changes
"useradd", # Add users
"userdel", # Delete users
"brew", # Homebrew package manager
"groupadd", # Add groups
"groupdel", # Delete groups
"visudo", # Edit sudoers file
"screen", # Terminal session management
"fdisk", # Disk partitioning
"parted", # Disk partitioning
"chroot", # Change root directory
"route" # Routing table management
"--force", # Force flag for many commands
"rebase", # Rebase git repository
"git" # Git commands
]
unsafe_commands_windows = [
"del", # Deletes files
"erase", # Alias for del, deletes files
"rd", # Removes directories (rmdir alias)
"rmdir", # Removes directories
"format", # Formats a disk, erasing data
"diskpart", # Manages disk partitions, can wipe drives
"chkdsk /f", # Fixes filesystem, can alter data
"fsutil", # File system utilities, can modify system files
"xcopy /y", # Copies files, overwriting without prompt
"copy /y", # Copies files, overwriting without prompt
"move", # Moves files, can overwrite
"attrib", # Changes file attributes, e.g., hiding or exposing files
"icacls", # Changes file permissions (modern)
"takeown", # Takes ownership of files
"reg delete", # Deletes registry keys/values
"regedit /s", # Silently imports registry changes
"shutdown", # Shuts down or restarts the system
"schtasks", # Schedules tasks, can run malicious commands
"taskkill", # Kills processes
"wmic", # Deletes processes via WMI
"bcdedit", # Modifies boot configuration
"powercfg", # Changes power settings, can disable protections
"assoc", # Changes file associations
"ftype", # Changes file type commands
"cipher /w", # Wipes free space, erasing data
"esentutl", # Database utilities, can corrupt system files
"subst", # Substitutes drive paths, can confuse system
"mklink", # Creates symbolic links, can redirect access
"bootcfg"
]
def is_any_unsafe(cmds):
"""
check if any bash command is unsafe.
"""
for cmd in cmds:
if is_unsafe(cmd):
return True
return False
def is_unsafe(cmd):
"""
check if a bash command is unsafe.
"""
if sys.platform.startswith("win"):
if any(c in cmd for c in unsafe_commands_windows):
return True
else:
if any(c in cmd for c in unsafe_commands_unix):
return True
return False
if __name__ == "__main__":
cmd = input("Enter a command: ")
if is_unsafe(cmd):
print("Unsafe command detected!")
else:
print("Command is safe to execute.")
================================================
FILE: sources/tools/searxSearch.py
================================================
import requests
from bs4 import BeautifulSoup
import os
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class searxSearch(Tools):
def __init__(self, base_url: str = None):
"""
A tool for searching a SearxNG instance and extracting URLs and titles.
"""
super().__init__()
self.tag = "web_search"
self.name = "searxSearch"
self.description = "A tool for searching a SearxNG for web search"
self.base_url = os.getenv("SEARXNG_BASE_URL") # Requires a SearxNG base URL
self.user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36"
self.paywall_keywords = [
"Member-only", "access denied", "restricted content", "404", "this page is not working"
]
if not self.base_url:
raise ValueError("SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.")
def link_valid(self, link):
"""check if a link is valid."""
# TODO find a better way
if not link.startswith("http"):
return "Status: Invalid URL"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
try:
response = requests.get(link, headers=headers, timeout=5)
status = response.status_code
if status == 200:
content = response.text.lower()
if any(keyword in content for keyword in self.paywall_keywords):
return "Status: Possible Paywall"
return "Status: OK"
elif status == 404:
return "Status: 404 Not Found"
elif status == 403:
return "Status: 403 Forbidden"
else:
return f"Status: {status} {response.reason}"
except requests.exceptions.RequestException as e:
return f"Error: {str(e)}"
def check_all_links(self, links):
"""Check all links, one by one."""
# TODO Make it asyncromous or smth
statuses = []
for i, link in enumerate(links):
status = self.link_valid(link)
statuses.append(status)
return statuses
def execute(self, blocks: list, safety: bool = False) -> str:
"""Executes a search query against a SearxNG instance using POST and extracts URLs and titles."""
if not blocks:
return "Error: No search query provided."
query = blocks[0].strip()
if not query:
return "Error: Empty search query provided."
search_url = f"{self.base_url}/search"
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'en-US,en;q=0.9',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
'Pragma': 'no-cache',
'Upgrade-Insecure-Requests': '1',
'User-Agent': self.user_agent
}
data = f"q={query}&categories=general&language=auto&time_range=&safesearch=0&theme=simple".encode('utf-8')
try:
response = requests.post(search_url, headers=headers, data=data, verify=False)
response.raise_for_status()
html_content = response.text
soup = BeautifulSoup(html_content, 'html.parser')
results = []
for article in soup.find_all('article', class_='result'):
url_header = article.find('a', class_='url_header')
if url_header:
url = url_header['href']
title = article.find('h3').text.strip() if article.find('h3') else "No Title"
description = article.find('p', class_='content').text.strip() if article.find('p', class_='content') else "No Description"
results.append(f"Title:{title}\nSnippet:{description}\nLink:{url}")
if len(results) == 0:
return "No search results, web search failed."
return "\n\n".join(results) # Return results as a single string, separated by newlines
except requests.exceptions.RequestException as e:
raise Exception("\nSearxng search failed. did you run start_services.sh? is docker still running?") from e
def execution_failure_check(self, output: str) -> bool:
"""
Checks if the execution failed based on the output.
"""
return "Error" in output
def interpreter_feedback(self, output: str) -> str:
"""
Feedback of web search to agent.
"""
if self.execution_failure_check(output):
return f"Web search failed: {output}"
return f"Web search result:\n{output}"
if __name__ == "__main__":
search_tool = searxSearch(base_url="http://127.0.0.1:8080")
result = search_tool.execute(["are dog better than cat?"])
print(result)
================================================
FILE: sources/tools/tools.py
================================================
"""
define a generic tool class, any tool can be used by the agent.
A tool can be used by a llm like so:
```
```
we call these "blocks".
For example:
```python
print("Hello world")
```
This is then executed by the tool with its own class implementation of execute().
A tool is not just for code tool but also API, internet search, MCP, etc..
"""
import sys
import os
import configparser
from abc import abstractmethod
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from sources.logger import Logger
class Tools():
"""
Abstract class for all tools.
"""
def __init__(self):
self.tag = "undefined"
self.name = "undefined"
self.description = "undefined"
self.client = None
self.messages = []
self.logger = Logger("tools.log")
self.config = configparser.ConfigParser()
self.work_dir = self.create_work_dir()
self.excutable_blocks_found = False
self.safe_mode = False
self.allow_language_exec_bash = False
def get_work_dir(self):
return self.work_dir
def set_allow_language_exec_bash(self, value: bool) -> None:
self.allow_language_exec_bash = value
def safe_get_work_dir_path(self):
path = None
path = os.getenv('WORK_DIR', path)
if path is None or path == "":
path = self.config['MAIN']['work_dir'] if 'MAIN' in self.config and 'work_dir' in self.config['MAIN'] else None
if path is None or path == "":
raise Exception("No work dir specified, please specify a work dir in .env file.")
return path
def config_exists(self):
"""Check if the config file exists."""
return os.path.exists('./config.ini')
def create_work_dir(self):
"""Create the work directory if it does not exist."""
default_path = os.path.dirname(os.getcwd())
if self.config_exists():
self.config.read('./config.ini')
workdir_path = self.safe_get_work_dir_path()
else:
workdir_path = default_path
return workdir_path
@abstractmethod
def execute(self, blocks:[str], safety:bool) -> str:
"""
Abstract method that must be implemented by child classes to execute the tool's functionality.
Args:
blocks (List[str]): The codes or queries blocks to execute
safety (bool): Whenever human intervention is required
Returns:
str: The output/result from executing the tool
"""
pass
@abstractmethod
def execution_failure_check(self, output:str) -> bool:
"""
Abstract method that must be implemented by child classes to check if tool execution failed.
Args:
output (str): The output string from the tool execution to analyze
Returns:
bool: True if execution failed, False if successful
"""
pass
@abstractmethod
def interpreter_feedback(self, output:str) -> str:
"""
Abstract method that must be implemented by child classes to provide feedback to the AI from the tool.
Args:
output (str): The output string from the tool execution to analyze
Returns:
str: The feedback message to the AI
"""
pass
def save_block(self, blocks:[str], save_path:str) -> None:
"""
Save code or query blocks to a file at the specified path.
Creates the directory path if it doesn't exist.
Args:
blocks (List[str]): List of code/query blocks to save
save_path (str): File path where blocks should be saved
"""
if save_path is None:
return
self.logger.info(f"Saving blocks to {save_path}")
save_path_dir = os.path.dirname(save_path)
save_path_file = os.path.basename(save_path)
directory = os.path.join(self.work_dir, save_path_dir)
if directory and not os.path.exists(directory):
self.logger.info(f"Creating directory {directory}")
os.makedirs(directory)
for block in blocks:
with open(os.path.join(directory, save_path_file), 'w') as f:
f.write(block)
def get_parameter_value(self, block: str, parameter_name: str) -> str:
"""
Get a parameter name.
Args:
block (str): The block of text to search for the parameter
parameter_name (str): The name of the parameter to retrieve
Returns:
str: The value of the parameter
"""
for param_line in block.split('\n'):
if parameter_name in param_line:
param_value = param_line.split('=')[1].strip()
return param_value
return None
def found_executable_blocks(self):
"""
Check if executable blocks were found.
"""
tmp = self.excutable_blocks_found
self.excutable_blocks_found = False
return tmp
def load_exec_block(self, llm_text: str):
"""
Extract code/query blocks from LLM-generated text and process them for execution.
This method parses the text looking for code blocks marked with the tool's tag (e.g. ```python).
Args:
llm_text (str): The raw text containing code blocks from the LLM
Returns:
tuple[list[str], str | None]: A tuple containing:
- List of extracted and processed code blocks
- The path the code blocks was saved to
"""
assert self.tag != "undefined", "Tag not defined"
start_tag = f'```{self.tag}'
end_tag = '```'
code_blocks = []
start_index = 0
save_path = None
if start_tag not in llm_text:
return None, None
while True:
start_pos = llm_text.find(start_tag, start_index)
if start_pos == -1:
break
line_start = llm_text.rfind('\n', 0, start_pos)+1
leading_whitespace = llm_text[line_start:start_pos]
end_pos = llm_text.find(end_tag, start_pos + len(start_tag))
if end_pos == -1:
break
content = llm_text[start_pos + len(start_tag):end_pos]
lines = content.split('\n')
if leading_whitespace:
processed_lines = []
for line in lines:
if line.startswith(leading_whitespace):
processed_lines.append(line[len(leading_whitespace):])
else:
processed_lines.append(line)
content = '\n'.join(processed_lines)
if ':' in content.split('\n')[0]:
save_path = content.split('\n')[0].split(':')[1]
content = content[content.find('\n')+1:]
self.excutable_blocks_found = True
code_blocks.append(content)
start_index = end_pos + len(end_tag)
self.logger.info(f"Found {len(code_blocks)} blocks to execute")
return code_blocks, save_path
if __name__ == "__main__":
tool = Tools()
tool.tag = "python"
rt = tool.load_exec_block("""```python
import os
for file in os.listdir():
if file.endswith('.py'):
print(file)
```
goodbye!
""")
print(rt)
================================================
FILE: sources/tools/webSearch.py
================================================
import os
import requests
import dotenv
dotenv.load_dotenv()
from sources.tools.tools import Tools
from sources.utility import animate_thinking, pretty_print
"""
WARNING
webSearch is fully deprecated and is being replaced by searxSearch for web search.
"""
class webSearch(Tools):
def __init__(self, api_key: str = None):
"""
A tool to perform a Google search and return information from the first result.
"""
super().__init__()
self.tag = "web_search"
self.api_key = api_key or os.getenv("SERPAPI_KEY") # Requires a SerpApi key
self.paywall_keywords = [
"subscribe", "login to continue", "access denied", "restricted content", "404", "this page is not working"
]
def link_valid(self, link):
"""check if a link is valid."""
if not link.startswith("http"):
return "Status: Invalid URL"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
try:
response = requests.get(link, headers=headers, timeout=5)
status = response.status_code
if status == 200:
content = response.text[:1000].lower()
if any(keyword in content for keyword in self.paywall_keywords):
return "Status: Possible Paywall"
return "Status: OK"
elif status == 404:
return "Status: 404 Not Found"
elif status == 403:
return "Status: 403 Forbidden"
else:
return f"Status: {status} {response.reason}"
except requests.exceptions.RequestException as e:
return f"Error: {str(e)}"
def check_all_links(self, links):
"""Check all links, one by one."""
# TODO Make it asyncromous or smth
statuses = []
for i, link in enumerate(links):
status = self.link_valid(link)
statuses.append(status)
return statuses
def execute(self, blocks: str, safety: bool = True) -> str:
if self.api_key is None:
return "Error: No SerpApi key provided."
for block in blocks:
query = block.strip()
pretty_print(f"Searching for: {query}", color="status")
if not query:
return "Error: No search query provided."
try:
url = "https://serpapi.com/search"
params = {
"q": query,
"api_key": self.api_key,
"num": 50,
"output": "json"
}
response = requests.get(url, params=params)
response.raise_for_status()
data = response.json()
results = []
if "organic_results" in data and len(data["organic_results"]) > 0:
organic_results = data["organic_results"][:50]
links = [result.get("link", "No link available") for result in organic_results]
statuses = self.check_all_links(links)
for result, status in zip(organic_results, statuses):
if not "OK" in status:
continue
title = result.get("title", "No title")
snippet = result.get("snippet", "No snippet available")
link = result.get("link", "No link available")
results.append(f"Title:{title}\nSnippet:{snippet}\nLink:{link}")
return "\n\n".join(results)
else:
return "No results found for the query."
except requests.RequestException as e:
return f"Error during web search: {str(e)}"
except Exception as e:
return f"Unexpected error: {str(e)}"
return "No search performed"
def execution_failure_check(self, output: str) -> bool:
return output.startswith("Error") or "No results found" in output
def interpreter_feedback(self, output: str) -> str:
if self.execution_failure_check(output):
return f"Web search failed: {output}"
return f"Web search result:\n{output}"
if __name__ == "__main__":
search_tool = webSearch(api_key=os.getenv("SERPAPI_KEY"))
query = "when did covid start"
result = search_tool.execute([query], safety=True)
output = search_tool.interpreter_feedback(result)
print(output)
================================================
FILE: sources/utility.py
================================================
from colorama import Fore
from termcolor import colored
import platform
import threading
import itertools
import time
thinking_event = threading.Event()
current_animation_thread = None
def get_color_map():
if platform.system().lower() != "windows":
color_map = {
"success": "green",
"failure": "red",
"status": "light_green",
"code": "light_blue",
"warning": "yellow",
"output": "cyan",
"info": "cyan"
}
else:
color_map = {
"success": "green",
"failure": "red",
"status": "light_green",
"code": "light_blue",
"warning": "yellow",
"output": "cyan",
"info": "black"
}
return color_map
def pretty_print(text, color="info", no_newline=False):
"""
Print text with color formatting.
Args:
text (str): The text to print
color (str, optional): The color to use. Defaults to "info".
Valid colors are:
- "success": Green
- "failure": Red
- "status": Light green
- "code": Light blue
- "warning": Yellow
- "output": Cyan
- "default": Black (Windows only)
"""
thinking_event.set()
if current_animation_thread and current_animation_thread.is_alive():
current_animation_thread.join()
thinking_event.clear()
color_map = get_color_map()
if color not in color_map:
color = "info"
print(colored(text, color_map[color]), end='' if no_newline else "\n")
def animate_thinking(text, color="status", duration=120):
"""
Animate a thinking spinner while a task is being executed.
It use a daemon thread to run the animation. This will not block the main thread.
Color are the same as pretty_print.
"""
global current_animation_thread
thinking_event.set()
if current_animation_thread and current_animation_thread.is_alive():
current_animation_thread.join()
thinking_event.clear()
def _animate():
color_map = {
"success": (Fore.GREEN, "green"),
"failure": (Fore.RED, "red"),
"status": (Fore.LIGHTGREEN_EX, "light_green"),
"code": (Fore.LIGHTBLUE_EX, "light_blue"),
"warning": (Fore.YELLOW, "yellow"),
"output": (Fore.LIGHTCYAN_EX, "cyan"),
"default": (Fore.RESET, "black"),
"info": (Fore.CYAN, "cyan")
}
fore_color, term_color = color_map.get(color, color_map["default"])
spinner = itertools.cycle([
'▉▁▁▁▁▁', '▉▉▂▁▁▁', '▉▉▉▃▁▁', '▉▉▉▉▅▁', '▉▉▉▉▉▇', '▉▉▉▉▉▉',
'▉▉▉▉▇▅', '▉▉▉▆▃▁', '▉▉▅▃▁▁', '▉▇▃▁▁▁', '▇▃▁▁▁▁', '▃▁▁▁▁▁',
'▁▃▅▃▁▁', '▁▅▉▅▁▁', '▃▉▉▉▃▁', '▅▉▁▉▅▃', '▇▃▁▃▇▅', '▉▁▁▁▉▇',
'▉▅▃▁▃▅', '▇▉▅▃▅▇', '▅▉▇▅▇▉', '▃▇▉▇▉▅', '▁▅▇▉▇▃', '▁▃▅▇▅▁'
])
end_time = time.time() + duration
while not thinking_event.is_set() and time.time() < end_time:
symbol = next(spinner)
if platform.system().lower() != "windows":
print(f"\r{fore_color}{symbol} {text}{Fore.RESET}", end="", flush=True)
else:
print(f"\r{colored(f'{symbol} {text}', term_color)}", end="", flush=True)
time.sleep(0.2)
print("\r" + " " * (len(text) + 7) + "\r", end="", flush=True)
current_animation_thread = threading.Thread(target=_animate, daemon=True)
current_animation_thread.start()
def timer_decorator(func):
"""
Decorator to measure the execution time of a function.
Usage:
@timer_decorator
def my_function():
# code to execute
"""
from time import time
def wrapper(*args, **kwargs):
start_time = time()
result = func(*args, **kwargs)
end_time = time()
pretty_print(f"{func.__name__} took {end_time - start_time:.2f} seconds to execute", "status")
return result
return wrapper
if __name__ == "__main__":
import time
pretty_print("starting imaginary task", "success")
animate_thinking("Thinking...", "status")
time.sleep(4)
pretty_print("starting another task", "failure")
animate_thinking("Thinking...", "status")
time.sleep(4)
pretty_print("yet another task", "info")
animate_thinking("Thinking...", "status")
time.sleep(4)
pretty_print("This is an info message", "info")
================================================
FILE: sources/web_scripts/find_inputs.js
================================================
function findInputs(element, result = []) {
// Find all elements in the current DOM tree
const inputs = element.querySelectorAll('input');
inputs.forEach(input => {
result.push({
tagName: input.tagName,
text: input.name || '',
type: input.type || '',
class: input.className || '',
xpath: getXPath(input),
displayed: isElementDisplayed(input)
});
});
// Find all