mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-06-23 00:02:10 -04:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b666d16db5 | ||
|
cd70db29ed | ||
|
fb72ba1ff5 | ||
|
b968d45c11 | ||
|
228d5379cf | ||
|
dd820ef7c4 | ||
|
a7cbc8c3fd | ||
|
4d171835ac | ||
|
0c28ee7059 | ||
|
96aeb44210 | ||
|
29f29773af | ||
|
d8c04cead8 | ||
|
b1cb46ec2a | ||
|
b83d06e67f | ||
|
7aa339cf40 | ||
|
1b84182030 | ||
|
02e12089d3 | ||
|
09f37a0ff8 | ||
|
5e7e4b3f78 | ||
|
22ebd42c32 | ||
|
051a63f031 | ||
|
26356f872e | ||
|
22b8bc546f | ||
|
52164142de | ||
|
be6347389e | ||
|
8c10eccd24 | ||
|
6ef0bd518e | ||
|
04dc157b98 | ||
|
014bf67c63 | ||
|
8c9f26e249 | ||
|
d4e6a6e485 | ||
|
a081255951 | ||
|
36c852b8be | ||
|
c38c7455d8 | ||
|
9131f4c432 | ||
|
6bfa014594 | ||
|
5af31278b7 | ||
|
a80f023ed2 | ||
|
126042fdc9 |
@ -1,7 +1,7 @@
|
||||
version: 2.1
|
||||
setup: true
|
||||
orbs:
|
||||
path-filtering: circleci/path-filtering@1.1.0
|
||||
path-filtering: circleci/path-filtering@1.3.0
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
|
@ -18,6 +18,68 @@ parameters:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
job-macos-executor: &job-macos-executor
|
||||
macos:
|
||||
xcode: 16.2.0
|
||||
resource_class: macos.m1.medium.gen1
|
||||
environment:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
|
||||
job-macos-install-deps: &job-macos-install-deps
|
||||
name: Install basic macOS build dependencies
|
||||
command: brew install ccache llvm wget
|
||||
|
||||
job-linux-install-chat-deps: &job-linux-install-chat-deps
|
||||
name: Install Linux build dependencies for gpt4all-chat
|
||||
command: |
|
||||
# Prevent apt-get from interactively prompting for service restart
|
||||
echo "\$nrconf{restart} = 'l'" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf >/dev/null
|
||||
wget -qO- 'https://apt.llvm.org/llvm-snapshot.gpg.key' | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc >/dev/null
|
||||
sudo add-apt-repository -yn 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main'
|
||||
wget -qO- "https://packages.lunarg.com/lunarg-signing-key-pub.asc" \
|
||||
| sudo tee /etc/apt/trusted.gpg.d/lunarg.asc >/dev/null
|
||||
wget -qO- "https://packages.lunarg.com/vulkan/1.3.290/lunarg-vulkan-1.3.290-jammy.list" \
|
||||
| sudo tee /etc/apt/sources.list.d/lunarg-vulkan-1.3.290-jammy.list >/dev/null
|
||||
wget "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb"
|
||||
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||
packages=(
|
||||
bison build-essential ccache clang-19 clang-tools-19 cuda-compiler-11-8 flex gperf libcublas-dev-11-8
|
||||
libfontconfig1 libfreetype6 libgl1-mesa-dev libmysqlclient21 libnvidia-compute-550-server libodbc2 libpq5
|
||||
libstdc++-12-dev libwayland-dev libx11-6 libx11-xcb1 libxcb-cursor0 libxcb-glx0 libxcb-icccm4 libxcb-image0
|
||||
libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1
|
||||
libxcb-xfixes0 libxcb-xinerama0 libxcb-xkb1 libxcb1 libxext6 libxfixes3 libxi6 libxkbcommon-dev libxkbcommon-x11-0
|
||||
libxrender1 patchelf python3 vulkan-sdk python3 vulkan-sdk
|
||||
)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "${packages[@]}"
|
||||
wget "https://qt.mirror.constant.com/archive/online_installers/4.8/qt-online-installer-linux-x64-4.8.1.run"
|
||||
chmod +x qt-online-installer-linux-x64-4.8.1.run
|
||||
./qt-online-installer-linux-x64-4.8.1.run --no-force-installations --no-default-installations \
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations \
|
||||
--email "$QT_EMAIL" --password "$QT_PASSWORD" install \
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.linux_gcc_64 qt.qt6.682.addons.qt5compat \
|
||||
qt.qt6.682.debug_info extensions.qtpdf.682 qt.qt6.682.addons.qthttpserver
|
||||
|
||||
job-linux-install-backend-deps: &job-linux-install-backend-deps
|
||||
name: Install Linux build dependencies for gpt4all-backend
|
||||
command: |
|
||||
wget -qO- 'https://apt.llvm.org/llvm-snapshot.gpg.key' | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc >/dev/null
|
||||
sudo add-apt-repository -yn 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main'
|
||||
wget -qO- "https://packages.lunarg.com/lunarg-signing-key-pub.asc" \
|
||||
| sudo tee /etc/apt/trusted.gpg.d/lunarg.asc >/dev/null
|
||||
wget -qO- "https://packages.lunarg.com/vulkan/1.3.290/lunarg-vulkan-1.3.290-jammy.list" \
|
||||
| sudo tee /etc/apt/sources.list.d/lunarg-vulkan-1.3.290-jammy.list >/dev/null
|
||||
wget "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb"
|
||||
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||
packages=(
|
||||
build-essential ccache clang-19 clang-tools-19 cuda-compiler-11-8 libcublas-dev-11-8
|
||||
libnvidia-compute-550-server libstdc++-12-dev vulkan-sdk
|
||||
)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "${packages[@]}"
|
||||
pyenv global 3.13.2
|
||||
pip install setuptools wheel cmake ninja
|
||||
|
||||
jobs:
|
||||
# work around CircleCI-Public/path-filtering-orb#20
|
||||
noop:
|
||||
@ -34,8 +96,7 @@ jobs:
|
||||
name: Verify that commit is on the main branch
|
||||
command: git merge-base --is-ancestor HEAD main
|
||||
build-offline-chat-installer-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@ -46,12 +107,11 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- ccache-gpt4all-macos-
|
||||
- run:
|
||||
<<: *job-macos-install-deps
|
||||
- run:
|
||||
name: Install Rosetta
|
||||
command: softwareupdate --install-rosetta --agree-to-license # needed for QtIFW
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: brew install ccache wget
|
||||
- run:
|
||||
name: Installing Qt
|
||||
command: |
|
||||
@ -61,8 +121,8 @@ jobs:
|
||||
--no-force-installations --no-default-installations --no-size-checking --default-answer \
|
||||
--accept-licenses --confirm-command --accept-obligations --email "$QT_EMAIL" --password "$QT_PASSWORD" \
|
||||
install \
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.clang_64 qt.qt6.681.addons.qt5compat \
|
||||
extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.clang_64 qt.qt6.682.addons.qt5compat \
|
||||
extensions.qtpdf.682 qt.qt6.682.addons.qthttpserver
|
||||
hdiutil detach /Volumes/qt-online-installer-macOS-x64-4.8.1
|
||||
- run:
|
||||
name: Setup Keychain
|
||||
@ -84,14 +144,17 @@ jobs:
|
||||
~/Qt/Tools/CMake/CMake.app/Contents/bin/cmake \
|
||||
-S ../gpt4all-chat -B . -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH:PATH=~/Qt/6.8.1/macos/lib/cmake \
|
||||
-DCMAKE_PREFIX_PATH:PATH=~/Qt/6.8.2/macos/lib/cmake \
|
||||
-DCMAKE_MAKE_PROGRAM:FILEPATH=~/Qt/Tools/Ninja/ninja \
|
||||
-DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ \
|
||||
-DCMAKE_RANLIB=/usr/bin/ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DBUILD_UNIVERSAL=ON \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=12.6 \
|
||||
-DGGML_METAL_MACOSX_VERSION_MIN=12.6 \
|
||||
-DMACDEPLOYQT=~/Qt/6.8.1/macos/bin/macdeployqt \
|
||||
-DMACDEPLOYQT=~/Qt/6.8.2/macos/bin/macdeployqt \
|
||||
-DGPT4ALL_OFFLINE_INSTALLER=ON \
|
||||
-DGPT4ALL_SIGN_INSTALL=ON \
|
||||
-DGPT4ALL_GEN_CPACK_CONFIG=ON
|
||||
@ -128,8 +191,7 @@ jobs:
|
||||
- upload
|
||||
|
||||
sign-offline-chat-installer-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
# attach to a workspace containing unsigned dmg
|
||||
@ -163,8 +225,7 @@ jobs:
|
||||
- upload
|
||||
|
||||
notarize-offline-chat-installer-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
@ -203,8 +264,7 @@ jobs:
|
||||
hdiutil detach /Volumes/gpt4all-installer-darwin
|
||||
|
||||
build-online-chat-installer-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@ -215,12 +275,11 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- ccache-gpt4all-macos-
|
||||
- run:
|
||||
<<: *job-macos-install-deps
|
||||
- run:
|
||||
name: Install Rosetta
|
||||
command: softwareupdate --install-rosetta --agree-to-license # needed for QtIFW
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: brew install ccache wget
|
||||
- run:
|
||||
name: Installing Qt
|
||||
command: |
|
||||
@ -230,8 +289,8 @@ jobs:
|
||||
--no-force-installations --no-default-installations --no-size-checking --default-answer \
|
||||
--accept-licenses --confirm-command --accept-obligations --email "$QT_EMAIL" --password "$QT_PASSWORD" \
|
||||
install \
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.clang_64 qt.qt6.681.addons.qt5compat \
|
||||
extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.clang_64 qt.qt6.682.addons.qt5compat \
|
||||
extensions.qtpdf.682 qt.qt6.682.addons.qthttpserver
|
||||
hdiutil detach /Volumes/qt-online-installer-macOS-x64-4.8.1
|
||||
- run:
|
||||
name: Setup Keychain
|
||||
@ -253,14 +312,17 @@ jobs:
|
||||
~/Qt/Tools/CMake/CMake.app/Contents/bin/cmake \
|
||||
-S ../gpt4all-chat -B . -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH:PATH=~/Qt/6.8.1/macos/lib/cmake \
|
||||
-DCMAKE_PREFIX_PATH:PATH=~/Qt/6.8.2/macos/lib/cmake \
|
||||
-DCMAKE_MAKE_PROGRAM:FILEPATH=~/Qt/Tools/Ninja/ninja \
|
||||
-DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ \
|
||||
-DCMAKE_RANLIB=/usr/bin/ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DBUILD_UNIVERSAL=ON \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=12.6 \
|
||||
-DGGML_METAL_MACOSX_VERSION_MIN=12.6 \
|
||||
-DMACDEPLOYQT=~/Qt/6.8.1/macos/bin/macdeployqt \
|
||||
-DMACDEPLOYQT=~/Qt/6.8.2/macos/bin/macdeployqt \
|
||||
-DGPT4ALL_OFFLINE_INSTALLER=OFF \
|
||||
-DGPT4ALL_SIGN_INSTALL=ON \
|
||||
-DGPT4ALL_GEN_CPACK_CONFIG=ON
|
||||
@ -290,8 +352,7 @@ jobs:
|
||||
- upload
|
||||
|
||||
sign-online-chat-installer-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
# attach to a workspace containing unsigned dmg
|
||||
@ -325,8 +386,7 @@ jobs:
|
||||
- upload
|
||||
|
||||
notarize-online-chat-installer-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
@ -379,34 +439,7 @@ jobs:
|
||||
keys:
|
||||
- ccache-gpt4all-linux-amd64-
|
||||
- run:
|
||||
name: Setup Linux and Dependencies
|
||||
command: |
|
||||
# Prevent apt-get from interactively prompting for service restart
|
||||
echo "\$nrconf{restart} = 'l'" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf >/dev/null
|
||||
wget -qO- "https://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
|
||||
wget -qO- "https://packages.lunarg.com/vulkan/1.3.290/lunarg-vulkan-1.3.290-jammy.list" | sudo tee /etc/apt/sources.list.d/lunarg-vulkan-1.3.290-jammy.list
|
||||
wget "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb"
|
||||
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||
packages=(
|
||||
bison build-essential ccache cuda-compiler-11-8 flex g++-12 gperf libcublas-dev-11-8 libfontconfig1
|
||||
libfreetype6 libgl1-mesa-dev libmysqlclient21 libnvidia-compute-550-server libodbc2 libpq5 libwayland-dev
|
||||
libx11-6 libx11-xcb1 libxcb-cursor0 libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0
|
||||
libxcb-render-util0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 libxcb-xinerama0
|
||||
libxcb-xkb1 libxcb1 libxext6 libxfixes3 libxi6 libxkbcommon-dev libxkbcommon-x11-0 libxrender1 patchelf
|
||||
python3 vulkan-sdk
|
||||
)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "${packages[@]}"
|
||||
- run:
|
||||
name: Installing Qt
|
||||
command: |
|
||||
wget "https://qt.mirror.constant.com/archive/online_installers/4.8/qt-online-installer-linux-x64-4.8.1.run"
|
||||
chmod +x qt-online-installer-linux-x64-4.8.1.run
|
||||
./qt-online-installer-linux-x64-4.8.1.run --no-force-installations --no-default-installations \
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations \
|
||||
--email "$QT_EMAIL" --password "$QT_PASSWORD" install \
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.linux_gcc_64 qt.qt6.681.addons.qt5compat \
|
||||
qt.qt6.681.debug_info extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
<<: *job-linux-install-chat-deps
|
||||
- run:
|
||||
name: Build linuxdeployqt
|
||||
command: |
|
||||
@ -417,7 +450,7 @@ jobs:
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
set -eo pipefail
|
||||
export CMAKE_PREFIX_PATH=~/Qt/6.8.1/gcc_64/lib/cmake
|
||||
export CMAKE_PREFIX_PATH=~/Qt/6.8.2/gcc_64/lib/cmake
|
||||
export PATH=$PATH:$HOME/Qt/Tools/QtInstallerFramework/4.8/bin
|
||||
export PATH=$PATH:/usr/local/cuda/bin
|
||||
ccache -o "cache_dir=${PWD}/../.ccache" -o max_size=500M -p -z
|
||||
@ -427,8 +460,10 @@ jobs:
|
||||
~/Qt/Tools/CMake/bin/cmake \
|
||||
-S ../gpt4all-chat -B . \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=gcc-12 \
|
||||
-DCMAKE_CXX_COMPILER=g++-12 \
|
||||
-DCMAKE_C_COMPILER=clang-19 \
|
||||
-DCMAKE_CXX_COMPILER=clang++-19 \
|
||||
-DCMAKE_CXX_COMPILER_AR=ar \
|
||||
-DCMAKE_CXX_COMPILER_RANLIB=ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CUDA_COMPILER_LAUNCHER=ccache \
|
||||
@ -468,34 +503,7 @@ jobs:
|
||||
keys:
|
||||
- ccache-gpt4all-linux-amd64-
|
||||
- run:
|
||||
name: Setup Linux and Dependencies
|
||||
command: |
|
||||
# Prevent apt-get from interactively prompting for service restart
|
||||
echo "\$nrconf{restart} = 'l'" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf >/dev/null
|
||||
wget -qO- "https://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
|
||||
wget -qO- "https://packages.lunarg.com/vulkan/1.3.290/lunarg-vulkan-1.3.290-jammy.list" | sudo tee /etc/apt/sources.list.d/lunarg-vulkan-1.3.290-jammy.list
|
||||
wget "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb"
|
||||
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||
packages=(
|
||||
bison build-essential ccache cuda-compiler-11-8 flex g++-12 gperf libcublas-dev-11-8 libfontconfig1
|
||||
libfreetype6 libgl1-mesa-dev libmysqlclient21 libnvidia-compute-550-server libodbc2 libpq5 libwayland-dev
|
||||
libx11-6 libx11-xcb1 libxcb-cursor0 libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0
|
||||
libxcb-render-util0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 libxcb-xinerama0
|
||||
libxcb-xkb1 libxcb1 libxext6 libxfixes3 libxi6 libxkbcommon-dev libxkbcommon-x11-0 libxrender1 patchelf
|
||||
python3 vulkan-sdk
|
||||
)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "${packages[@]}"
|
||||
- run:
|
||||
name: Installing Qt
|
||||
command: |
|
||||
wget "https://qt.mirror.constant.com/archive/online_installers/4.8/qt-online-installer-linux-x64-4.8.1.run"
|
||||
chmod +x qt-online-installer-linux-x64-4.8.1.run
|
||||
./qt-online-installer-linux-x64-4.8.1.run --no-force-installations --no-default-installations \
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations \
|
||||
--email "$QT_EMAIL" --password "$QT_PASSWORD" install \
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.linux_gcc_64 qt.qt6.681.addons.qt5compat \
|
||||
qt.qt6.681.debug_info extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
<<: *job-linux-install-chat-deps
|
||||
- run:
|
||||
name: Build linuxdeployqt
|
||||
command: |
|
||||
@ -506,7 +514,7 @@ jobs:
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
set -eo pipefail
|
||||
export CMAKE_PREFIX_PATH=~/Qt/6.8.1/gcc_64/lib/cmake
|
||||
export CMAKE_PREFIX_PATH=~/Qt/6.8.2/gcc_64/lib/cmake
|
||||
export PATH=$PATH:$HOME/Qt/Tools/QtInstallerFramework/4.8/bin
|
||||
export PATH=$PATH:/usr/local/cuda/bin
|
||||
ccache -o "cache_dir=${PWD}/../.ccache" -o max_size=500M -p -z
|
||||
@ -516,8 +524,10 @@ jobs:
|
||||
~/Qt/Tools/CMake/bin/cmake \
|
||||
-S ../gpt4all-chat -B . \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=gcc-12 \
|
||||
-DCMAKE_CXX_COMPILER=g++-12 \
|
||||
-DCMAKE_C_COMPILER=clang-19 \
|
||||
-DCMAKE_CXX_COMPILER=clang++-19 \
|
||||
-DCMAKE_CXX_COMPILER_AR=ar \
|
||||
-DCMAKE_CXX_COMPILER_RANLIB=ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CUDA_COMPILER_LAUNCHER=ccache \
|
||||
@ -571,8 +581,8 @@ jobs:
|
||||
& .\qt-online-installer-windows-x64-4.8.1.exe --no-force-installations --no-default-installations `
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations `
|
||||
--email "${Env:QT_EMAIL}" --password "${Env:QT_PASSWORD}" install `
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.win64_msvc2022_64 qt.qt6.681.addons.qt5compat `
|
||||
qt.qt6.681.debug_info extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.win64_msvc2022_64 qt.qt6.682.addons.qt5compat `
|
||||
qt.qt6.682.debug_info extensions.qtpdf.682 qt.qt6.682.addons.qthttpserver
|
||||
- run:
|
||||
name: Install VulkanSDK
|
||||
command: |
|
||||
@ -613,7 +623,7 @@ jobs:
|
||||
& "C:\Qt\Tools\CMake_64\bin\cmake.exe" `
|
||||
-S ..\gpt4all-chat -B . -G Ninja `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.1\msvc2022_64" `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.2\msvc2022_64" `
|
||||
"-DCMAKE_MAKE_PROGRAM:FILEPATH=C:\Qt\Tools\Ninja\ninja.exe" `
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache `
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache `
|
||||
@ -705,8 +715,8 @@ jobs:
|
||||
& .\qt-online-installer-windows-x64-4.8.1.exe --no-force-installations --no-default-installations `
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations `
|
||||
--email "${Env:QT_EMAIL}" --password "${Env:QT_PASSWORD}" install `
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.win64_msvc2022_64 qt.qt6.681.addons.qt5compat `
|
||||
qt.qt6.681.debug_info extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.win64_msvc2022_64 qt.qt6.682.addons.qt5compat `
|
||||
qt.qt6.682.debug_info extensions.qtpdf.682 qt.qt6.682.addons.qthttpserver
|
||||
- run:
|
||||
name: Install VulkanSDK
|
||||
command: |
|
||||
@ -752,7 +762,7 @@ jobs:
|
||||
& "C:\Qt\Tools\CMake_64\bin\cmake.exe" `
|
||||
-S ..\gpt4all-chat -B . -G Ninja `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.1\msvc2022_64" `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.2\msvc2022_64" `
|
||||
"-DCMAKE_MAKE_PROGRAM:FILEPATH=C:\Qt\Tools\Ninja\ninja.exe" `
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache `
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache `
|
||||
@ -853,9 +863,9 @@ jobs:
|
||||
& .\qt-online-installer-windows-x64-4.8.1.exe --no-force-installations --no-default-installations `
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations `
|
||||
--email "${Env:QT_EMAIL}" --password "${Env:QT_PASSWORD}" install `
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.win64_msvc2022_64 `
|
||||
qt.qt6.681.win64_msvc2022_arm64_cross_compiled qt.qt6.681.addons.qt5compat qt.qt6.681.debug_info `
|
||||
qt.qt6.681.addons.qthttpserver
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.win64_msvc2022_64 `
|
||||
qt.qt6.682.win64_msvc2022_arm64_cross_compiled qt.qt6.682.addons.qt5compat qt.qt6.682.debug_info `
|
||||
qt.qt6.682.addons.qthttpserver
|
||||
- run:
|
||||
name: "Install Dotnet 8"
|
||||
command: |
|
||||
@ -885,14 +895,14 @@ jobs:
|
||||
& "C:\Qt\Tools\CMake_64\bin\cmake.exe" `
|
||||
-S ..\gpt4all-chat -B . -G Ninja `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.1\msvc2022_arm64" `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.2\msvc2022_arm64" `
|
||||
"-DCMAKE_MAKE_PROGRAM:FILEPATH=C:\Qt\Tools\Ninja\ninja.exe" `
|
||||
"-DCMAKE_TOOLCHAIN_FILE=C:\Qt\6.8.1\msvc2022_arm64\lib\cmake\Qt6\qt.toolchain.cmake" `
|
||||
"-DCMAKE_TOOLCHAIN_FILE=C:\Qt\6.8.2\msvc2022_arm64\lib\cmake\Qt6\qt.toolchain.cmake" `
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache `
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache `
|
||||
-DLLMODEL_CUDA=OFF `
|
||||
-DLLMODEL_KOMPUTE=OFF `
|
||||
"-DWINDEPLOYQT=C:\Qt\6.8.1\msvc2022_64\bin\windeployqt.exe;--qtpaths;C:\Qt\6.8.1\msvc2022_arm64\bin\qtpaths.bat" `
|
||||
"-DWINDEPLOYQT=C:\Qt\6.8.2\msvc2022_64\bin\windeployqt.exe;--qtpaths;C:\Qt\6.8.2\msvc2022_arm64\bin\qtpaths.bat" `
|
||||
-DGPT4ALL_TEST=OFF `
|
||||
-DGPT4ALL_OFFLINE_INSTALLER=ON
|
||||
& "C:\Qt\Tools\Ninja\ninja.exe"
|
||||
@ -980,9 +990,9 @@ jobs:
|
||||
& .\qt-online-installer-windows-x64-4.8.1.exe --no-force-installations --no-default-installations `
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations `
|
||||
--email "${Env:QT_EMAIL}" --password "${Env:QT_PASSWORD}" install `
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.win64_msvc2022_64 `
|
||||
qt.qt6.681.win64_msvc2022_arm64_cross_compiled qt.qt6.681.addons.qt5compat qt.qt6.681.debug_info `
|
||||
qt.qt6.681.addons.qthttpserver
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.win64_msvc2022_64 `
|
||||
qt.qt6.682.win64_msvc2022_arm64_cross_compiled qt.qt6.682.addons.qt5compat qt.qt6.682.debug_info `
|
||||
qt.qt6.682.addons.qthttpserver
|
||||
- run:
|
||||
name: "Install Dotnet 8"
|
||||
command: |
|
||||
@ -1017,14 +1027,14 @@ jobs:
|
||||
& "C:\Qt\Tools\CMake_64\bin\cmake.exe" `
|
||||
-S ..\gpt4all-chat -B . -G Ninja `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.1\msvc2022_arm64" `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.2\msvc2022_arm64" `
|
||||
"-DCMAKE_MAKE_PROGRAM:FILEPATH=C:\Qt\Tools\Ninja\ninja.exe" `
|
||||
"-DCMAKE_TOOLCHAIN_FILE=C:\Qt\6.8.1\msvc2022_arm64\lib\cmake\Qt6\qt.toolchain.cmake" `
|
||||
"-DCMAKE_TOOLCHAIN_FILE=C:\Qt\6.8.2\msvc2022_arm64\lib\cmake\Qt6\qt.toolchain.cmake" `
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache `
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache `
|
||||
-DLLMODEL_CUDA=OFF `
|
||||
-DLLMODEL_KOMPUTE=OFF `
|
||||
"-DWINDEPLOYQT=C:\Qt\6.8.1\msvc2022_64\bin\windeployqt.exe;--qtpaths;C:\Qt\6.8.1\msvc2022_arm64\bin\qtpaths.bat" `
|
||||
"-DWINDEPLOYQT=C:\Qt\6.8.2\msvc2022_64\bin\windeployqt.exe;--qtpaths;C:\Qt\6.8.2\msvc2022_arm64\bin\qtpaths.bat" `
|
||||
-DGPT4ALL_TEST=OFF `
|
||||
-DGPT4ALL_OFFLINE_INSTALLER=OFF
|
||||
& "C:\Qt\Tools\Ninja\ninja.exe"
|
||||
@ -1109,46 +1119,21 @@ jobs:
|
||||
keys:
|
||||
- ccache-gpt4all-linux-amd64-
|
||||
- run:
|
||||
name: Setup Linux and Dependencies
|
||||
command: |
|
||||
# Prevent apt-get from interactively prompting for service restart
|
||||
echo "\$nrconf{restart} = 'l'" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf >/dev/null
|
||||
wget -qO- "https://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
|
||||
wget -qO- "https://packages.lunarg.com/vulkan/1.3.290/lunarg-vulkan-1.3.290-jammy.list" | sudo tee /etc/apt/sources.list.d/lunarg-vulkan-1.3.290-jammy.list
|
||||
wget "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb"
|
||||
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||
packages=(
|
||||
bison build-essential ccache cuda-compiler-11-8 flex g++-12 gperf libcublas-dev-11-8 libfontconfig1
|
||||
libfreetype6 libgl1-mesa-dev libmysqlclient21 libnvidia-compute-550-server libodbc2 libpq5 libwayland-dev
|
||||
libx11-6 libx11-xcb1 libxcb-cursor0 libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0
|
||||
libxcb-render-util0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 libxcb-xinerama0
|
||||
libxcb-xkb1 libxcb1 libxext6 libxfixes3 libxi6 libxkbcommon-dev libxkbcommon-x11-0 libxrender1 python3
|
||||
vulkan-sdk
|
||||
)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "${packages[@]}"
|
||||
- run:
|
||||
name: Installing Qt
|
||||
command: |
|
||||
wget "https://qt.mirror.constant.com/archive/online_installers/4.8/qt-online-installer-linux-x64-4.8.1.run"
|
||||
chmod +x qt-online-installer-linux-x64-4.8.1.run
|
||||
./qt-online-installer-linux-x64-4.8.1.run --no-force-installations --no-default-installations \
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations \
|
||||
--email "$QT_EMAIL" --password "$QT_PASSWORD" install \
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.linux_gcc_64 qt.qt6.681.addons.qt5compat \
|
||||
qt.qt6.681.debug_info extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
<<: *job-linux-install-chat-deps
|
||||
- run:
|
||||
name: Build
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
export CMAKE_PREFIX_PATH=~/Qt/6.8.1/gcc_64/lib/cmake
|
||||
export CMAKE_PREFIX_PATH=~/Qt/6.8.2/gcc_64/lib/cmake
|
||||
export PATH=$PATH:/usr/local/cuda/bin
|
||||
ccache -o "cache_dir=${PWD}/../.ccache" -o max_size=500M -p -z
|
||||
~/Qt/Tools/CMake/bin/cmake \
|
||||
-S gpt4all-chat -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=gcc-12 \
|
||||
-DCMAKE_CXX_COMPILER=g++-12 \
|
||||
-DCMAKE_C_COMPILER=clang-19 \
|
||||
-DCMAKE_CXX_COMPILER=clang++-19 \
|
||||
-DCMAKE_CXX_COMPILER_AR=ar \
|
||||
-DCMAKE_CXX_COMPILER_RANLIB=ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CUDA_COMPILER_LAUNCHER=ccache \
|
||||
@ -1186,8 +1171,8 @@ jobs:
|
||||
& .\qt-online-installer-windows-x64-4.8.1.exe --no-force-installations --no-default-installations `
|
||||
--no-size-checking --default-answer --accept-licenses --confirm-command --accept-obligations `
|
||||
--email "${Env:QT_EMAIL}" --password "${Env:QT_PASSWORD}" install `
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.win64_msvc2022_64 qt.qt6.681.addons.qt5compat `
|
||||
qt.qt6.681.debug_info extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.win64_msvc2022_64 qt.qt6.682.addons.qt5compat `
|
||||
qt.qt6.682.debug_info extensions.qtpdf.682 qt.qt6.682.addons.qthttpserver
|
||||
- run:
|
||||
name: Install VulkanSDK
|
||||
command: |
|
||||
@ -1212,7 +1197,7 @@ jobs:
|
||||
& "C:\Qt\Tools\CMake_64\bin\cmake.exe" `
|
||||
-S gpt4all-chat -B build -G Ninja `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.1\msvc2022_64" `
|
||||
"-DCMAKE_PREFIX_PATH:PATH=C:\Qt\6.8.2\msvc2022_64" `
|
||||
"-DCMAKE_MAKE_PROGRAM:FILEPATH=C:\Qt\Tools\Ninja\ninja.exe" `
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache `
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache `
|
||||
@ -1227,8 +1212,7 @@ jobs:
|
||||
- ..\.ccache
|
||||
|
||||
build-gpt4all-chat-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@ -1239,12 +1223,11 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- ccache-gpt4all-macos-
|
||||
- run:
|
||||
<<: *job-macos-install-deps
|
||||
- run:
|
||||
name: Install Rosetta
|
||||
command: softwareupdate --install-rosetta --agree-to-license # needed for QtIFW
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: brew install ccache wget
|
||||
- run:
|
||||
name: Installing Qt
|
||||
command: |
|
||||
@ -1254,8 +1237,8 @@ jobs:
|
||||
--no-force-installations --no-default-installations --no-size-checking --default-answer \
|
||||
--accept-licenses --confirm-command --accept-obligations --email "$QT_EMAIL" --password "$QT_PASSWORD" \
|
||||
install \
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.681.clang_64 qt.qt6.681.addons.qt5compat \
|
||||
extensions.qtpdf.681 qt.qt6.681.addons.qthttpserver
|
||||
qt.tools.cmake qt.tools.ifw.48 qt.tools.ninja qt.qt6.682.clang_64 qt.qt6.682.addons.qt5compat \
|
||||
extensions.qtpdf.682 qt.qt6.682.addons.qthttpserver
|
||||
hdiutil detach /Volumes/qt-online-installer-macOS-x64-4.8.1
|
||||
- run:
|
||||
name: Build
|
||||
@ -1265,8 +1248,11 @@ jobs:
|
||||
~/Qt/Tools/CMake/CMake.app/Contents/bin/cmake \
|
||||
-S gpt4all-chat -B build -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH:PATH=~/Qt/6.8.1/macos/lib/cmake \
|
||||
-DCMAKE_PREFIX_PATH:PATH=~/Qt/6.8.2/macos/lib/cmake \
|
||||
-DCMAKE_MAKE_PROGRAM:FILEPATH=~/Qt/Tools/Ninja/ninja \
|
||||
-DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ \
|
||||
-DCMAKE_RANLIB=/usr/bin/ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DBUILD_UNIVERSAL=ON \
|
||||
@ -1334,22 +1320,7 @@ jobs:
|
||||
keys:
|
||||
- ccache-gpt4all-linux-amd64-
|
||||
- run:
|
||||
name: Set Python Version
|
||||
command: pyenv global 3.11.2
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
wget -qO- "https://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
|
||||
wget -qO- "https://packages.lunarg.com/vulkan/1.3.290/lunarg-vulkan-1.3.290-jammy.list" | sudo tee /etc/apt/sources.list.d/lunarg-vulkan-1.3.290-jammy.list
|
||||
wget "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb"
|
||||
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||
packages=(
|
||||
build-essential ccache cmake cuda-compiler-11-8 g++-12 libcublas-dev-11-8 libnvidia-compute-550-server
|
||||
vulkan-sdk
|
||||
)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "${packages[@]}"
|
||||
pip install setuptools wheel cmake
|
||||
<<: *job-linux-install-backend-deps
|
||||
- run:
|
||||
name: Build C library
|
||||
no_output_timeout: 30m
|
||||
@ -1358,15 +1329,17 @@ jobs:
|
||||
git submodule update --init --recursive
|
||||
ccache -o "cache_dir=${PWD}/../.ccache" -o max_size=500M -p -z
|
||||
cd gpt4all-backend
|
||||
cmake -B build \
|
||||
cmake -B build -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=gcc-12 \
|
||||
-DCMAKE_CXX_COMPILER=g++-12 \
|
||||
-DCMAKE_C_COMPILER=clang-19 \
|
||||
-DCMAKE_CXX_COMPILER=clang++-19 \
|
||||
-DCMAKE_CXX_COMPILER_AR=ar \
|
||||
-DCMAKE_CXX_COMPILER_RANLIB=ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CUDA_COMPILER_LAUNCHER=ccache \
|
||||
-DKOMPUTE_OPT_DISABLE_VULKAN_VERSION_CHECK=ON \
|
||||
-DCMAKE_CUDA_ARCHITECTURES='52-virtual;61-virtual;70-virtual;75-virtual'
|
||||
-DCMAKE_CUDA_ARCHITECTURES='50-virtual;52-virtual;61-virtual;70-virtual;75-virtual'
|
||||
cmake --build build -j$(nproc)
|
||||
ccache -s
|
||||
- run:
|
||||
@ -1387,18 +1360,17 @@ jobs:
|
||||
- "*.whl"
|
||||
|
||||
build-py-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
resource_class: macos.m1.large.gen1
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- ccache-gpt4all-macos-
|
||||
- run:
|
||||
<<: *job-macos-install-deps
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
brew install ccache cmake
|
||||
pip install setuptools wheel cmake
|
||||
- run:
|
||||
name: Build C library
|
||||
@ -1409,6 +1381,9 @@ jobs:
|
||||
cd gpt4all-backend
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ \
|
||||
-DCMAKE_RANLIB=/usr/bin/ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DBUILD_UNIVERSAL=ON \
|
||||
@ -1483,7 +1458,7 @@ jobs:
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache `
|
||||
-DCMAKE_CUDA_COMPILER_LAUNCHER=ccache `
|
||||
-DKOMPUTE_OPT_DISABLE_VULKAN_VERSION_CHECK=ON `
|
||||
-DCMAKE_CUDA_ARCHITECTURES='52-virtual;61-virtual;70-virtual;75-virtual'
|
||||
-DCMAKE_CUDA_ARCHITECTURES='50-virtual;52-virtual;61-virtual;70-virtual;75-virtual'
|
||||
cmake --build build --parallel
|
||||
ccache -s
|
||||
- run:
|
||||
@ -1537,18 +1512,7 @@ jobs:
|
||||
keys:
|
||||
- ccache-gpt4all-linux-amd64-
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
wget -qO- "https://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
|
||||
wget -qO- "https://packages.lunarg.com/vulkan/1.3.290/lunarg-vulkan-1.3.290-jammy.list" | sudo tee /etc/apt/sources.list.d/lunarg-vulkan-1.3.290-jammy.list
|
||||
wget "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb"
|
||||
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||
packages=(
|
||||
build-essential ccache cmake cuda-compiler-11-8 g++-12 libcublas-dev-11-8 libnvidia-compute-550-server
|
||||
vulkan-sdk
|
||||
)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "${packages[@]}"
|
||||
<<: *job-linux-install-backend-deps
|
||||
- run:
|
||||
name: Build Libraries
|
||||
no_output_timeout: 30m
|
||||
@ -1558,10 +1522,12 @@ jobs:
|
||||
cd gpt4all-backend
|
||||
mkdir -p runtimes/build
|
||||
cd runtimes/build
|
||||
cmake ../.. \
|
||||
cmake ../.. -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=gcc-12 \
|
||||
-DCMAKE_C_COMPILER=g++-12 \
|
||||
-DCMAKE_C_COMPILER=clang-19 \
|
||||
-DCMAKE_CXX_COMPILER=clang++-19 \
|
||||
-DCMAKE_CXX_COMPILER_AR=ar \
|
||||
-DCMAKE_CXX_COMPILER_RANLIB=ranlib \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
@ -1582,8 +1548,7 @@ jobs:
|
||||
- runtimes/linux-x64/*.so
|
||||
|
||||
build-bindings-backend-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@ -1595,9 +1560,7 @@ jobs:
|
||||
keys:
|
||||
- ccache-gpt4all-macos-
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
brew install ccache cmake
|
||||
<<: *job-macos-install-deps
|
||||
- run:
|
||||
name: Build Libraries
|
||||
no_output_timeout: 30m
|
||||
@ -1608,6 +1571,9 @@ jobs:
|
||||
cd runtimes/build
|
||||
cmake ../.. \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ \
|
||||
-DCMAKE_RANLIB=/usr/bin/ranlib \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DBUILD_UNIVERSAL=ON \
|
||||
@ -1725,8 +1691,7 @@ jobs:
|
||||
- runtimes/linux-x64/*-*.so
|
||||
|
||||
build-nodejs-macos:
|
||||
macos:
|
||||
xcode: 15.4.0
|
||||
<<: *job-macos-executor
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
@ -1903,22 +1868,22 @@ workflows:
|
||||
context: gpt4all
|
||||
- build-offline-chat-installer-linux:
|
||||
context: gpt4all
|
||||
- sign-online-chat-installer-macos:
|
||||
- sign-offline-chat-installer-macos:
|
||||
context: gpt4all
|
||||
requires:
|
||||
- build-online-chat-installer-macos
|
||||
- notarize-online-chat-installer-macos:
|
||||
- build-offline-chat-installer-macos
|
||||
- notarize-offline-chat-installer-macos:
|
||||
context: gpt4all
|
||||
requires:
|
||||
- sign-online-chat-installer-macos
|
||||
- sign-online-chat-installer-windows:
|
||||
- sign-offline-chat-installer-macos
|
||||
- sign-offline-chat-installer-windows:
|
||||
context: gpt4all
|
||||
requires:
|
||||
- build-online-chat-installer-windows
|
||||
- sign-online-chat-installer-windows-arm:
|
||||
- build-offline-chat-installer-windows
|
||||
- sign-offline-chat-installer-windows-arm:
|
||||
context: gpt4all
|
||||
requires:
|
||||
- build-online-chat-installer-windows-arm
|
||||
- build-offline-chat-installer-windows-arm
|
||||
build-chat-installers-release:
|
||||
# only run on main branch tags that start with 'v' and a digit
|
||||
when:
|
||||
|
@ -72,6 +72,6 @@ Discord: `@Tim453`
|
||||
- Flatpak
|
||||
|
||||
Jack ([@wuodoo](https://github.com/wuodoo))<br/>
|
||||
E-mail: 2296103047@qq.com><br/>
|
||||
E-mail: 2296103047@qq.com<br/>
|
||||
Discord: `@mikage`
|
||||
- zh\_CN translation
|
||||
|
19
README.md
19
README.md
@ -1,5 +1,9 @@
|
||||
<h1 align="center">GPT4All</h1>
|
||||
|
||||
<p align="center">
|
||||
Now with support for DeepSeek R1 Distillations
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.nomic.ai/gpt4all">Website</a> • <a href="https://docs.gpt4all.io">Documentation</a> • <a href="https://discord.gg/mGZE39AS3e">Discord</a> • <a href="https://www.youtube.com/watch?v=gQcZDXRVJok">YouTube Tutorial</a>
|
||||
</p>
|
||||
@ -31,6 +35,11 @@ GPT4All is made possible by our compute partner <a href="https://www.paperspace.
|
||||
<img src="gpt4all-bindings/python/docs/assets/windows.png" style="height: 1em; width: auto" /> Windows Installer
|
||||
</a> —
|
||||
</p>
|
||||
<p>
|
||||
— <a href="https://gpt4all.io/installers/gpt4all-installer-win64-arm.exe">
|
||||
<img src="gpt4all-bindings/python/docs/assets/windows.png" style="height: 1em; width: auto" /> Windows ARM Installer
|
||||
</a> —
|
||||
</p>
|
||||
<p>
|
||||
— <a href="https://gpt4all.io/installers/gpt4all-installer-darwin.dmg">
|
||||
<img src="gpt4all-bindings/python/docs/assets/mac.png" style="height: 1em; width: auto" /> macOS Installer
|
||||
@ -42,10 +51,16 @@ GPT4All is made possible by our compute partner <a href="https://www.paperspace.
|
||||
</a> —
|
||||
</p>
|
||||
<p>
|
||||
Windows and Linux require Intel Core i3 2nd Gen / AMD Bulldozer, or better. x86-64 only, no ARM.
|
||||
The Windows and Linux builds require Intel Core i3 2nd Gen / AMD Bulldozer, or better.
|
||||
</p>
|
||||
<p>
|
||||
macOS requires Monterey 12.6 or newer. Best results with Apple Silicon M-series processors.
|
||||
The Windows ARM build supports Qualcomm Snapdragon and Microsoft SQ1/SQ2 processors.
|
||||
</p>
|
||||
<p>
|
||||
The Linux build is x86-64 only (no ARM).
|
||||
</p>
|
||||
<p>
|
||||
The macOS build requires Monterey 12.6 or newer. Best results with Apple Silicon M-series processors.
|
||||
</p>
|
||||
|
||||
See the full [System Requirements](gpt4all-chat/system_requirements.md) for more details.
|
||||
|
@ -69,7 +69,7 @@ if (LLMODEL_CUDA)
|
||||
cmake_minimum_required(VERSION 3.18) # for CMAKE_CUDA_ARCHITECTURES
|
||||
|
||||
# Defaults must be set before enable_language(CUDA).
|
||||
# Keep this in sync with the arch list in ggml/src/CMakeLists.txt.
|
||||
# Keep this in sync with the arch list in ggml/src/CMakeLists.txt (plus 5.0 for non-F16 branch).
|
||||
if (NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
|
||||
# 52 == lowest CUDA 12 standard
|
||||
# 60 == f16 CUDA intrinsics
|
||||
@ -78,7 +78,7 @@ if (LLMODEL_CUDA)
|
||||
if (GGML_CUDA_F16 OR GGML_CUDA_DMMV_F16)
|
||||
set(CMAKE_CUDA_ARCHITECTURES "60;61;70;75") # needed for f16 CUDA intrinsics
|
||||
else()
|
||||
set(CMAKE_CUDA_ARCHITECTURES "52;61;70;75") # lowest CUDA 12 standard + lowest for integer intrinsics
|
||||
set(CMAKE_CUDA_ARCHITECTURES "50;52;61;70;75") # lowest CUDA 12 standard + lowest for integer intrinsics
|
||||
#set(CMAKE_CUDA_ARCHITECTURES "OFF") # use this to compile much faster, but only F16 models work
|
||||
endif()
|
||||
endif()
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit b06658d366abe3cea92f4e868db72165531a74da
|
||||
Subproject commit 11f734c3b0334dbae4823b4a7467764e447fc6d6
|
@ -53,6 +53,8 @@ static const std::vector<const char *> KNOWN_ARCHES {
|
||||
"gpt2",
|
||||
// "gptj", -- no inference code
|
||||
"gptneox",
|
||||
"granite",
|
||||
"granitemoe",
|
||||
"mpt",
|
||||
"baichuan",
|
||||
"starcoder",
|
||||
@ -80,6 +82,7 @@ static const std::vector<const char *> KNOWN_ARCHES {
|
||||
"command-r",
|
||||
// "dbrx", -- 16x12B parameters
|
||||
"olmo",
|
||||
"olmoe",
|
||||
"openelm",
|
||||
// "arctic", -- 10B+128x3.66B parameters
|
||||
"deepseek2",
|
||||
|
@ -140,9 +140,14 @@ const std::vector<LLModel::Implementation> &LLModel::Implementation::implementat
|
||||
std::string path;
|
||||
// Split the paths string by the delimiter and process each path.
|
||||
while (std::getline(ss, path, ';')) {
|
||||
std::u8string u8_path(path.begin(), path.end());
|
||||
fs::directory_iterator iter;
|
||||
try {
|
||||
iter = fs::directory_iterator(std::u8string(path.begin(), path.end()));
|
||||
} catch (const fs::filesystem_error &) {
|
||||
continue; // skip nonexistent path
|
||||
}
|
||||
// Iterate over all libraries
|
||||
for (const auto &f : fs::directory_iterator(u8_path)) {
|
||||
for (const auto &f : iter) {
|
||||
const fs::path &p = f.path();
|
||||
|
||||
if (p.extension() != LIB_FILE_EXT) continue;
|
||||
|
@ -4,6 +4,35 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
|
||||
## [3.10.0] - 2025-02-24
|
||||
|
||||
### Added
|
||||
- Whitelist Granite (non-MoE) model architecture (by [@ThiloteE](https://github.com/ThiloteE) in [#3487](https://github.com/nomic-ai/gpt4all/pull/3487))
|
||||
- Add support for CUDA compute 5.0 GPUs such as the GTX 750 ([#3499](https://github.com/nomic-ai/gpt4all/pull/3499))
|
||||
- Add a Remote Providers tab to the Add Model page ([#3506](https://github.com/nomic-ai/gpt4all/pull/3506))
|
||||
|
||||
### Changed
|
||||
- Substitute prettier default templates for OLMoE 7B 0924/0125 and Granite 3.1 3B/8B (by [@ThiloteE](https://github.com/ThiloteE) in [#3471](https://github.com/nomic-ai/gpt4all/pull/3471))
|
||||
- Build with LLVM Clang 19 on macOS and Ubuntu ([#3500](https://github.com/nomic-ai/gpt4all/pull/3500))
|
||||
|
||||
### Fixed
|
||||
- Fix several potential crashes ([#3465](https://github.com/nomic-ai/gpt4all/pull/3465))
|
||||
- Fix visual spacing issues with deepseek models ([#3470](https://github.com/nomic-ai/gpt4all/pull/3470))
|
||||
- Add missing strings to Italian translation (by [@Harvester62](https://github.com/Harvester62) in [#3496](https://github.com/nomic-ai/gpt4all/pull/3496))
|
||||
- Update Simplified Chinese translation (by [@Junior2Ran](https://github.com/Junior2Ran) in [#3467](https://github.com/nomic-ai/pull/3467))
|
||||
|
||||
## [3.9.0] - 2025-02-04
|
||||
|
||||
### Added
|
||||
- Whitelist OLMoE and Granite MoE model architectures (no Vulkan) (by [@ThiloteE](https://github.com/ThiloteE) in [#3449](https://github.com/nomic-ai/gpt4all/pull/3449))
|
||||
|
||||
### Fixed
|
||||
- Fix "index N is not a prompt" when using LocalDocs with reasoning ([#3451](https://github.com/nomic-ai/gpt4all/pull/3451))
|
||||
- Work around rendering artifacts on Snapdragon SoCs with Windows ([#3450](https://github.com/nomic-ai/gpt4all/pull/3450))
|
||||
- Prevent DeepSeek-R1 reasoning from appearing in chat names and follow-up questions ([#3458](https://github.com/nomic-ai/gpt4all/pull/3458))
|
||||
- Fix LocalDocs crash on Windows ARM when reading PDFs ([#3460](https://github.com/nomic-ai/gpt4all/pull/3460))
|
||||
- Fix UI freeze when chat template is `{#` ([#3446](https://github.com/nomic-ai/gpt4all/pull/3446))
|
||||
|
||||
## [3.8.0] - 2025-01-30
|
||||
|
||||
### Added
|
||||
@ -283,6 +312,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
- Fix several Vulkan resource management issues ([#2694](https://github.com/nomic-ai/gpt4all/pull/2694))
|
||||
- Fix crash/hang when some models stop generating, by showing special tokens ([#2701](https://github.com/nomic-ai/gpt4all/pull/2701))
|
||||
|
||||
[3.10.0]: https://github.com/nomic-ai/gpt4all/compare/v3.9.0...v3.10.0
|
||||
[3.9.0]: https://github.com/nomic-ai/gpt4all/compare/v3.8.0...v3.9.0
|
||||
[3.8.0]: https://github.com/nomic-ai/gpt4all/compare/v3.7.0...v3.8.0
|
||||
[3.7.0]: https://github.com/nomic-ai/gpt4all/compare/v3.6.1...v3.7.0
|
||||
[3.6.1]: https://github.com/nomic-ai/gpt4all/compare/v3.6.0...v3.6.1
|
||||
|
@ -3,10 +3,10 @@ cmake_minimum_required(VERSION 3.25) # for try_compile SOURCE_FROM_VAR
|
||||
include(../common/common.cmake)
|
||||
|
||||
set(APP_VERSION_MAJOR 3)
|
||||
set(APP_VERSION_MINOR 8)
|
||||
set(APP_VERSION_PATCH 0)
|
||||
set(APP_VERSION_MINOR 10)
|
||||
set(APP_VERSION_PATCH 1)
|
||||
set(APP_VERSION_BASE "${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}.${APP_VERSION_PATCH}")
|
||||
set(APP_VERSION "${APP_VERSION_BASE}")
|
||||
set(APP_VERSION "${APP_VERSION_BASE}-dev0")
|
||||
|
||||
project(gpt4all VERSION ${APP_VERSION_BASE} LANGUAGES CXX C)
|
||||
|
||||
@ -35,6 +35,8 @@ option(GPT4ALL_SIGN_INSTALL "Sign installed binaries and installers (requires si
|
||||
option(GPT4ALL_GEN_CPACK_CONFIG "Generate the CPack config.xml in the package step and nothing else." OFF)
|
||||
set(GPT4ALL_USE_QTPDF "AUTO" CACHE STRING "Whether to Use QtPDF for LocalDocs. If OFF or not available on this platform, PDFium is used.")
|
||||
set_property(CACHE GPT4ALL_USE_QTPDF PROPERTY STRINGS AUTO ON OFF)
|
||||
set(GPT4ALL_FORCE_D3D12 "AUTO" CACHE STRING "Whether to use Direct3D 12 as the Qt scene graph backend. Defaults to ON on Windows ARM.")
|
||||
set_property(CACHE GPT4ALL_FORCE_D3D12 PROPERTY STRINGS AUTO ON OFF)
|
||||
|
||||
include(cmake/cpack_config.cmake)
|
||||
|
||||
@ -90,12 +92,6 @@ include_directories("${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
# Generate a header file with the version number
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/config.h"
|
||||
)
|
||||
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON)
|
||||
set(GPT4ALL_QT_COMPONENTS Core HttpServer LinguistTools Quick QuickDialogs2 Sql Svg)
|
||||
set(GPT4ALL_USING_QTPDF OFF)
|
||||
@ -108,7 +104,7 @@ elseif (GPT4ALL_USE_QTPDF MATCHES "^(ON|AUTO)$")
|
||||
set(GPT4ALL_USING_QTPDF ON)
|
||||
list(APPEND GPT4ALL_QT_COMPONENTS Pdf)
|
||||
endif()
|
||||
find_package(Qt6 6.5 COMPONENTS ${GPT4ALL_QT_COMPONENTS} REQUIRED)
|
||||
find_package(Qt6 6.8 COMPONENTS ${GPT4ALL_QT_COMPONENTS} REQUIRED)
|
||||
|
||||
if (QT_KNOWN_POLICY_QTP0004)
|
||||
qt_policy(SET QTP0004 NEW) # generate extra qmldir files on Qt 6.8+
|
||||
@ -130,6 +126,24 @@ message(STATUS "Qt 6 root directory: ${Qt6_ROOT_DIR}")
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
set(GPT4ALL_CONFIG_FORCE_D3D12 -1)
|
||||
if (NOT CMAKE_SYSTEM_NAME MATCHES Windows OR Qt6_VERSION VERSION_LESS "6.6")
|
||||
# Direct3D 12 is not available.
|
||||
if (GPT4ALL_FORCE_D3D12 STREQUAL "ON")
|
||||
message(FATAL_ERROR "Cannot use Direct3D 12 on this platform.")
|
||||
endif()
|
||||
elseif (GPT4ALL_FORCE_D3D12 MATCHES "^(ON|AUTO)$")
|
||||
if (GPT4ALL_FORCE_D3D12 STREQUAL "ON" OR CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|AARCH64|arm64|ARM64)$")
|
||||
set(GPT4ALL_CONFIG_FORCE_D3D12 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Generate a header file for configuration
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/config.h"
|
||||
)
|
||||
|
||||
add_subdirectory(deps)
|
||||
add_subdirectory(../gpt4all-backend llmodel)
|
||||
|
||||
@ -252,6 +266,7 @@ qt_add_qml_module(chat
|
||||
qml/AddModelView.qml
|
||||
qml/AddGPT4AllModelView.qml
|
||||
qml/AddHFModelView.qml
|
||||
qml/AddRemoteModelView.qml
|
||||
qml/ApplicationSettings.qml
|
||||
qml/ChatDrawer.qml
|
||||
qml/ChatCollapsibleItem.qml
|
||||
@ -300,6 +315,7 @@ qt_add_qml_module(chat
|
||||
qml/MyTextField.qml
|
||||
qml/MyToolButton.qml
|
||||
qml/MyWelcomeButton.qml
|
||||
qml/RemoteModelCard.qml
|
||||
RESOURCES
|
||||
icons/antenna_1.svg
|
||||
icons/antenna_2.svg
|
||||
@ -330,6 +346,7 @@ qt_add_qml_module(chat
|
||||
icons/gpt4all-48.png
|
||||
icons/gpt4all.svg
|
||||
icons/gpt4all_transparent.svg
|
||||
icons/groq.svg
|
||||
icons/home.svg
|
||||
icons/image.svg
|
||||
icons/info.svg
|
||||
@ -337,12 +354,14 @@ qt_add_qml_module(chat
|
||||
icons/left_panel_open.svg
|
||||
icons/local-docs.svg
|
||||
icons/models.svg
|
||||
icons/mistral.svg
|
||||
icons/network.svg
|
||||
icons/nomic_logo.svg
|
||||
icons/notes.svg
|
||||
icons/paperclip.svg
|
||||
icons/plus.svg
|
||||
icons/plus_circle.svg
|
||||
icons/openai.svg
|
||||
icons/recycle.svg
|
||||
icons/regenerate.svg
|
||||
icons/search.svg
|
||||
|
@ -1,45 +0,0 @@
|
||||
# gpt4all-chat
|
||||
|
||||
Cross platform Qt based GUI for GPT4All versions with GPT-J as the base
|
||||
model. NOTE: The model seen in the screenshot is actually a preview of a
|
||||
new training run for GPT4All based on GPT-J. The GPT4All project is busy
|
||||
at work getting ready to release this model including installers for all
|
||||
three major OS's. In the meantime, you can try this UI out with the original
|
||||
GPT-J model by following build instructions below.
|
||||
|
||||

|
||||
|
||||
## Install
|
||||
|
||||
One click installers for macOS, Linux, and Windows at https://www.nomic.ai/gpt4all
|
||||
|
||||
## Features
|
||||
|
||||
* Cross-platform (Linux, Windows, MacOSX)
|
||||
* The UI is made to look and feel like you've come to expect from a chatty gpt
|
||||
* Check for updates so you can always stay fresh with latest models
|
||||
* Easy to install with precompiled binaries available for all three major desktop platforms
|
||||
* Multi-modal - Ability to load more than one model and switch between them
|
||||
* Multi-chat - a list of current and past chats and the ability to save/delete/export and switch between
|
||||
* Supports models that are supported by llama.cpp
|
||||
* Model downloader in GUI featuring many popular open source models
|
||||
* Settings dialog to change temp, top_p, min_p, top_k, threads, etc
|
||||
* Copy your conversation to clipboard
|
||||
* RAG via LocalDocs feature
|
||||
* Check for updates to get the very latest GUI
|
||||
|
||||
## Building and running
|
||||
|
||||
* Follow the visual instructions on the [build_and_run](build_and_run.md) page
|
||||
|
||||
## Getting the latest
|
||||
|
||||
If you've already checked out the source code and/or built the program make sure when you do a git fetch to get the latest changes and that you also do `git submodule update --init --recursive` to update the submodules. (If you ever run into trouble, deinitializing via `git submodule deinit -f .` and then initializing again via `git submodule update --init --recursive` fixes most issues)
|
||||
|
||||
## Contributing
|
||||
|
||||
* Pull requests welcome. See the feature wish list for ideas :)
|
||||
|
||||
|
||||
## License
|
||||
The source code of this chat interface is currently under a MIT license.
|
@ -1,6 +0,0 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#define APP_VERSION "@APP_VERSION@"
|
||||
|
||||
#endif // CONFIG_H
|
@ -37,7 +37,6 @@ set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL "https://www.nomic.ai/gpt4all")
|
||||
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/icons/gpt4all-48.png")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE)
|
||||
set(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_SOURCE_DIR}/README.md)
|
||||
set(CPACK_PACKAGE_EXECUTABLES "GPT4All")
|
||||
set(CPACK_CREATE_DESKTOP_LINKS "GPT4All")
|
||||
set(CPACK_IFW_PACKAGE_NAME "GPT4All")
|
||||
|
@ -17,32 +17,32 @@ add_subdirectory(QXlsx/QXlsx)
|
||||
|
||||
if (NOT GPT4ALL_USING_QTPDF)
|
||||
# If we do not use QtPDF, we need to get PDFium.
|
||||
set(GPT4ALL_PDFIUM_TAG "chromium/6954")
|
||||
set(GPT4ALL_PDFIUM_TAG "chromium/6996")
|
||||
if (CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||
FetchContent_Declare(
|
||||
pdfium
|
||||
URL "https://github.com/bblanchon/pdfium-binaries/releases/download/${GPT4ALL_PDFIUM_TAG}/pdfium-linux-x64.tgz"
|
||||
URL_HASH "SHA256=69917fd9543befc6c806254aff6c8a604d9e7cd3999a3e70fc32b8690d372da2"
|
||||
URL_HASH "SHA256=68b381b87efed539f2e33ae1e280304c9a42643a878cc296c1d66a93b0cb4335"
|
||||
)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES Windows)
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64)$")
|
||||
FetchContent_Declare(
|
||||
pdfium
|
||||
URL "https://github.com/bblanchon/pdfium-binaries/releases/download/${GPT4ALL_PDFIUM_TAG}/pdfium-win-x64.tgz"
|
||||
URL_HASH "SHA256=62ecac78fbaf658457beaffcc05eb147f493d435a2e1309e6a731808b4e80d38"
|
||||
URL_HASH "SHA256=83e714c302ceacccf403826d5cb57ea39b77f393d83b8d5781283012774a9378"
|
||||
)
|
||||
elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|AARCH64|arm64|ARM64)$")
|
||||
FetchContent_Declare(
|
||||
pdfium
|
||||
URL "https://github.com/bblanchon/pdfium-binaries/releases/download/${GPT4ALL_PDFIUM_TAG}/pdfium-win-arm64.tgz"
|
||||
URL_HASH "SHA256=a0b69014467f2b9824776c064920bc95359c9ba0d88793bdda1894a0f22206f8"
|
||||
URL_HASH "SHA256=78e77e871453a4915cbf66fb381b951c9932f88a747c6b2b33c9f27ec2371445"
|
||||
)
|
||||
endif()
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES Darwin)
|
||||
FetchContent_Declare(
|
||||
pdfium
|
||||
URL "https://github.com/bblanchon/pdfium-binaries/releases/download/${GPT4ALL_PDFIUM_TAG}/pdfium-mac-univ.tgz"
|
||||
URL_HASH "SHA256=7442f1dc6bef90898b2b7bd38dbec369ddd81bbf66c1c5aac3a1b60e107098f9"
|
||||
URL_HASH "SHA256=e7577f3242ff9c1df50025f9615673a43601a201bc51ee4792975f98920793a2"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 491f5cb2e9925644bca2dddf09200042fa54bef4
|
||||
Subproject commit e97bb2442cd6ab3d5bb5f5a3e8a1f7d6081d613b
|
3
gpt4all-chat/icons/groq.svg
Normal file
3
gpt4all-chat/icons/groq.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26.3 26.3"><defs><style>.cls-1{fill:#f05237;}.cls-2{fill:#fff;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Content"><circle class="cls-1" cx="13.15" cy="13.15" r="13.15"/><path class="cls-2" d="M13.17,6.88a4.43,4.43,0,0,0,0,8.85h1.45V14.07H13.17a2.77,2.77,0,1,1,2.77-2.76v4.07a2.74,2.74,0,0,1-4.67,2L10.1,18.51a4.37,4.37,0,0,0,3.07,1.29h.06a4.42,4.42,0,0,0,4.36-4.4V11.2a4.43,4.43,0,0,0-4.42-4.32"/></g></g></svg>
|
After Width: | Height: | Size: 620 B |
1
gpt4all-chat/icons/mistral.svg
Normal file
1
gpt4all-chat/icons/mistral.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"><path d="M189.08 303.228H94.587l.044-94.446h94.497l-.048 94.446z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M283.528 397.674h-94.493l.044-94.446h94.496l-.047 94.446z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M283.575 303.228H189.08l.046-94.446h94.496l-.047 94.446z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M378.07 303.228h-94.495l.044-94.446h94.498l-.047 94.446zM189.128 208.779H94.633l.044-94.448h94.498l-.047 94.448zM378.115 208.779h-94.494l.045-94.448h94.496l-.047 94.448zM94.587 303.227H.093l.044-96.017h94.496l-.046 96.017z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M94.633 208.779H.138l.046-94.448H94.68l-.047 94.448z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M94.68 115.902H.185L.23 19.885h94.498l-.047 96.017zM472.657 114.331h-94.495l.044-94.446h94.497l-.046 94.446zM94.54 399.244H.046l.044-97.588h94.497l-.047 97.588z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M94.495 492.123H0l.044-94.446H94.54l-.045 94.446zM472.563 303.228H378.07l.044-94.446h94.496l-.047 94.446zM472.61 208.779h-94.495l.044-94.448h94.498l-.047 94.448z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M472.517 397.674h-94.494l.044-94.446h94.497l-.047 94.446z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M472.47 492.121h-94.493l.044-96.017h94.496l-.047 96.017z" fill="#1c1c1b" fill-rule="nonzero"/><path d="M228.375 303.22h-96.061l.046-94.446h96.067l-.052 94.446z" fill="#ff7000" fill-rule="nonzero"/><path d="M322.827 397.666h-94.495l.044-96.018h94.498l-.047 96.018z" fill="#ff4900" fill-rule="nonzero"/><path d="M324.444 303.22h-97.636l.046-94.446h97.638l-.048 94.446z" fill="#ff7000" fill-rule="nonzero"/><path d="M418.938 303.22h-96.064l.045-94.446h96.066l-.047 94.446z" fill="#ff7000" fill-rule="nonzero"/><path d="M228.423 208.77H132.36l.045-94.445h96.066l-.05 94.446zM418.985 208.77H322.92l.044-94.445h96.069l-.048 94.446z" fill="#ffa300" fill-rule="nonzero"/><path d="M133.883 304.79H39.392l.044-96.017h94.496l-.049 96.017z" fill="#ff7000" fill-rule="nonzero"/><path d="M133.929 208.77H39.437l.044-95.445h94.496l-.048 95.445z" fill="#ffa300" fill-rule="nonzero"/><path d="M133.976 114.325H39.484l.044-94.448h94.497l-.05 94.448zM511.954 115.325h-94.493l.044-95.448h94.497l-.048 95.448z" fill="#ffce00" fill-rule="nonzero"/><path d="M133.836 399.667H39.345l.044-96.447h94.496l-.049 96.447z" fill="#ff4900" fill-rule="nonzero"/><path d="M133.79 492.117H39.3l.044-94.448h94.496l-.049 94.448z" fill="#ff0107" fill-rule="nonzero"/><path d="M511.862 303.22h-94.495l.046-94.446h94.496l-.047 94.446z" fill="#ff7000" fill-rule="nonzero"/><path d="M511.907 208.77h-94.493l.044-94.445h94.496l-.047 94.446z" fill="#ffa300" fill-rule="nonzero"/><path d="M511.815 398.666h-94.493l.044-95.447h94.496l-.047 95.447z" fill="#ff4900" fill-rule="nonzero"/><path d="M511.77 492.117h-94.496l.046-94.448h94.496l-.047 94.448z" fill="#ff0107" fill-rule="nonzero"/></svg>
|
After Width: | Height: | Size: 2.9 KiB |
2
gpt4all-chat/icons/openai.svg
Normal file
2
gpt4all-chat/icons/openai.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 24 24" role="img" xmlns="http://www.w3.org/2000/svg"><title>OpenAI icon</title><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>
|
After Width: | Height: | Size: 1.7 KiB |
@ -1,17 +1,15 @@
|
||||
## Latest News
|
||||
|
||||
GPT4All v3.7.0 was released on January 23rd. Changes include:
|
||||
GPT4All v3.10.0 was released on February 24th. Changes include:
|
||||
|
||||
* **Windows ARM Support:** GPT4All now supports the Windows ARM platform, ensuring compatibility with devices powered by Qualcomm Snapdragon and Microsoft SQ-series processors.
|
||||
* **NOTE:** Support for GPU and/or NPU acceleration is not available at this time. Only the CPU will be used to run LLMs.
|
||||
* **NOTE:** You must install the new *Windows ARM* version of GPT4All from the website. The standard *Windows* version will not work due to emulation limitations.
|
||||
* **Fixed Updating on macOS:** The maintenance tool no longer crashes when attempting to update or uninstall GPT4All on Sequoia.
|
||||
* **NOTE:** If you have installed the version from the GitHub releases as a workaround for this issue, you can safely uninstall it and switch back to the version from the website.
|
||||
* **Fixed Chat Saving on macOS:** Chats now save as expected when the application is quit with Command-Q.
|
||||
* **Code Interpreter Improvements:**
|
||||
* The behavior when the code takes too long to execute and times out has been improved.
|
||||
* console.log now accepts multiple arguments for better compatibility with native JavaScript.
|
||||
* **Chat Templating Improvements:**
|
||||
* Two crashes and one compatibility issue have been fixed in the chat template parser.
|
||||
* The default chat template for EM German Mistral has been fixed.
|
||||
* Automatic replacements have been added for five new models as we continue to improve compatibility with common chat templates.
|
||||
* **Remote Models:**
|
||||
* The Add Model page now has a dedicated tab for remote model providers.
|
||||
* Groq, OpenAI, and Mistral remote models are now easier to configure.
|
||||
* **CUDA Compatibility:** GPUs with CUDA compute capability 5.0 such as the GTX 750 are now supported by the CUDA backend.
|
||||
* **New Model:** The non-MoE Granite model is now supported.
|
||||
* **Translation Updates:**
|
||||
* The Italian translation has been updated.
|
||||
* The Simplified Chinese translation has been significantly improved.
|
||||
* **Better Chat Templates:** The default chat templates for OLMoE 7B 0924/0125 and Granite 3.1 3B/8B have been improved.
|
||||
* **Whitespace Fixes:** DeepSeek-R1-based models now have better whitespace behavior in their output.
|
||||
* **Crash Fixes:** Several issues that could potentially cause GPT4All to crash have been fixed.
|
||||
|
@ -263,5 +263,20 @@
|
||||
"version": "3.7.0",
|
||||
"notes": "* **Windows ARM Support:** GPT4All now supports the Windows ARM platform, ensuring compatibility with devices powered by Qualcomm Snapdragon and Microsoft SQ-series processors.\n * **NOTE:** Support for GPU and/or NPU acceleration is not available at this time. Only the CPU will be used to run LLMs.\n * **NOTE:** You must install the new *Windows ARM* version of GPT4All from the website. The standard *Windows* version will not work due to emulation limitations.\n* **Fixed Updating on macOS:** The maintenance tool no longer crashes when attempting to update or uninstall GPT4All on Sequoia.\n * **NOTE:** If you have installed the version from the GitHub releases as a workaround for this issue, you can safely uninstall it and switch back to the version from the website.\n* **Fixed Chat Saving on macOS:** Chats now save as expected when the application is quit with Command-Q.\n* **Code Interpreter Improvements:**\n * The behavior when the code takes too long to execute and times out has been improved.\n * console.log now accepts multiple arguments for better compatibility with native JavaScript.\n* **Chat Templating Improvements:**\n * Two crashes and one compatibility issue have been fixed in the chat template parser.\n * The default chat template for EM German Mistral has been fixed.\n * Automatic replacements have been added for five new models as we continue to improve compatibility with common chat templates.\n",
|
||||
"contributors": "* Jared Van Bortel (Nomic AI)\n* Adam Treat (Nomic AI)\n* Riccardo Giovanetti (`@Harvester62`)"
|
||||
},
|
||||
{
|
||||
"version": "3.8.0",
|
||||
"notes": "* **Native DeepSeek-R1-Distill Support:** GPT4All now has robust support for the DeepSeek-R1 family of distillations.\n * Several model variants are now available on the downloads page.\n * Reasoning (wrapped in \"think\" tags) is displayed similarly to the Reasoner model.\n * The DeepSeek-R1 Qwen pretokenizer is now supported, resolving the loading failure in previous versions.\n * The model is now configured with a GPT4All-compatible prompt template by default.\n* **Chat Templating Overhaul:** The template parser has been *completely* replaced with one that has much better compatibility with common models.\n* **Code Interpreter Fixes:**\n * An issue preventing the code interpreter from logging a single string in v3.7.0 has been fixed.\n * The UI no longer freezes while the code interpreter is running a computation.\n* **Local Server Fixes:**\n * An issue preventing the server from using LocalDocs after the first request since v3.5.0 has been fixed.\n * System messages are now correctly hidden from the message history.\n",
|
||||
"contributors": "* Jared Van Bortel (Nomic AI)\n* Adam Treat (Nomic AI)\n* ThiloteE (`@ThiloteE`)"
|
||||
},
|
||||
{
|
||||
"version": "3.9.0",
|
||||
"notes": "* **LocalDocs Fix:** LocalDocs no longer shows an error on later messages with reasoning models.\n* **DeepSeek Fix:** DeepSeek-R1 reasoning (in 'think' tags) no longer appears in chat names and follow-up questions.\n* **Windows ARM Improvements:**\n * Graphical artifacts on some SoCs have been fixed.\n * A crash when adding a collection of PDFs to LocalDocs has been fixed.\n* **Template Parser Fixes:** Chat templates containing an unclosed comment no longer freeze GPT4All.\n* **New Models:** OLMoE and Granite MoE models are now supported.\n",
|
||||
"contributors": "* Jared Van Bortel (Nomic AI)\n* Adam Treat (Nomic AI)\n* ThiloteE (`@ThiloteE`)"
|
||||
},
|
||||
{
|
||||
"version": "3.10.0",
|
||||
"notes": "* **Remote Models:**\n * The Add Model page now has a dedicated tab for remote model providers.\n * Groq, OpenAI, and Mistral remote models are now easier to configure.\n* **CUDA Compatibility:** GPUs with CUDA compute capability 5.0 such as the GTX 750 are now supported by the CUDA backend.\n* **New Model:** The non-MoE Granite model is now supported.\n* **Translation Updates:**\n * The Italian translation has been updated.\n * The Simplified Chinese translation has been significantly improved.\n* **Better Chat Templates:** The default chat templates for OLMoE 7B 0924/0125 and Granite 3.1 3B/8B have been improved.\n* **Whitespace Fixes:** DeepSeek-R1-based models now have better whitespace behavior in their output.\n* **Crash Fixes:** Several issues that could potentially cause GPT4All to crash have been fixed.\n",
|
||||
"contributors": "* Jared Van Bortel (Nomic AI)\n* Adam Treat (Nomic AI)\n* ThiloteE (`@ThiloteE`)\n* Lil Bob (`@Junior2Ran`)\n* Riccardo Giovanetti (`@Harvester62`)"
|
||||
}
|
||||
]
|
||||
|
@ -204,7 +204,7 @@ ColumnLayout {
|
||||
Layout.minimumWidth: 200
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
visible: !isOnline && !installed && !calcHash && downloadError === ""
|
||||
visible: !installed && !calcHash && downloadError === ""
|
||||
Accessible.description: qsTr("Stop/restart/start the download")
|
||||
onClicked: {
|
||||
if (!isDownloading) {
|
||||
@ -230,52 +230,6 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
MySettingsButton {
|
||||
id: installButton
|
||||
visible: !installed && isOnline
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.minimumWidth: 200
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
text: qsTr("Install")
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
onClicked: {
|
||||
var apiKeyText = apiKey.text.trim(),
|
||||
baseUrlText = baseUrl.text.trim(),
|
||||
modelNameText = modelName.text.trim();
|
||||
|
||||
var apiKeyOk = apiKeyText !== "",
|
||||
baseUrlOk = !isCompatibleApi || baseUrlText !== "",
|
||||
modelNameOk = !isCompatibleApi || modelNameText !== "";
|
||||
|
||||
if (!apiKeyOk)
|
||||
apiKey.showError();
|
||||
if (!baseUrlOk)
|
||||
baseUrl.showError();
|
||||
if (!modelNameOk)
|
||||
modelName.showError();
|
||||
|
||||
if (!apiKeyOk || !baseUrlOk || !modelNameOk)
|
||||
return;
|
||||
|
||||
if (!isCompatibleApi)
|
||||
Download.installModel(
|
||||
filename,
|
||||
apiKeyText,
|
||||
);
|
||||
else
|
||||
Download.installCompatibleModel(
|
||||
modelNameText,
|
||||
apiKeyText,
|
||||
baseUrlText,
|
||||
);
|
||||
}
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: qsTr("Install")
|
||||
Accessible.description: qsTr("Install online model")
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
Label {
|
||||
@ -390,69 +344,6 @@ ColumnLayout {
|
||||
Accessible.description: qsTr("Displayed when the file hash is being calculated")
|
||||
}
|
||||
}
|
||||
|
||||
MyTextField {
|
||||
id: apiKey
|
||||
visible: !installed && isOnline
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.minimumWidth: 200
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
wrapMode: Text.WrapAnywhere
|
||||
function showError() {
|
||||
messageToast.show(qsTr("ERROR: $API_KEY is empty."));
|
||||
apiKey.placeholderTextColor = theme.textErrorColor;
|
||||
}
|
||||
onTextChanged: {
|
||||
apiKey.placeholderTextColor = theme.mutedTextColor;
|
||||
}
|
||||
placeholderText: qsTr("enter $API_KEY")
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
Accessible.description: qsTr("Whether the file hash is being calculated")
|
||||
}
|
||||
|
||||
MyTextField {
|
||||
id: baseUrl
|
||||
visible: !installed && isOnline && isCompatibleApi
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.minimumWidth: 200
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
wrapMode: Text.WrapAnywhere
|
||||
function showError() {
|
||||
messageToast.show(qsTr("ERROR: $BASE_URL is empty."));
|
||||
baseUrl.placeholderTextColor = theme.textErrorColor;
|
||||
}
|
||||
onTextChanged: {
|
||||
baseUrl.placeholderTextColor = theme.mutedTextColor;
|
||||
}
|
||||
placeholderText: qsTr("enter $BASE_URL")
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
Accessible.description: qsTr("Whether the file hash is being calculated")
|
||||
}
|
||||
|
||||
MyTextField {
|
||||
id: modelName
|
||||
visible: !installed && isOnline && isCompatibleApi
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.minimumWidth: 200
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
wrapMode: Text.WrapAnywhere
|
||||
function showError() {
|
||||
messageToast.show(qsTr("ERROR: $MODEL_NAME is empty."))
|
||||
modelName.placeholderTextColor = theme.textErrorColor;
|
||||
}
|
||||
onTextChanged: {
|
||||
modelName.placeholderTextColor = theme.mutedTextColor;
|
||||
}
|
||||
placeholderText: qsTr("enter $MODEL_NAME")
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
Accessible.description: qsTr("Whether the file hash is being calculated")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,13 @@ Rectangle {
|
||||
gpt4AllModelView.show();
|
||||
}
|
||||
}
|
||||
MyTabButton {
|
||||
text: qsTr("Remote Providers")
|
||||
isSelected: remoteModelView.isShown()
|
||||
onPressed: {
|
||||
remoteModelView.show();
|
||||
}
|
||||
}
|
||||
MyTabButton {
|
||||
text: qsTr("HuggingFace")
|
||||
isSelected: huggingfaceModelView.isShown()
|
||||
@ -112,7 +119,20 @@ Rectangle {
|
||||
stackLayout.currentIndex = 0;
|
||||
}
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 0
|
||||
return stackLayout.currentIndex === 0;
|
||||
}
|
||||
}
|
||||
|
||||
AddRemoteModelView {
|
||||
id: remoteModelView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
function show() {
|
||||
stackLayout.currentIndex = 1;
|
||||
}
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,10 +146,10 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
function show() {
|
||||
stackLayout.currentIndex = 1;
|
||||
stackLayout.currentIndex = 2;
|
||||
}
|
||||
function isShown() {
|
||||
return stackLayout.currentIndex === 1
|
||||
return stackLayout.currentIndex === 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
147
gpt4all-chat/qml/AddRemoteModelView.qml
Normal file
147
gpt4all-chat/qml/AddRemoteModelView.qml
Normal file
@ -0,0 +1,147 @@
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.Basic
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
import Qt.labs.folderlistmodel
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import llm
|
||||
import chatlistmodel
|
||||
import download
|
||||
import modellist
|
||||
import network
|
||||
import gpt4all
|
||||
import mysettings
|
||||
import localdocs
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
spacing: 5
|
||||
|
||||
Label {
|
||||
Layout.topMargin: 0
|
||||
Layout.bottomMargin: 25
|
||||
Layout.rightMargin: 150 * theme.fontScale
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
verticalAlignment: Text.AlignTop
|
||||
text: qsTr("Various remote model providers that use network resources for inference.")
|
||||
font.pixelSize: theme.fontSizeLarger
|
||||
color: theme.textColor
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
contentWidth: availableWidth
|
||||
clip: true
|
||||
Flow {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 20
|
||||
bottomPadding: 20
|
||||
property int childWidth: 330 * theme.fontScale
|
||||
property int childHeight: 400 + 166 * theme.fontScale
|
||||
RemoteModelCard {
|
||||
width: parent.childWidth
|
||||
height: parent.childHeight
|
||||
providerBaseUrl: "https://api.groq.com/openai/v1/"
|
||||
providerName: qsTr("Groq")
|
||||
providerImage: "qrc:/gpt4all/icons/groq.svg"
|
||||
providerDesc: qsTr('Groq offers a high-performance AI inference engine designed for low-latency and efficient processing. Optimized for real-time applications, Groq’s technology is ideal for users who need fast responses from open large language models and other AI workloads.<br><br>Get your API key: <a href="https://console.groq.com/keys">https://groq.com/</a>')
|
||||
modelWhitelist: [
|
||||
// last updated 2025-02-24
|
||||
"deepseek-r1-distill-llama-70b",
|
||||
"deepseek-r1-distill-qwen-32b",
|
||||
"gemma2-9b-it",
|
||||
"llama-3.1-8b-instant",
|
||||
"llama-3.2-1b-preview",
|
||||
"llama-3.2-3b-preview",
|
||||
"llama-3.3-70b-specdec",
|
||||
"llama-3.3-70b-versatile",
|
||||
"llama3-70b-8192",
|
||||
"llama3-8b-8192",
|
||||
"mixtral-8x7b-32768",
|
||||
"qwen-2.5-32b",
|
||||
"qwen-2.5-coder-32b",
|
||||
]
|
||||
}
|
||||
RemoteModelCard {
|
||||
width: parent.childWidth
|
||||
height: parent.childHeight
|
||||
providerBaseUrl: "https://api.openai.com/v1/"
|
||||
providerName: qsTr("OpenAI")
|
||||
providerImage: "qrc:/gpt4all/icons/openai.svg"
|
||||
providerDesc: qsTr('OpenAI provides access to advanced AI models, including GPT-4 supporting a wide range of applications, from conversational AI to content generation and code completion.<br><br>Get your API key: <a href="https://platform.openai.com/signup">https://openai.com/</a>')
|
||||
modelWhitelist: [
|
||||
// last updated 2025-02-24
|
||||
"gpt-3.5-turbo",
|
||||
"gpt-3.5-turbo-16k",
|
||||
"gpt-4",
|
||||
"gpt-4-32k",
|
||||
"gpt-4-turbo",
|
||||
"gpt-4o",
|
||||
]
|
||||
}
|
||||
RemoteModelCard {
|
||||
width: parent.childWidth
|
||||
height: parent.childHeight
|
||||
providerBaseUrl: "https://api.mistral.ai/v1/"
|
||||
providerName: qsTr("Mistral")
|
||||
providerImage: "qrc:/gpt4all/icons/mistral.svg"
|
||||
providerDesc: qsTr('Mistral AI specializes in efficient, open-weight language models optimized for various natural language processing tasks. Their models are designed for flexibility and performance, making them a solid option for applications requiring scalable AI solutions.<br><br>Get your API key: <a href="https://mistral.ai/">https://mistral.ai/</a>')
|
||||
modelWhitelist: [
|
||||
// last updated 2025-02-24
|
||||
"codestral-2405",
|
||||
"codestral-2411-rc5",
|
||||
"codestral-2412",
|
||||
"codestral-2501",
|
||||
"codestral-latest",
|
||||
"codestral-mamba-2407",
|
||||
"codestral-mamba-latest",
|
||||
"ministral-3b-2410",
|
||||
"ministral-3b-latest",
|
||||
"ministral-8b-2410",
|
||||
"ministral-8b-latest",
|
||||
"mistral-large-2402",
|
||||
"mistral-large-2407",
|
||||
"mistral-large-2411",
|
||||
"mistral-large-latest",
|
||||
"mistral-medium-2312",
|
||||
"mistral-medium-latest",
|
||||
"mistral-saba-2502",
|
||||
"mistral-saba-latest",
|
||||
"mistral-small-2312",
|
||||
"mistral-small-2402",
|
||||
"mistral-small-2409",
|
||||
"mistral-small-2501",
|
||||
"mistral-small-latest",
|
||||
"mistral-tiny-2312",
|
||||
"mistral-tiny-2407",
|
||||
"mistral-tiny-latest",
|
||||
"open-codestral-mamba",
|
||||
"open-mistral-7b",
|
||||
"open-mistral-nemo",
|
||||
"open-mistral-nemo-2407",
|
||||
"open-mixtral-8x22b",
|
||||
"open-mixtral-8x22b-2404",
|
||||
"open-mixtral-8x7b",
|
||||
]
|
||||
}
|
||||
RemoteModelCard {
|
||||
width: parent.childWidth
|
||||
height: parent.childHeight
|
||||
providerIsCustom: true
|
||||
providerName: qsTr("Custom")
|
||||
providerImage: "qrc:/gpt4all/icons/antenna_3.svg"
|
||||
providerDesc: qsTr("The custom provider option allows users to connect their own OpenAI-compatible AI models or third-party inference services. This is useful for organizations with proprietary models or those leveraging niche AI providers not listed here.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -198,6 +198,7 @@ GridLayout {
|
||||
isError: false
|
||||
isThinking: true
|
||||
thinkingTime: modelData.thinkingTime
|
||||
visible: modelData.content !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,29 +60,30 @@ ComboBox {
|
||||
highlighted: comboBox.highlightedIndex === index
|
||||
}
|
||||
popup: Popup {
|
||||
// FIXME This should be made much nicer to take into account lists that are very long so
|
||||
// that it is scrollable and also sized optimally taking into account the x,y and the content
|
||||
// width and height as well as the window width and height
|
||||
y: comboBox.height - 1
|
||||
width: comboBox.width
|
||||
implicitHeight: contentItem.implicitHeight + 20
|
||||
implicitHeight: Math.min(window.height - y, contentItem.implicitHeight + 20)
|
||||
padding: 0
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitWidth: myListView.contentWidth
|
||||
implicitWidth: comboBox.width
|
||||
implicitHeight: myListView.contentHeight
|
||||
color: "transparent"
|
||||
ListView {
|
||||
id: myListView
|
||||
radius: 10
|
||||
ScrollView {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
ListView {
|
||||
id: myListView
|
||||
implicitHeight: contentHeight
|
||||
model: comboBox.popup.visible ? comboBox.delegateModel : null
|
||||
currentIndex: comboBox.highlightedIndex
|
||||
ScrollIndicator.vertical: ScrollIndicator { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: theme.menuBackgroundColor//theme.controlBorder
|
||||
|
221
gpt4all-chat/qml/RemoteModelCard.qml
Normal file
221
gpt4all-chat/qml/RemoteModelCard.qml
Normal file
@ -0,0 +1,221 @@
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.Basic
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
import Qt.labs.folderlistmodel
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import llm
|
||||
import chatlistmodel
|
||||
import download
|
||||
import modellist
|
||||
import network
|
||||
import gpt4all
|
||||
import mysettings
|
||||
import localdocs
|
||||
|
||||
|
||||
Rectangle {
|
||||
property alias providerName: providerNameLabel.text
|
||||
property alias providerImage: myimage.source
|
||||
property alias providerDesc: providerDescLabel.text
|
||||
property string providerBaseUrl: ""
|
||||
property bool providerIsCustom: false
|
||||
property var modelWhitelist: null
|
||||
|
||||
color: theme.conversationBackground
|
||||
radius: 10
|
||||
border.width: 1
|
||||
border.color: theme.controlBorder
|
||||
implicitHeight: topColumn.height + bottomColumn.height + 33 * theme.fontScale
|
||||
|
||||
ColumnLayout {
|
||||
id: topColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 20
|
||||
spacing: 15 * theme.fontScale
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
spacing: 10
|
||||
Item {
|
||||
Layout.preferredWidth: 27 * theme.fontScale
|
||||
Layout.preferredHeight: 27 * theme.fontScale
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
Image {
|
||||
id: myimage
|
||||
anchors.centerIn: parent
|
||||
sourceSize.width: parent.width
|
||||
sourceSize.height: parent.height
|
||||
mipmap: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: providerNameLabel
|
||||
color: theme.textColor
|
||||
font.pixelSize: theme.fontSizeBanner
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: providerDescLabel
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.Wrap
|
||||
color: theme.settingsTitleTextColor
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
onLinkActivated: function(link) { Qt.openUrlExternally(link); }
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton // pass clicks to parent
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: bottomColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 20
|
||||
spacing: 30
|
||||
|
||||
ColumnLayout {
|
||||
MySettingsLabel {
|
||||
text: qsTr("API Key")
|
||||
font.bold: true
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
color: theme.settingsTitleTextColor
|
||||
}
|
||||
|
||||
MyTextField {
|
||||
id: apiKeyField
|
||||
Layout.fillWidth: true
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
wrapMode: Text.WrapAnywhere
|
||||
function showError() {
|
||||
messageToast.show(qsTr("ERROR: $API_KEY is empty."));
|
||||
apiKeyField.placeholderTextColor = theme.textErrorColor;
|
||||
}
|
||||
onTextChanged: {
|
||||
apiKeyField.placeholderTextColor = theme.mutedTextColor;
|
||||
if (!providerIsCustom) {
|
||||
let models = ModelList.remoteModelList(apiKeyField.text, providerBaseUrl);
|
||||
if (modelWhitelist !== null)
|
||||
models = models.filter(m => modelWhitelist.includes(m));
|
||||
myModelList.model = models;
|
||||
myModelList.currentIndex = -1;
|
||||
}
|
||||
}
|
||||
placeholderText: qsTr("enter $API_KEY")
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
Accessible.description: qsTr("Whether the file hash is being calculated")
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: providerIsCustom
|
||||
MySettingsLabel {
|
||||
text: qsTr("Base Url")
|
||||
font.bold: true
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
color: theme.settingsTitleTextColor
|
||||
}
|
||||
MyTextField {
|
||||
id: baseUrlField
|
||||
Layout.fillWidth: true
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
wrapMode: Text.WrapAnywhere
|
||||
function showError() {
|
||||
messageToast.show(qsTr("ERROR: $BASE_URL is empty."));
|
||||
baseUrlField.placeholderTextColor = theme.textErrorColor;
|
||||
}
|
||||
onTextChanged: {
|
||||
baseUrlField.placeholderTextColor = theme.mutedTextColor;
|
||||
}
|
||||
placeholderText: qsTr("enter $BASE_URL")
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
visible: providerIsCustom
|
||||
MySettingsLabel {
|
||||
text: qsTr("Model Name")
|
||||
font.bold: true
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
color: theme.settingsTitleTextColor
|
||||
}
|
||||
MyTextField {
|
||||
id: modelNameField
|
||||
Layout.fillWidth: true
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
wrapMode: Text.WrapAnywhere
|
||||
function showError() {
|
||||
messageToast.show(qsTr("ERROR: $MODEL_NAME is empty."))
|
||||
modelNameField.placeholderTextColor = theme.textErrorColor;
|
||||
}
|
||||
onTextChanged: {
|
||||
modelNameField.placeholderTextColor = theme.mutedTextColor;
|
||||
}
|
||||
placeholderText: qsTr("enter $MODEL_NAME")
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.name: placeholderText
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: myModelList.count > 0 && !providerIsCustom
|
||||
|
||||
MySettingsLabel {
|
||||
text: qsTr("Models")
|
||||
font.bold: true
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
color: theme.settingsTitleTextColor
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
|
||||
MyComboBox {
|
||||
Layout.fillWidth: true
|
||||
id: myModelList
|
||||
currentIndex: -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MySettingsButton {
|
||||
id: installButton
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: qsTr("Install")
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
|
||||
property string apiKeyText: apiKeyField.text.trim()
|
||||
property string baseUrlText: providerIsCustom ? baseUrlField.text.trim() : providerBaseUrl.trim()
|
||||
property string modelNameText: providerIsCustom ? modelNameField.text.trim() : myModelList.currentText.trim()
|
||||
|
||||
enabled: apiKeyText !== "" && baseUrlText !== "" && modelNameText !== ""
|
||||
|
||||
onClicked: {
|
||||
Download.installCompatibleModel(
|
||||
modelNameText,
|
||||
apiKeyText,
|
||||
baseUrlText,
|
||||
);
|
||||
myModelList.currentIndex = -1;
|
||||
}
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: qsTr("Install")
|
||||
Accessible.description: qsTr("Install remote model")
|
||||
}
|
||||
}
|
||||
}
|
@ -7,24 +7,26 @@
|
||||
#include "toolcallparser.h"
|
||||
#include "toolmodel.h"
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QByteArray>
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QIODevice>
|
||||
#include <QLatin1String>
|
||||
#include <QMap>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <Qt>
|
||||
#include <QtAssert>
|
||||
#include <QtLogging>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
using namespace ToolEnums;
|
||||
|
||||
|
||||
Chat::Chat(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_id(Network::globalInstance()->generateUniqueId())
|
||||
@ -255,7 +257,7 @@ void Chat::responseStopped(qint64 promptResponseMs)
|
||||
|
||||
ToolCallParser parser;
|
||||
parser.update(possibleToolcall.toUtf8());
|
||||
if (parser.state() == ToolEnums::ParseState::Complete && parser.startTag() != ToolCallConstants::ThinkTag)
|
||||
if (parser.state() == ToolEnums::ParseState::Complete && parser.startTag() != ToolCallConstants::ThinkStartTag)
|
||||
processToolCall(parser.toolCall());
|
||||
else
|
||||
responseComplete();
|
||||
@ -381,11 +383,8 @@ void Chat::trySwitchContextOfLoadedModel()
|
||||
|
||||
void Chat::generatedNameChanged(const QString &name)
|
||||
{
|
||||
// Only use the first three words maximum and remove newlines and extra spaces
|
||||
m_generatedName = name.simplified();
|
||||
QStringList words = m_generatedName.split(' ', Qt::SkipEmptyParts);
|
||||
int wordCount = qMin(7, words.size());
|
||||
m_name = words.mid(0, wordCount).join(' ');
|
||||
m_generatedName = name;
|
||||
m_name = name;
|
||||
emit nameChanged();
|
||||
m_needsSave = true;
|
||||
}
|
||||
|
@ -3,21 +3,26 @@
|
||||
|
||||
#include "chatllm.h"
|
||||
#include "chatmodel.h"
|
||||
#include "database.h" // IWYU pragma: keep
|
||||
#include "localdocsmodel.h" // IWYU pragma: keep
|
||||
#include "database.h"
|
||||
#include "localdocsmodel.h"
|
||||
#include "modellist.h"
|
||||
#include "tool.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlEngine> // IWYU pragma: keep
|
||||
#include <QString>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QStringView>
|
||||
#include <QtGlobal>
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QtTypes>
|
||||
|
||||
// IWYU pragma: no_forward_declare LocalDocsCollectionsModel
|
||||
// IWYU pragma: no_forward_declare ToolCallInfo
|
||||
class QDataStream;
|
||||
|
||||
|
||||
class Chat : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <QAnyStringView>
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QGuiApplication>
|
||||
@ -9,15 +12,17 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QLatin1String>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QStringView>
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
#include <QUtf8StringView>
|
||||
#include <QUtf8StringView> // IWYU pragma: keep
|
||||
#include <QVariant>
|
||||
#include <QXmlStreamReader>
|
||||
#include <Qt>
|
||||
#include <QtGlobal>
|
||||
#include <QtAssert>
|
||||
#include <QtLogging>
|
||||
|
||||
#include <expected>
|
||||
@ -29,6 +34,7 @@ using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
ChatAPI::ChatAPI()
|
||||
: QObject(nullptr)
|
||||
, m_modelName("gpt-3.5-turbo")
|
||||
|
@ -3,10 +3,11 @@
|
||||
|
||||
#include <gpt4all-backend/llmodel.h>
|
||||
|
||||
#include <QByteArray> // IWYU pragma: keep
|
||||
#include <QByteArray>
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QtPreprocessorSupport>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@ -17,9 +18,11 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// IWYU pragma: no_forward_declare QByteArray
|
||||
class ChatAPI;
|
||||
class QNetworkAccessManager;
|
||||
|
||||
class ChatAPI;
|
||||
|
||||
class ChatAPIWorker : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -1,23 +1,24 @@
|
||||
#include "chatlistmodel.h"
|
||||
|
||||
#include "database.h" // IWYU pragma: keep
|
||||
#include "mysettings.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDataStream>
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#include <QEvent>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QGlobalStatic>
|
||||
#include <QGuiApplication>
|
||||
#include <QIODevice>
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <Qt>
|
||||
#include <QtTypes>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
|
||||
static constexpr quint32 CHAT_FORMAT_MAGIC = 0xF5D553CC;
|
||||
static constexpr qint32 CHAT_FORMAT_VERSION = 12;
|
||||
|
@ -7,17 +7,20 @@
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QByteArray>
|
||||
#include <QDate>
|
||||
#include <QDebug>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <QVector> // IWYU pragma: keep
|
||||
#include <Qt>
|
||||
#include <QtGlobal>
|
||||
#include <QtAssert>
|
||||
#include <QtLogging>
|
||||
#include <QtPreprocessorSupport>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -15,31 +15,40 @@
|
||||
#include <minja/minja.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <QChar>
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QGlobalStatic>
|
||||
#include <QIODevice>
|
||||
#include <QIODevice> // IWYU pragma: keep
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QMutex> // IWYU pragma: keep
|
||||
#include <QMutexLocker> // IWYU pragma: keep
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include <QRegularExpression> // IWYU pragma: keep
|
||||
#include <QRegularExpressionMatch> // IWYU pragma: keep
|
||||
#include <QSet>
|
||||
#include <QStringView>
|
||||
#include <QTextStream>
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QWaitCondition>
|
||||
#include <Qt>
|
||||
#include <QtAssert>
|
||||
#include <QtLogging>
|
||||
#include <QtTypes> // IWYU pragma: keep
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
@ -92,6 +101,70 @@ static const std::shared_ptr<minja::Context> &jinjaEnv()
|
||||
return environment;
|
||||
}
|
||||
|
||||
class BaseResponseHandler {
|
||||
public:
|
||||
virtual void onSplitIntoTwo (const QString &startTag, const QString &firstBuffer, const QString &secondBuffer) = 0;
|
||||
virtual void onSplitIntoThree (const QString &secondBuffer, const QString &thirdBuffer) = 0;
|
||||
// "old-style" responses, with all of the implementation details left in
|
||||
virtual void onOldResponseChunk(const QByteArray &chunk) = 0;
|
||||
// notify of a "new-style" response that has been cleaned of tool calling
|
||||
virtual bool onBufferResponse (const QString &response, int bufferIdx) = 0;
|
||||
// notify of a "new-style" response, no tool calling applicable
|
||||
virtual bool onRegularResponse () = 0;
|
||||
virtual bool getStopGenerating () const = 0;
|
||||
};
|
||||
|
||||
static auto promptModelWithTools(
|
||||
LLModel *model, const LLModel::PromptCallback &promptCallback, BaseResponseHandler &respHandler,
|
||||
const LLModel::PromptContext &ctx, const QByteArray &prompt, const QStringList &toolNames
|
||||
) -> std::pair<QStringList, bool>
|
||||
{
|
||||
ToolCallParser toolCallParser(toolNames);
|
||||
auto handleResponse = [&toolCallParser, &respHandler](LLModel::Token token, std::string_view piece) -> bool {
|
||||
Q_UNUSED(token)
|
||||
|
||||
toolCallParser.update(piece.data());
|
||||
|
||||
// Split the response into two if needed
|
||||
if (toolCallParser.numberOfBuffers() < 2 && toolCallParser.splitIfPossible()) {
|
||||
const auto parseBuffers = toolCallParser.buffers();
|
||||
Q_ASSERT(parseBuffers.size() == 2);
|
||||
respHandler.onSplitIntoTwo(toolCallParser.startTag(), parseBuffers.at(0), parseBuffers.at(1));
|
||||
}
|
||||
|
||||
// Split the response into three if needed
|
||||
if (toolCallParser.numberOfBuffers() < 3 && toolCallParser.startTag() == ToolCallConstants::ThinkStartTag
|
||||
&& toolCallParser.splitIfPossible()) {
|
||||
const auto parseBuffers = toolCallParser.buffers();
|
||||
Q_ASSERT(parseBuffers.size() == 3);
|
||||
respHandler.onSplitIntoThree(parseBuffers.at(1), parseBuffers.at(2));
|
||||
}
|
||||
|
||||
respHandler.onOldResponseChunk(QByteArray::fromRawData(piece.data(), piece.size()));
|
||||
|
||||
bool ok;
|
||||
const auto parseBuffers = toolCallParser.buffers();
|
||||
if (parseBuffers.size() > 1) {
|
||||
ok = respHandler.onBufferResponse(parseBuffers.last(), parseBuffers.size() - 1);
|
||||
} else {
|
||||
ok = respHandler.onRegularResponse();
|
||||
}
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
const bool shouldExecuteToolCall = toolCallParser.state() == ToolEnums::ParseState::Complete
|
||||
&& toolCallParser.startTag() != ToolCallConstants::ThinkStartTag;
|
||||
|
||||
return !shouldExecuteToolCall && !respHandler.getStopGenerating();
|
||||
};
|
||||
model->prompt(std::string_view(prompt), promptCallback, handleResponse, ctx);
|
||||
|
||||
const bool shouldExecuteToolCall = toolCallParser.state() == ToolEnums::ParseState::Complete
|
||||
&& toolCallParser.startTag() != ToolCallConstants::ThinkStartTag;
|
||||
|
||||
return { toolCallParser.buffers(), shouldExecuteToolCall };
|
||||
}
|
||||
|
||||
class LLModelStore {
|
||||
public:
|
||||
static LLModelStore *globalInstance();
|
||||
@ -730,7 +803,8 @@ std::vector<MessageItem> ChatLLM::forkConversation(const QString &prompt) const
|
||||
conversation.reserve(items.size() + 1);
|
||||
conversation.assign(items.begin(), items.end());
|
||||
}
|
||||
conversation.emplace_back(MessageItem::Type::Prompt, prompt.toUtf8());
|
||||
qsizetype nextIndex = conversation.empty() ? 0 : conversation.back().index().value() + 1;
|
||||
conversation.emplace_back(nextIndex, MessageItem::Type::Prompt, prompt.toUtf8());
|
||||
return conversation;
|
||||
}
|
||||
|
||||
@ -801,7 +875,7 @@ std::string ChatLLM::applyJinjaTemplate(std::span<const MessageItem> items) cons
|
||||
json::array_t messages;
|
||||
messages.reserve(useSystem + items.size());
|
||||
if (useSystem) {
|
||||
systemItem = std::make_unique<MessageItem>(MessageItem::Type::System, systemMessage.toUtf8());
|
||||
systemItem = std::make_unique<MessageItem>(MessageItem::system_tag, systemMessage.toUtf8());
|
||||
messages.emplace_back(makeMap(*systemItem));
|
||||
}
|
||||
for (auto &item : items)
|
||||
@ -855,14 +929,14 @@ auto ChatLLM::promptInternalChat(const QStringList &enabledCollections, const LL
|
||||
// Find the prompt that represents the query. Server chats are flexible and may not have one.
|
||||
auto items = getChat();
|
||||
if (auto peer = m_chatModel->getPeer(items, items.end() - 1)) // peer of response
|
||||
query = { *peer - items.begin(), (*peer)->content() };
|
||||
query = { (*peer)->index().value(), (*peer)->content() };
|
||||
}
|
||||
|
||||
if (query) {
|
||||
auto &[promptIndex, queryStr] = *query;
|
||||
const int retrievalSize = MySettings::globalInstance()->localDocsRetrievalSize();
|
||||
emit requestRetrieveFromDB(enabledCollections, queryStr, retrievalSize, &databaseResults); // blocks
|
||||
m_chatModel->updateSources(promptIndex + startOffset, databaseResults);
|
||||
m_chatModel->updateSources(promptIndex, databaseResults);
|
||||
emit databaseResultsChanged(databaseResults);
|
||||
}
|
||||
}
|
||||
@ -881,6 +955,63 @@ auto ChatLLM::promptInternalChat(const QStringList &enabledCollections, const LL
|
||||
};
|
||||
}
|
||||
|
||||
class ChatViewResponseHandler : public BaseResponseHandler {
|
||||
public:
|
||||
ChatViewResponseHandler(ChatLLM *cllm, QElapsedTimer *totalTime, ChatLLM::PromptResult *result)
|
||||
: m_cllm(cllm), m_totalTime(totalTime), m_result(result) {}
|
||||
|
||||
void onSplitIntoTwo(const QString &startTag, const QString &firstBuffer, const QString &secondBuffer) override
|
||||
{
|
||||
if (startTag == ToolCallConstants::ThinkStartTag)
|
||||
m_cllm->m_chatModel->splitThinking({ firstBuffer, secondBuffer });
|
||||
else
|
||||
m_cllm->m_chatModel->splitToolCall({ firstBuffer, secondBuffer });
|
||||
}
|
||||
|
||||
void onSplitIntoThree(const QString &secondBuffer, const QString &thirdBuffer) override
|
||||
{
|
||||
m_cllm->m_chatModel->endThinking({ secondBuffer, thirdBuffer }, m_totalTime->elapsed());
|
||||
}
|
||||
|
||||
void onOldResponseChunk(const QByteArray &chunk) override
|
||||
{
|
||||
m_result->responseTokens++;
|
||||
m_cllm->m_timer->inc();
|
||||
m_result->response.append(chunk);
|
||||
}
|
||||
|
||||
bool onBufferResponse(const QString &response, int bufferIdx) override
|
||||
{
|
||||
Q_UNUSED(bufferIdx)
|
||||
try {
|
||||
QString r = response;
|
||||
m_cllm->m_chatModel->setResponseValue(removeLeadingWhitespace(r));
|
||||
} catch (const std::exception &e) {
|
||||
// We have a try/catch here because the main thread might have removed the response from
|
||||
// the chatmodel by erasing the conversation during the response... the main thread sets
|
||||
// m_stopGenerating before doing so, but it doesn't wait after that to reset the chatmodel
|
||||
Q_ASSERT(m_cllm->m_stopGenerating);
|
||||
return false;
|
||||
}
|
||||
emit m_cllm->responseChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onRegularResponse() override
|
||||
{
|
||||
auto respStr = QString::fromUtf8(m_result->response);
|
||||
return onBufferResponse(respStr, 0);
|
||||
}
|
||||
|
||||
bool getStopGenerating() const override
|
||||
{ return m_cllm->m_stopGenerating; }
|
||||
|
||||
private:
|
||||
ChatLLM *m_cllm;
|
||||
QElapsedTimer *m_totalTime;
|
||||
ChatLLM::PromptResult *m_result;
|
||||
};
|
||||
|
||||
auto ChatLLM::promptInternal(
|
||||
const std::variant<std::span<const MessageItem>, std::string_view> &prompt,
|
||||
const LLModel::PromptContext &ctx,
|
||||
@ -930,64 +1061,20 @@ auto ChatLLM::promptInternal(
|
||||
|
||||
QElapsedTimer totalTime;
|
||||
totalTime.start();
|
||||
ChatViewResponseHandler respHandler(this, &totalTime, &result);
|
||||
|
||||
m_timer->start();
|
||||
|
||||
ToolCallParser toolCallParser;
|
||||
auto handleResponse = [this, &result, &toolCallParser, &totalTime](LLModel::Token token, std::string_view piece) -> bool {
|
||||
Q_UNUSED(token)
|
||||
result.responseTokens++;
|
||||
m_timer->inc();
|
||||
|
||||
toolCallParser.update(piece.data());
|
||||
|
||||
// Split the response into two if needed and create chat items
|
||||
if (toolCallParser.numberOfBuffers() < 2 && toolCallParser.splitIfPossible()) {
|
||||
const auto parseBuffers = toolCallParser.buffers();
|
||||
Q_ASSERT(parseBuffers.size() == 2);
|
||||
if (toolCallParser.startTag() == ToolCallConstants::ThinkTag)
|
||||
m_chatModel->splitThinking({parseBuffers.at(0), parseBuffers.at(1)});
|
||||
else
|
||||
m_chatModel->splitToolCall({parseBuffers.at(0), parseBuffers.at(1)});
|
||||
}
|
||||
|
||||
// Split the response into three if needed and create chat items
|
||||
if (toolCallParser.numberOfBuffers() < 3 && toolCallParser.startTag() == ToolCallConstants::ThinkTag
|
||||
&& toolCallParser.splitIfPossible()) {
|
||||
const auto parseBuffers = toolCallParser.buffers();
|
||||
Q_ASSERT(parseBuffers.size() == 3);
|
||||
m_chatModel->endThinking({parseBuffers.at(1), parseBuffers.at(2)}, totalTime.elapsed());
|
||||
}
|
||||
|
||||
result.response.append(piece.data(), piece.size());
|
||||
auto respStr = QString::fromUtf8(result.response);
|
||||
|
||||
try {
|
||||
const auto parseBuffers = toolCallParser.buffers();
|
||||
if (parseBuffers.size() > 1)
|
||||
m_chatModel->setResponseValue(parseBuffers.last());
|
||||
else
|
||||
m_chatModel->setResponseValue(removeLeadingWhitespace(respStr));
|
||||
} catch (const std::exception &e) {
|
||||
// We have a try/catch here because the main thread might have removed the response from
|
||||
// the chatmodel by erasing the conversation during the response... the main thread sets
|
||||
// m_stopGenerating before doing so, but it doesn't wait after that to reset the chatmodel
|
||||
Q_ASSERT(m_stopGenerating);
|
||||
return false;
|
||||
}
|
||||
|
||||
emit responseChanged();
|
||||
|
||||
const bool shouldExecuteToolCall = toolCallParser.state() == ToolEnums::ParseState::Complete
|
||||
&& toolCallParser.startTag() != ToolCallConstants::ThinkTag;
|
||||
|
||||
return !shouldExecuteToolCall && !m_stopGenerating;
|
||||
};
|
||||
|
||||
QStringList finalBuffers;
|
||||
bool shouldExecuteTool;
|
||||
try {
|
||||
emit promptProcessing();
|
||||
m_llModelInfo.model->setThreadCount(mySettings->threadCount());
|
||||
m_stopGenerating = false;
|
||||
m_llModelInfo.model->prompt(conversation, handlePrompt, handleResponse, ctx);
|
||||
std::tie(finalBuffers, shouldExecuteTool) = promptModelWithTools(
|
||||
m_llModelInfo.model.get(), handlePrompt, respHandler, ctx,
|
||||
QByteArray::fromRawData(conversation.data(), conversation.size()),
|
||||
ToolCallConstants::AllTagNames
|
||||
);
|
||||
} catch (...) {
|
||||
m_timer->stop();
|
||||
throw;
|
||||
@ -996,22 +1083,18 @@ auto ChatLLM::promptInternal(
|
||||
m_timer->stop();
|
||||
qint64 elapsed = totalTime.elapsed();
|
||||
|
||||
const auto parseBuffers = toolCallParser.buffers();
|
||||
const bool shouldExecuteToolCall = toolCallParser.state() == ToolEnums::ParseState::Complete
|
||||
&& toolCallParser.startTag() != ToolCallConstants::ThinkTag;
|
||||
|
||||
// trim trailing whitespace
|
||||
auto respStr = QString::fromUtf8(result.response);
|
||||
if (!respStr.isEmpty() && (std::as_const(respStr).back().isSpace() || parseBuffers.size() > 1)) {
|
||||
if (parseBuffers.size() > 1)
|
||||
m_chatModel->setResponseValue(parseBuffers.last());
|
||||
if (!respStr.isEmpty() && (std::as_const(respStr).back().isSpace() || finalBuffers.size() > 1)) {
|
||||
if (finalBuffers.size() > 1)
|
||||
m_chatModel->setResponseValue(finalBuffers.last().trimmed());
|
||||
else
|
||||
m_chatModel->setResponseValue(respStr.trimmed());
|
||||
emit responseChanged();
|
||||
}
|
||||
|
||||
bool doQuestions = false;
|
||||
if (!m_isServer && messageItems && !shouldExecuteToolCall) {
|
||||
if (!m_isServer && messageItems && !shouldExecuteTool) {
|
||||
switch (mySettings->suggestionMode()) {
|
||||
case SuggestionMode::On: doQuestions = true; break;
|
||||
case SuggestionMode::LocalDocsOnly: doQuestions = usedLocalDocs; break;
|
||||
@ -1089,6 +1172,66 @@ void ChatLLM::reloadModel()
|
||||
loadModel(m);
|
||||
}
|
||||
|
||||
// This class throws discards the text within thinking tags, for use with chat names and follow-up questions.
|
||||
class SimpleResponseHandler : public BaseResponseHandler {
|
||||
public:
|
||||
SimpleResponseHandler(ChatLLM *cllm)
|
||||
: m_cllm(cllm) {}
|
||||
|
||||
void onSplitIntoTwo(const QString &startTag, const QString &firstBuffer, const QString &secondBuffer) override
|
||||
{ /* no-op */ }
|
||||
|
||||
void onSplitIntoThree(const QString &secondBuffer, const QString &thirdBuffer) override
|
||||
{ /* no-op */ }
|
||||
|
||||
void onOldResponseChunk(const QByteArray &chunk) override
|
||||
{ m_response.append(chunk); }
|
||||
|
||||
bool onBufferResponse(const QString &response, int bufferIdx) override
|
||||
{
|
||||
if (bufferIdx == 1)
|
||||
return true; // ignore "think" content
|
||||
return onSimpleResponse(response);
|
||||
}
|
||||
|
||||
bool onRegularResponse() override
|
||||
{ return onBufferResponse(QString::fromUtf8(m_response), 0); }
|
||||
|
||||
bool getStopGenerating() const override
|
||||
{ return m_cllm->m_stopGenerating; }
|
||||
|
||||
protected:
|
||||
virtual bool onSimpleResponse(const QString &response) = 0;
|
||||
|
||||
protected:
|
||||
ChatLLM *m_cllm;
|
||||
QByteArray m_response;
|
||||
};
|
||||
|
||||
class NameResponseHandler : public SimpleResponseHandler {
|
||||
private:
|
||||
// max length of chat names, in words
|
||||
static constexpr qsizetype MAX_WORDS = 3;
|
||||
|
||||
public:
|
||||
using SimpleResponseHandler::SimpleResponseHandler;
|
||||
|
||||
protected:
|
||||
bool onSimpleResponse(const QString &response) override
|
||||
{
|
||||
QTextStream stream(const_cast<QString *>(&response), QIODeviceBase::ReadOnly);
|
||||
QStringList words;
|
||||
while (!stream.atEnd() && words.size() < MAX_WORDS) {
|
||||
QString word;
|
||||
stream >> word;
|
||||
words << word;
|
||||
}
|
||||
|
||||
emit m_cllm->generatedNameChanged(words.join(u' '));
|
||||
return words.size() < MAX_WORDS || stream.atEnd();
|
||||
}
|
||||
};
|
||||
|
||||
void ChatLLM::generateName()
|
||||
{
|
||||
Q_ASSERT(isModelLoaded());
|
||||
@ -1105,23 +1248,15 @@ void ChatLLM::generateName()
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray response; // raw UTF-8
|
||||
|
||||
auto handleResponse = [this, &response](LLModel::Token token, std::string_view piece) -> bool {
|
||||
Q_UNUSED(token)
|
||||
|
||||
response.append(piece.data(), piece.size());
|
||||
QStringList words = QString::fromUtf8(response).simplified().split(u' ', Qt::SkipEmptyParts);
|
||||
emit generatedNameChanged(words.join(u' '));
|
||||
return words.size() <= 3;
|
||||
};
|
||||
NameResponseHandler respHandler(this);
|
||||
|
||||
try {
|
||||
m_llModelInfo.model->prompt(
|
||||
applyJinjaTemplate(forkConversation(chatNamePrompt)),
|
||||
[this](auto &&...) { return !m_stopGenerating; },
|
||||
handleResponse,
|
||||
promptContextFromSettings(m_modelInfo)
|
||||
promptModelWithTools(
|
||||
m_llModelInfo.model.get(),
|
||||
/*promptCallback*/ [this](auto &&...) { return !m_stopGenerating; },
|
||||
respHandler, promptContextFromSettings(m_modelInfo),
|
||||
applyJinjaTemplate(forkConversation(chatNamePrompt)).c_str(),
|
||||
{ ToolCallConstants::ThinkTagName }
|
||||
);
|
||||
} catch (const std::exception &e) {
|
||||
qWarning() << "ChatLLM failed to generate name:" << e.what();
|
||||
@ -1133,13 +1268,43 @@ void ChatLLM::handleChatIdChanged(const QString &id)
|
||||
m_llmThread.setObjectName(id);
|
||||
}
|
||||
|
||||
void ChatLLM::generateQuestions(qint64 elapsed)
|
||||
class QuestionResponseHandler : public SimpleResponseHandler {
|
||||
public:
|
||||
using SimpleResponseHandler::SimpleResponseHandler;
|
||||
|
||||
protected:
|
||||
bool onSimpleResponse(const QString &response) override
|
||||
{
|
||||
auto responseUtf8Bytes = response.toUtf8().slice(m_offset);
|
||||
auto responseUtf8 = std::string(responseUtf8Bytes.begin(), responseUtf8Bytes.end());
|
||||
// extract all questions from response
|
||||
ptrdiff_t lastMatchEnd = -1;
|
||||
auto it = std::sregex_iterator(responseUtf8.begin(), responseUtf8.end(), s_reQuestion);
|
||||
auto end = std::sregex_iterator();
|
||||
for (; it != end; ++it) {
|
||||
auto pos = it->position();
|
||||
auto len = it->length();
|
||||
lastMatchEnd = pos + len;
|
||||
emit m_cllm->generatedQuestionFinished(QString::fromUtf8(&responseUtf8[pos], len));
|
||||
}
|
||||
|
||||
// remove processed input from buffer
|
||||
if (lastMatchEnd != -1)
|
||||
m_offset += lastMatchEnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// FIXME: This only works with response by the model in english which is not ideal for a multi-language
|
||||
// model.
|
||||
// match whole question sentences
|
||||
static const std::regex reQuestion(R"(\b(?:What|Where|How|Why|When|Who|Which|Whose|Whom)\b[^?]*\?)");
|
||||
static inline const std::regex s_reQuestion { R"(\b(?:What|Where|How|Why|When|Who|Which|Whose|Whom)\b[^?]*\?)" };
|
||||
|
||||
qsizetype m_offset = 0;
|
||||
};
|
||||
|
||||
void ChatLLM::generateQuestions(qint64 elapsed)
|
||||
{
|
||||
Q_ASSERT(isModelLoaded());
|
||||
if (!isModelLoaded()) {
|
||||
emit responseStopped(elapsed);
|
||||
@ -1157,39 +1322,17 @@ void ChatLLM::generateQuestions(qint64 elapsed)
|
||||
|
||||
emit generatingQuestions();
|
||||
|
||||
std::string response; // raw UTF-8
|
||||
|
||||
auto handleResponse = [this, &response](LLModel::Token token, std::string_view piece) -> bool {
|
||||
Q_UNUSED(token)
|
||||
|
||||
// add token to buffer
|
||||
response.append(piece);
|
||||
|
||||
// extract all questions from response
|
||||
ptrdiff_t lastMatchEnd = -1;
|
||||
auto it = std::sregex_iterator(response.begin(), response.end(), reQuestion);
|
||||
auto end = std::sregex_iterator();
|
||||
for (; it != end; ++it) {
|
||||
auto pos = it->position();
|
||||
auto len = it->length();
|
||||
lastMatchEnd = pos + len;
|
||||
emit generatedQuestionFinished(QString::fromUtf8(&response[pos], len));
|
||||
}
|
||||
|
||||
// remove processed input from buffer
|
||||
if (lastMatchEnd != -1)
|
||||
response.erase(0, lastMatchEnd);
|
||||
return true;
|
||||
};
|
||||
QuestionResponseHandler respHandler(this);
|
||||
|
||||
QElapsedTimer totalTime;
|
||||
totalTime.start();
|
||||
try {
|
||||
m_llModelInfo.model->prompt(
|
||||
applyJinjaTemplate(forkConversation(suggestedFollowUpPrompt)),
|
||||
[this](auto &&...) { return !m_stopGenerating; },
|
||||
handleResponse,
|
||||
promptContextFromSettings(m_modelInfo)
|
||||
promptModelWithTools(
|
||||
m_llModelInfo.model.get(),
|
||||
/*promptCallback*/ [this](auto &&...) { return !m_stopGenerating; },
|
||||
respHandler, promptContextFromSettings(m_modelInfo),
|
||||
applyJinjaTemplate(forkConversation(suggestedFollowUpPrompt)).c_str(),
|
||||
{ ToolCallConstants::ThinkTagName }
|
||||
);
|
||||
} catch (const std::exception &e) {
|
||||
qWarning() << "ChatLLM failed to generate follow-up questions:" << e.what();
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define CHATLLM_H
|
||||
|
||||
#include "chatmodel.h"
|
||||
#include "database.h" // IWYU pragma: keep
|
||||
#include "database.h"
|
||||
#include "modellist.h"
|
||||
|
||||
#include <gpt4all-backend/llmodel.h>
|
||||
@ -10,28 +10,30 @@
|
||||
#include <QByteArray>
|
||||
#include <QElapsedTimer>
|
||||
#include <QFileInfo>
|
||||
#include <QList> // IWYU pragma: keep
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QString>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QStringView>
|
||||
#include <QThread>
|
||||
#include <QVariantMap> // IWYU pragma: keep
|
||||
#include <QtGlobal>
|
||||
#include <QtNumeric>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
class ChatLLM;
|
||||
class QDataStream;
|
||||
|
||||
|
||||
// NOTE: values serialized to disk, do not change or reuse
|
||||
enum class LLModelTypeV0 { // chat versions 2-5
|
||||
MPT = 0,
|
||||
@ -88,9 +90,6 @@ inline LLModelTypeV1 parseLLModelTypeV0(int v0)
|
||||
}
|
||||
}
|
||||
|
||||
class ChatLLM;
|
||||
class ChatModel;
|
||||
|
||||
struct LLModelInfo {
|
||||
std::unique_ptr<LLModel> model;
|
||||
QFileInfo fileInfo;
|
||||
@ -285,6 +284,8 @@ private:
|
||||
bool m_isServer;
|
||||
bool m_forceMetal;
|
||||
bool m_reloadingToChangeVariant;
|
||||
friend class ChatViewResponseHandler;
|
||||
friend class SimpleResponseHandler;
|
||||
};
|
||||
|
||||
#endif // CHATLLM_H
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
#include <QtGlobal>
|
||||
#include <QTextStream>
|
||||
#include <QtLogging>
|
||||
|
||||
#include <exception>
|
||||
|
||||
|
||||
QList<ResultInfo> ChatItem::consolidateSources(const QList<ResultInfo> &sources)
|
||||
{
|
||||
|
@ -4,32 +4,41 @@
|
||||
#include "database.h"
|
||||
#include "tool.h"
|
||||
#include "toolcallparser.h"
|
||||
#include "utils.h"
|
||||
#include "utils.h" // IWYU pragma: keep
|
||||
#include "xlsxtomd.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QAbstractListModel>
|
||||
#include <QBuffer>
|
||||
#include <QByteArray>
|
||||
#include <QClipboard>
|
||||
#include <QDataStream>
|
||||
#include <QJsonDocument>
|
||||
#include <QFileInfo>
|
||||
#include <QGuiApplication>
|
||||
#include <QIODevice>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker> // IWYU pragma: keep
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QPair> // IWYU pragma: keep
|
||||
#include <QString>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <Qt>
|
||||
#include <QtGlobal>
|
||||
#include <QtAssert>
|
||||
#include <QtPreprocessorSupport>
|
||||
#include <QtTypes>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -94,11 +103,28 @@ class MessageItem
|
||||
public:
|
||||
enum class Type { System, Prompt, Response, ToolResponse };
|
||||
|
||||
MessageItem(Type type, QString content)
|
||||
: m_type(type), m_content(std::move(content)) {}
|
||||
struct system_tag_t { explicit system_tag_t() = default; };
|
||||
static inline constexpr system_tag_t system_tag = system_tag_t{};
|
||||
|
||||
MessageItem(Type type, QString content, const QList<ResultInfo> &sources, const QList<PromptAttachment> &promptAttachments)
|
||||
: m_type(type), m_content(std::move(content)), m_sources(sources), m_promptAttachments(promptAttachments) {}
|
||||
MessageItem(qsizetype index, Type type, QString content)
|
||||
: m_index(index), m_type(type), m_content(std::move(content))
|
||||
{
|
||||
Q_ASSERT(type != Type::System); // use system_tag constructor
|
||||
}
|
||||
|
||||
// Construct a system message with no index, since they are never stored in the chat
|
||||
MessageItem(system_tag_t, QString content)
|
||||
: m_type(Type::System), m_content(std::move(content)) {}
|
||||
|
||||
MessageItem(qsizetype index, Type type, QString content, const QList<ResultInfo> &sources, const QList<PromptAttachment> &promptAttachments)
|
||||
: m_index(index)
|
||||
, m_type(type)
|
||||
, m_content(std::move(content))
|
||||
, m_sources(sources)
|
||||
, m_promptAttachments(promptAttachments) {}
|
||||
|
||||
// index of the parent ChatItem (system, prompt, response) in its container
|
||||
std::optional<qsizetype> index() const { return m_index; }
|
||||
|
||||
Type type() const { return m_type; }
|
||||
const QString &content() const { return m_content; }
|
||||
@ -126,6 +152,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<qsizetype> m_index;
|
||||
Type m_type;
|
||||
QString m_content;
|
||||
QList<ResultInfo> m_sources;
|
||||
@ -186,7 +213,8 @@ public:
|
||||
: QObject(nullptr)
|
||||
{
|
||||
moveToThread(parent->thread());
|
||||
setParent(parent);
|
||||
// setParent must be called from the thread the object lives in
|
||||
QMetaObject::invokeMethod(this, [this, parent]() { this->setParent(parent); });
|
||||
}
|
||||
|
||||
// NOTE: System messages are currently never serialized and only *stored* by the local server.
|
||||
@ -399,7 +427,7 @@ public:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
MessageItem asMessageItem() const
|
||||
MessageItem asMessageItem(qsizetype index) const
|
||||
{
|
||||
MessageItem::Type msgType;
|
||||
switch (auto typ = type()) {
|
||||
@ -413,7 +441,7 @@ public:
|
||||
case Think:
|
||||
throw std::invalid_argument(fmt::format("cannot convert ChatItem type {} to message item", int(typ)));
|
||||
}
|
||||
return { msgType, flattenedContent(), sources, promptAttachments };
|
||||
return { index, msgType, flattenedContent(), sources, promptAttachments };
|
||||
}
|
||||
|
||||
static QList<ResultInfo> consolidateSources(const QList<ResultInfo> &sources);
|
||||
@ -537,6 +565,7 @@ private:
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// FIXME(jared): this should really be done at the parent level, not the sub-item level
|
||||
static std::optional<qsizetype> getPeerInternal(const MessageItem *arr, qsizetype size, qsizetype index)
|
||||
{
|
||||
qsizetype peer;
|
||||
@ -1114,10 +1143,12 @@ public:
|
||||
// A flattened version of the chat item tree used by the backend and jinja
|
||||
QMutexLocker locker(&m_mutex);
|
||||
std::vector<MessageItem> chatItems;
|
||||
for (const ChatItem *item : m_chatItems) {
|
||||
chatItems.reserve(chatItems.size() + item->subItems.size() + 1);
|
||||
ranges::copy(item->subItems | views::transform(&ChatItem::asMessageItem), std::back_inserter(chatItems));
|
||||
chatItems.push_back(item->asMessageItem());
|
||||
for (qsizetype i : views::iota(0, m_chatItems.size())) {
|
||||
auto *parent = m_chatItems.at(i);
|
||||
chatItems.reserve(chatItems.size() + parent->subItems.size() + 1);
|
||||
ranges::copy(parent->subItems | views::transform([&](auto *s) { return s->asMessageItem(i); }),
|
||||
std::back_inserter(chatItems));
|
||||
chatItems.push_back(parent->asMessageItem(i));
|
||||
}
|
||||
return chatItems;
|
||||
}
|
||||
|
@ -1,29 +1,32 @@
|
||||
#include "chatviewtextprocessor.h"
|
||||
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QBrush>
|
||||
#include <QChar>
|
||||
#include <QClipboard>
|
||||
#include <QDebug>
|
||||
#include <QFlag>
|
||||
#include <QFont>
|
||||
#include <QFontMetricsF>
|
||||
#include <QGuiApplication>
|
||||
#include <QList>
|
||||
#include <QPainter>
|
||||
#include <QList> // IWYU pragma: keep
|
||||
#include <QPair>
|
||||
#include <QQuickTextDocument>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringList>
|
||||
#include <QTextBlock>
|
||||
#include <QTextCharFormat>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QTextBlock> // IWYU pragma: keep
|
||||
#include <QTextCharFormat> // IWYU pragma: keep
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocument>
|
||||
#include <QTextDocumentFragment>
|
||||
#include <QTextFrame>
|
||||
#include <QTextFrameFormat>
|
||||
#include <QTextFrame> // IWYU pragma: keep
|
||||
#include <QTextFrameFormat> // IWYU pragma: keep
|
||||
#include <QTextTableCell>
|
||||
#include <QVariant>
|
||||
#include <Qt>
|
||||
#include <QtGlobal>
|
||||
#include <QtAssert>
|
||||
#include <QtLogging>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
|
||||
enum Language {
|
||||
None,
|
||||
|
@ -3,18 +3,15 @@
|
||||
|
||||
#include <QColor>
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickTextDocument> // IWYU pragma: keep
|
||||
#include <QRectF>
|
||||
#include <QSizeF>
|
||||
#include <QQmlEngine> // IWYU pragma: keep
|
||||
#include <QQuickTextDocument>
|
||||
#include <QString>
|
||||
#include <QSyntaxHighlighter>
|
||||
#include <QTextObjectInterface>
|
||||
#include <QVector>
|
||||
#include <QVector> // IWYU pragma: keep
|
||||
#include <QtTypes>
|
||||
|
||||
// IWYU pragma: no_forward_declare QQuickTextDocument
|
||||
|
||||
class QPainter;
|
||||
class QTextDocument;
|
||||
class QTextFormat;
|
||||
|
||||
struct CodeColors {
|
||||
Q_GADGET
|
||||
|
@ -1,12 +1,16 @@
|
||||
#include "codeinterpreter.h"
|
||||
|
||||
#include <QJSEngine>
|
||||
#include <QJSValue>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
#include <Qt>
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
|
||||
CodeInterpreter::CodeInterpreter()
|
||||
: Tool()
|
||||
, m_error(ToolEnums::Error::NoError)
|
||||
|
@ -4,11 +4,13 @@
|
||||
#include "tool.h"
|
||||
#include "toolcallparser.h"
|
||||
|
||||
#include <QJSEngine>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QtGlobal>
|
||||
#include <QThread>
|
||||
#include <QtAssert>
|
||||
|
||||
class QJSEngine;
|
||||
|
||||
|
||||
class JavaScriptConsoleCapture : public QObject
|
||||
{
|
||||
|
7
gpt4all-chat/src/config.h.in
Normal file
7
gpt4all-chat/src/config.h.in
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define APP_VERSION "@APP_VERSION@"
|
||||
|
||||
#define G4A_CONFIG(name) (1/G4A_CONFIG_##name == 1)
|
||||
|
||||
#define G4A_CONFIG_force_d3d12 @GPT4ALL_CONFIG_FORCE_D3D12@
|
@ -1,19 +1,21 @@
|
||||
#include "database.h"
|
||||
|
||||
#include "mysettings.h"
|
||||
#include "utils.h"
|
||||
#include "utils.h" // IWYU pragma: keep
|
||||
|
||||
#include <duckx/duckx.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <usearch/index.hpp>
|
||||
#include <usearch/index_plugins.hpp>
|
||||
|
||||
#include <QByteArrayView>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QFlags>
|
||||
#include <QIODevice>
|
||||
#include <QKeyValueIterator>
|
||||
#include <QRegularExpression>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
@ -22,8 +24,9 @@
|
||||
#include <QMap>
|
||||
#include <QUtf8StringView>
|
||||
#include <QVariant>
|
||||
#include <Qt>
|
||||
#include <QtLogging>
|
||||
#include <QtMinMax>
|
||||
#include <QtTypes>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@ -46,6 +49,7 @@ namespace us = unum::usearch;
|
||||
//#define DEBUG
|
||||
//#define DEBUG_EXAMPLE
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/* QFile that checks input for binary data. If seen, it fails the read and returns true
|
||||
@ -1111,9 +1115,9 @@ class DocumentReader {
|
||||
public:
|
||||
struct Metadata { QString title, author, subject, keywords; };
|
||||
|
||||
static std::unique_ptr<DocumentReader> fromDocument(const DocumentInfo &info);
|
||||
static std::unique_ptr<DocumentReader> fromDocument(DocumentInfo info);
|
||||
|
||||
const DocumentInfo &doc () const { return *m_info; }
|
||||
const DocumentInfo &doc () const { return m_info; }
|
||||
const Metadata &metadata() const { return m_metadata; }
|
||||
const std::optional<QString> &word () const { return m_word; }
|
||||
const std::optional<QString> &nextWord() { m_word = advance(); return m_word; }
|
||||
@ -1123,8 +1127,8 @@ public:
|
||||
virtual ~DocumentReader() = default;
|
||||
|
||||
protected:
|
||||
explicit DocumentReader(const DocumentInfo &info)
|
||||
: m_info(&info) {}
|
||||
explicit DocumentReader(DocumentInfo info)
|
||||
: m_info(std::move(info)) {}
|
||||
|
||||
void postInit(Metadata &&metadata = {})
|
||||
{
|
||||
@ -1134,7 +1138,7 @@ protected:
|
||||
|
||||
virtual std::optional<QString> advance() = 0;
|
||||
|
||||
const DocumentInfo *m_info;
|
||||
DocumentInfo m_info;
|
||||
Metadata m_metadata;
|
||||
std::optional<QString> m_word;
|
||||
};
|
||||
@ -1144,8 +1148,8 @@ namespace {
|
||||
#ifdef GPT4ALL_USE_QTPDF
|
||||
class PdfDocumentReader final : public DocumentReader {
|
||||
public:
|
||||
explicit PdfDocumentReader(const DocumentInfo &info)
|
||||
: DocumentReader(info)
|
||||
explicit PdfDocumentReader(DocumentInfo info)
|
||||
: DocumentReader(std::move(info))
|
||||
{
|
||||
QString path = info.file.canonicalFilePath();
|
||||
if (m_doc.load(path) != QPdfDocument::Error::None)
|
||||
@ -1185,8 +1189,8 @@ private:
|
||||
#else
|
||||
class PdfDocumentReader final : public DocumentReader {
|
||||
public:
|
||||
explicit PdfDocumentReader(const DocumentInfo &info)
|
||||
: DocumentReader(info)
|
||||
explicit PdfDocumentReader(DocumentInfo info)
|
||||
: DocumentReader(std::move(info))
|
||||
{
|
||||
QString path = info.file.canonicalFilePath();
|
||||
m_doc = FPDF_LoadDocument(path.toUtf8().constData(), nullptr);
|
||||
@ -1209,7 +1213,6 @@ public:
|
||||
FPDF_ClosePage(m_page);
|
||||
if (m_doc)
|
||||
FPDF_CloseDocument(m_doc);
|
||||
FPDF_DestroyLibrary();
|
||||
}
|
||||
|
||||
int page() const override { return m_currentPage; }
|
||||
@ -1224,7 +1227,7 @@ private:
|
||||
return std::nullopt;
|
||||
|
||||
if (m_page)
|
||||
FPDF_ClosePage(m_page);
|
||||
FPDF_ClosePage(std::exchange(m_page, nullptr));
|
||||
m_page = FPDF_LoadPage(m_doc, m_currentPage++);
|
||||
if (!m_page)
|
||||
throw std::runtime_error("Failed to load page.");
|
||||
@ -1278,8 +1281,8 @@ private:
|
||||
|
||||
class WordDocumentReader final : public DocumentReader {
|
||||
public:
|
||||
explicit WordDocumentReader(const DocumentInfo &info)
|
||||
: DocumentReader(info)
|
||||
explicit WordDocumentReader(DocumentInfo info)
|
||||
: DocumentReader(std::move(info))
|
||||
, m_doc(info.file.canonicalFilePath().toStdString())
|
||||
{
|
||||
m_doc.open();
|
||||
@ -1371,8 +1374,8 @@ protected:
|
||||
|
||||
class TxtDocumentReader final : public DocumentReader {
|
||||
public:
|
||||
explicit TxtDocumentReader(const DocumentInfo &info)
|
||||
: DocumentReader(info)
|
||||
explicit TxtDocumentReader(DocumentInfo info)
|
||||
: DocumentReader(std::move(info))
|
||||
, m_file(info.file.canonicalFilePath())
|
||||
{
|
||||
if (!m_file.open(QIODevice::ReadOnly))
|
||||
@ -1413,13 +1416,13 @@ protected:
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<DocumentReader> DocumentReader::fromDocument(const DocumentInfo &doc)
|
||||
std::unique_ptr<DocumentReader> DocumentReader::fromDocument(DocumentInfo doc)
|
||||
{
|
||||
if (doc.isPdf())
|
||||
return std::make_unique<PdfDocumentReader>(doc);
|
||||
return std::make_unique<PdfDocumentReader>(std::move(doc));
|
||||
if (doc.isDocx())
|
||||
return std::make_unique<WordDocumentReader>(doc);
|
||||
return std::make_unique<TxtDocumentReader>(doc);
|
||||
return std::make_unique<WordDocumentReader>(std::move(doc));
|
||||
return std::make_unique<TxtDocumentReader>(std::move(doc));
|
||||
}
|
||||
|
||||
ChunkStreamer::ChunkStreamer(Database *database)
|
||||
@ -1427,12 +1430,12 @@ ChunkStreamer::ChunkStreamer(Database *database)
|
||||
|
||||
ChunkStreamer::~ChunkStreamer() = default;
|
||||
|
||||
void ChunkStreamer::setDocument(const DocumentInfo &doc, int documentId, const QString &embeddingModel)
|
||||
void ChunkStreamer::setDocument(DocumentInfo doc, int documentId, const QString &embeddingModel)
|
||||
{
|
||||
auto docKey = doc.key();
|
||||
if (!m_docKey || *m_docKey != docKey) {
|
||||
m_docKey = docKey;
|
||||
m_reader = DocumentReader::fromDocument(doc);
|
||||
m_reader = DocumentReader::fromDocument(std::move(doc));
|
||||
m_documentId = documentId;
|
||||
m_embeddingModel = embeddingModel;
|
||||
m_chunk.clear();
|
||||
@ -1442,7 +1445,8 @@ void ChunkStreamer::setDocument(const DocumentInfo &doc, int documentId, const Q
|
||||
if (m_database->m_documentIdCache.contains(documentId)) {
|
||||
QSqlQuery q(m_database->m_db);
|
||||
if (!m_database->removeChunksByDocumentId(q, documentId))
|
||||
handleDocumentError("ERROR: Cannot remove chunks of document", documentId, doc.file.canonicalPath(), q.lastError());
|
||||
handleDocumentError("ERROR: Cannot remove chunks of document",
|
||||
documentId, m_reader->doc().file.canonicalPath(), q.lastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef DATABASE_H
|
||||
#define DATABASE_H
|
||||
|
||||
#include "embllm.h" // IWYU pragma: keep
|
||||
#include "embllm.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QChar>
|
||||
@ -15,11 +15,11 @@
|
||||
#include <QSet>
|
||||
#include <QSqlDatabase>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
#include <QVector>
|
||||
#include <QtGlobal>
|
||||
#include <QVector> // IWYU pragma: keep
|
||||
#include <QtAssert>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
@ -28,7 +28,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <vector> // IWYU pragma: keep
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
@ -39,6 +39,7 @@ class QSqlQuery;
|
||||
class QTextStream;
|
||||
class QTimer;
|
||||
|
||||
|
||||
/* Version 0: GPT4All v2.4.3, full-text search
|
||||
* Version 1: GPT4All v2.5.3, embeddings in hsnwlib
|
||||
* Version 2: GPT4All v3.0.0, embeddings in sqlite
|
||||
@ -171,7 +172,7 @@ public:
|
||||
explicit ChunkStreamer(Database *database);
|
||||
~ChunkStreamer();
|
||||
|
||||
void setDocument(const DocumentInfo &doc, int documentId, const QString &embeddingModel);
|
||||
void setDocument(DocumentInfo doc, int documentId, const QString &embeddingModel);
|
||||
std::optional<DocumentInfo::key_type> currentDocKey() const;
|
||||
void reset();
|
||||
|
||||
|
@ -10,32 +10,37 @@
|
||||
#include <QDebug>
|
||||
#include <QGlobalStatic>
|
||||
#include <QGuiApplication>
|
||||
#include <QIODevice>
|
||||
#include <QIODevice> // IWYU pragma: keep
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QKeyValueIterator>
|
||||
#include <QLocale>
|
||||
#include <QNetworkRequest>
|
||||
#include <QPair>
|
||||
#include <QPair> // IWYU pragma: keep
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include <QSettings>
|
||||
#include <QSslConfiguration>
|
||||
#include <QSslSocket>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QTextStream>
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <QVector> // IWYU pragma: keep
|
||||
#include <Qt>
|
||||
#include <QtAssert>
|
||||
#include <QtLogging>
|
||||
#include <QtMinMax>
|
||||
|
||||
#include <algorithm>
|
||||
#include <compare>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
|
||||
class MyDownload: public Download { };
|
||||
Q_GLOBAL_STATIC(MyDownload, downloadInstance)
|
||||
Download *Download::globalInstance()
|
||||
|
@ -13,10 +13,14 @@
|
||||
#include <QSslError>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QtGlobal>
|
||||
#include <QtTypes>
|
||||
|
||||
// IWYU pragma: no_forward_declare QFile
|
||||
// IWYU pragma: no_forward_declare QList
|
||||
// IWYU pragma: no_forward_declare QSslError
|
||||
class QByteArray;
|
||||
|
||||
|
||||
struct ReleaseInfo {
|
||||
Q_GADGET
|
||||
Q_PROPERTY(QString version MEMBER version)
|
||||
|
@ -1,35 +1,35 @@
|
||||
#include "embllm.h"
|
||||
|
||||
#include "modellist.h"
|
||||
#include "mysettings.h"
|
||||
|
||||
#include <gpt4all-backend/llmodel.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QGuiApplication>
|
||||
#include <QIODevice>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QList>
|
||||
#include <QMutexLocker>
|
||||
#include <QMutexLocker> // IWYU pragma: keep
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QUrl>
|
||||
#include <Qt>
|
||||
#include <QtGlobal>
|
||||
#include <QtAssert>
|
||||
#include <QtLogging>
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
|
||||
static const QString EMBEDDING_MODEL_NAME = u"nomic-embed-text-v1.5"_s;
|
||||
static const QString LOCAL_EMBEDDING_MODEL = u"nomic-embed-text-v1.5.f16.gguf"_s;
|
||||
|
||||
@ -359,8 +359,11 @@ void EmbeddingLLMWorker::handleFinished()
|
||||
if (retrievedData.isValid() && retrievedData.canConvert<QVector<EmbeddingChunk>>())
|
||||
chunks = retrievedData.value<QVector<EmbeddingChunk>>();
|
||||
|
||||
QVariant response = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
QVariant response;
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
response = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
Q_ASSERT(response.isValid());
|
||||
}
|
||||
bool ok;
|
||||
int code = response.toInt(&ok);
|
||||
if (!ok || code != 200) {
|
||||
|
@ -5,10 +5,10 @@
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <QVector> // IWYU pragma: keep
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
@ -16,6 +16,7 @@
|
||||
class LLModel;
|
||||
class QNetworkAccessManager;
|
||||
|
||||
|
||||
struct EmbeddingChunk {
|
||||
QString model; // TODO(jared): use to select model
|
||||
int folder_id;
|
||||
|
@ -1,16 +1,11 @@
|
||||
#include "jinja_helpers.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace views = std::views;
|
||||
using json = nlohmann::ordered_json;
|
||||
|
@ -5,7 +5,11 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QtTypes> // IWYU pragma: keep
|
||||
|
||||
// IWYU pragma: no_forward_declare MessageItem
|
||||
// IWYU pragma: no_forward_declare PromptAttachment
|
||||
// IWYU pragma: no_forward_declare ResultInfo
|
||||
|
||||
using json = nlohmann::ordered_json;
|
||||
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include "jinja_replacements.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
// This is a list of prompt templates known to GPT4All and their associated replacements which are automatically used
|
||||
// instead when loading the chat template from GGUF. These exist for two primary reasons:
|
||||
// - HuggingFace model authors make ugly chat templates because they do not expect the end user to see them;
|
||||
@ -118,6 +121,26 @@ const std::unordered_map<std::string_view, std::string_view> CHAT_TEMPLATE_SUBST
|
||||
{%- if loop.last and add_generation_prompt %}
|
||||
{{- '<|assistant|>' }}
|
||||
{%- endif %}
|
||||
{%- endfor %})TEMPLATE",
|
||||
},
|
||||
// granite-3.1-3b-a800m-instruct-Q4_0.gguf, granite-3.1-8b-instruct-Q4_0.gguf (nomic-ai/gpt4all#3471)
|
||||
{
|
||||
// original
|
||||
R"TEMPLATE({%- if messages[0]['role'] == 'system' %}{%- set system_message = messages[0]['content'] %}{%- set loop_messages = messages[1:] %}{%- else %}{%- set system_message = "Knowledge Cutoff Date: April 2024. You are Granite, developed by IBM." %}{%- if tools and documents %}{%- set system_message = system_message + " You are a helpful AI assistant with access to the following tools. When a tool is required to answer the user's query, respond with <|tool_call|> followed by a JSON list of tools used. If a tool does not exist in the provided list of tools, notify the user that you do not have the ability to fulfill the request. Write the response to the user's input by strictly aligning with the facts in the provided documents. If the information needed to answer the question is not available in the documents, inform the user that the question cannot be answered based on the available data." %}{%- elif tools %}{%- set system_message = system_message + " You are a helpful AI assistant with access to the following tools. When a tool is required to answer the user's query, respond with <|tool_call|> followed by a JSON list of tools used. If a tool does not exist in the provided list of tools, notify the user that you do not have the ability to fulfill the request." %}{%- elif documents %}{%- set system_message = system_message + " Write the response to the user's input by strictly aligning with the facts in the provided documents. If the information needed to answer the question is not available in the documents, inform the user that the question cannot be answered based on the available data." %}{%- else %}{%- set system_message = system_message + " You are a helpful AI assistant." %}{%- endif %}{%- if controls and 'citations' in controls and documents %}{%- set system_message = system_message + ' In your response, use the symbols <co> and </co> to indicate when a fact comes from a document in the search result, e.g <co>0</co> for a fact from document 0. Afterwards, list all the citations with their corresponding documents in an ordered list.' %}{%- endif %}{%- if controls and 'hallucinations' in controls and documents %}{%- set system_message = system_message + ' Finally, after the response is written, include a numbered list of sentences from the response that are potentially hallucinated and not based in the documents.' %}{%- endif %}{%- set loop_messages = messages %}{%- endif %}{{- '<|start_of_role|>system<|end_of_role|>' + system_message + '<|end_of_text|> ' }}{%- if tools %}{{- '<|start_of_role|>tools<|end_of_role|>' }}{{- tools | tojson(indent=4) }}{{- '<|end_of_text|> ' }}{%- endif %}{%- if documents %}{{- '<|start_of_role|>documents<|end_of_role|>' }}{%- for document in documents %}{{- 'Document ' + loop.index0 | string + ' ' }}{{- document['text'] }}{%- if not loop.last %}{{- ' '}}{%- endif%}{%- endfor %}{{- '<|end_of_text|> ' }}{%- endif %}{%- for message in loop_messages %}{{- '<|start_of_role|>' + message['role'] + '<|end_of_role|>' + message['content'] + '<|end_of_text|> ' }}{%- if loop.last and add_generation_prompt %}{{- '<|start_of_role|>assistant' }}{%- if controls %}{{- ' ' + controls | tojson()}}{%- endif %}{{- '<|end_of_role|>' }}{%- endif %}{%- endfor %})TEMPLATE",
|
||||
// replacement
|
||||
R"TEMPLATE({%- if messages[0]['role'] == 'system' %}
|
||||
{%- set system_message = messages[0]['content'] %}
|
||||
{%- set loop_messages = messages[1:] %}
|
||||
{%- else %}
|
||||
{%- set system_message = "Knowledge Cutoff Date: April 2024. You are Granite, developed by IBM. You are a helpful AI assistant." %}
|
||||
{%- set loop_messages = messages %}
|
||||
{%- endif %}
|
||||
{{- '<|start_of_role|>system<|end_of_role|>' + system_message + '<|end_of_text|> ' }}
|
||||
{%- for message in loop_messages %}
|
||||
{{- '<|start_of_role|>' + message['role'] + '<|end_of_role|>' + message['content'] + '<|end_of_text|> ' }}
|
||||
{%- if loop.last and add_generation_prompt %}
|
||||
{{- '<|start_of_role|>assistant<|end_of_role|>' }}
|
||||
{%- endif %}
|
||||
{%- endfor %})TEMPLATE",
|
||||
},
|
||||
// Hermes-3-Llama-3.2-3B.Q4_0.gguf, mistral-7b-openorca.gguf2.Q4_0.gguf
|
||||
@ -618,6 +641,70 @@ const std::unordered_map<std::string_view, std::string_view> CHAT_TEMPLATE_SUBST
|
||||
{%- if add_generation_prompt %}
|
||||
{{- '<|im_start|>assistant\n' }}
|
||||
{%- endif %})TEMPLATE",
|
||||
},
|
||||
// OLMoE-1B-7B-0125-Instruct-Q4_0.gguf (nomic-ai/gpt4all#3471)
|
||||
{
|
||||
// original
|
||||
R"TEMPLATE({{ bos_token }}{% for message in messages %}{% if message['role'] == 'system' %}{{ '<|system|>
|
||||
' + message['content'] + '
|
||||
' }}{% elif message['role'] == 'user' %}{{ '<|user|>
|
||||
' + message['content'] + '
|
||||
' }}{% elif message['role'] == 'assistant' %}{% if not loop.last %}{{ '<|assistant|>
|
||||
' + message['content'] + eos_token + '
|
||||
' }}{% else %}{{ '<|assistant|>
|
||||
' + message['content'] + eos_token }}{% endif %}{% endif %}{% if loop.last and add_generation_prompt %}{{ '<|assistant|>
|
||||
' }}{% endif %}{% endfor %})TEMPLATE",
|
||||
// replacement
|
||||
R"TEMPLATE({{- bos_token }}
|
||||
{%- for message in messages %}
|
||||
{%- if message['role'] == 'system' %}
|
||||
{{- '<|system|>\n' + message['content'] + '\n' }}
|
||||
{%- elif message['role'] == 'user' %}
|
||||
{{- '<|user|>\n' + message['content'] + '\n' }}
|
||||
{%- elif message['role'] == 'assistant' %}
|
||||
{%- if not loop.last %}
|
||||
{{- '<|assistant|>\n' + message['content'] + eos_token + '\n' }}
|
||||
{%- else %}
|
||||
{{- '<|assistant|>\n' + message['content'] + eos_token }}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- if loop.last and add_generation_prompt %}
|
||||
{{- '<|assistant|>\n' }}
|
||||
{%- endif %}
|
||||
{%- endfor %})TEMPLATE",
|
||||
},
|
||||
// OLMoE-1B-7B-0924-Instruct-Q4_0.gguf (nomic-ai/gpt4all#3471)
|
||||
{
|
||||
// original
|
||||
R"TEMPLATE({{ bos_token }}{% for message in messages %}
|
||||
{% if message['role'] == 'system' %}
|
||||
{{ '<|system|>
|
||||
' + message['content'] }}
|
||||
{% elif message['role'] == 'user' %}
|
||||
{{ '<|user|>
|
||||
' + message['content'] }}
|
||||
{% elif message['role'] == 'assistant' %}
|
||||
{{ '<|assistant|>
|
||||
' + message['content'] + eos_token }}
|
||||
{% endif %}
|
||||
{% if loop.last and add_generation_prompt %}
|
||||
{{ '<|assistant|>' }}
|
||||
{% endif %}
|
||||
{% endfor %})TEMPLATE",
|
||||
// replacement
|
||||
R"TEMPLATE({{- bos_token }}
|
||||
{%- for message in messages %}
|
||||
{%- if message['role'] == 'system' %}
|
||||
{{- '<|system|>\n' + message['content'] }}
|
||||
{%- elif message['role'] == 'user' %}
|
||||
{{- '<|user|>\n' + message['content'] }}
|
||||
{%- elif message['role'] == 'assistant' %}
|
||||
{{- '<|assistant|>\n' + message['content'] + eos_token }}
|
||||
{%- endif %}
|
||||
{%- if loop.last and add_generation_prompt %}
|
||||
{{- '<|assistant|>' }}
|
||||
{%- endif %}
|
||||
{%- endfor %})TEMPLATE",
|
||||
},
|
||||
// Phi-3.1-mini-128k-instruct-Q4_0.gguf (nomic-ai/gpt4all#3346)
|
||||
{
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include <QSettings>
|
||||
#include <QUrl>
|
||||
#include <QtLogging>
|
||||
#include <QtSystemDetection>
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef GPT4ALL_OFFLINE_INSTALLER
|
||||
# include <QDesktopServices>
|
||||
@ -25,6 +28,7 @@
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
|
||||
class MyLLM: public LLM { };
|
||||
Q_GLOBAL_STATIC(MyLLM, llmInstance)
|
||||
LLM *LLM::globalInstance()
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QtGlobal>
|
||||
#include <QtTypes>
|
||||
|
||||
|
||||
class LLM : public QObject
|
||||
{
|
||||
|
@ -5,10 +5,14 @@
|
||||
#include "mysettings.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QGlobalStatic>
|
||||
#include <QGuiApplication>
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
#include <Qt>
|
||||
#include <QtLogging>
|
||||
|
||||
|
||||
class MyLocalDocs: public LocalDocs { };
|
||||
Q_GLOBAL_STATIC(MyLocalDocs, localDocsInstance)
|
||||
|
@ -2,11 +2,14 @@
|
||||
#define LOCALDOCS_H
|
||||
|
||||
#include "database.h"
|
||||
#include "localdocsmodel.h" // IWYU pragma: keep
|
||||
#include "localdocsmodel.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
|
||||
// IWYU pragma: no_forward_declare LocalDocsModel
|
||||
|
||||
|
||||
class LocalDocs : public QObject
|
||||
{
|
||||
|
@ -5,11 +5,11 @@
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QMap>
|
||||
#include <QVector>
|
||||
#include <QtGlobal>
|
||||
#include <QVector> // IWYU pragma: keep
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
LocalDocsCollectionsModel::LocalDocsCollectionsModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
|
@ -4,17 +4,19 @@
|
||||
#include "database.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QObject> // IWYU pragma: keep
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <Qt>
|
||||
|
||||
#include <functional>
|
||||
|
||||
class QByteArray;
|
||||
class QVariant;
|
||||
template <typename Key, typename T> class QHash;
|
||||
|
||||
|
||||
class LocalDocsCollectionsModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -2,8 +2,10 @@
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QFlags>
|
||||
#include <QGlobalStatic>
|
||||
#include <QIODevice>
|
||||
#include <QMutexLocker> // IWYU pragma: keep
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <cstdio>
|
||||
@ -12,6 +14,7 @@
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
|
||||
class MyLogger: public Logger { };
|
||||
Q_GLOBAL_STATIC(MyLogger, loggerInstance)
|
||||
Logger *Logger::globalInstance()
|
||||
@ -62,8 +65,11 @@ void Logger::messageHandler(QtMsgType type, const QMessageLogContext &, const QS
|
||||
}
|
||||
// Get time and date
|
||||
auto timestamp = QDateTime::currentDateTime().toString();
|
||||
// Write message
|
||||
|
||||
const std::string out = u"[%1] (%2): %3\n"_s.arg(typeString, timestamp, msg).toStdString();
|
||||
|
||||
// Write message
|
||||
QMutexLocker locker(&logger->m_mutex);
|
||||
logger->m_file.write(out.c_str());
|
||||
logger->m_file.flush();
|
||||
std::cerr << out;
|
||||
|
@ -2,19 +2,24 @@
|
||||
#define LOGGER_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QMutex>
|
||||
#include <QString>
|
||||
#include <QtLogging>
|
||||
|
||||
class Logger
|
||||
{
|
||||
QFile m_file;
|
||||
|
||||
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
explicit Logger();
|
||||
|
||||
static Logger *globalInstance();
|
||||
|
||||
explicit Logger();
|
||||
private:
|
||||
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
|
||||
private:
|
||||
QFile m_file;
|
||||
QMutex m_mutex;
|
||||
|
||||
friend class MyLogger;
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
void MacOSDock::showIcon()
|
||||
{
|
||||
[[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
|
@ -12,18 +12,28 @@
|
||||
#include <gpt4all-backend/llmodel.h>
|
||||
#include <singleapplication.h>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QCoreApplication>
|
||||
#include <QFont>
|
||||
#include <QFontDatabase>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QQuickWindow>
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QWindow>
|
||||
#include <Qt>
|
||||
#include <QtAssert>
|
||||
#include <QtSystemDetection>
|
||||
|
||||
#if G4A_CONFIG(force_d3d12)
|
||||
# include <QSGRendererInterface>
|
||||
#endif
|
||||
|
||||
#ifndef GPT4ALL_USE_QTPDF
|
||||
# include <fpdfview.h>
|
||||
@ -83,6 +93,10 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if G4A_CONFIG(force_d3d12)
|
||||
QQuickWindow::setGraphicsApi(QSGRendererInterface::Direct3D12);
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
app.setWindowIcon(QIcon(":/gpt4all/icons/gpt4all.svg"));
|
||||
#endif
|
||||
@ -173,5 +187,9 @@ int main(int argc, char *argv[])
|
||||
// Otherwise, we can get a heap-use-after-free inside of llama.cpp.
|
||||
ChatListModel::globalInstance()->destroyChats();
|
||||
|
||||
#ifndef GPT4ALL_USE_QTPDF
|
||||
FPDF_DestroyLibrary();
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -9,9 +9,11 @@
|
||||
|
||||
#include <QChar>
|
||||
#include <QCoreApplication>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QEvent>
|
||||
#include <QEventLoop>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
@ -29,14 +31,15 @@
|
||||
#include <QSslConfiguration>
|
||||
#include <QSslSocket>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QTextStream>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QtAssert>
|
||||
#include <QtLogging>
|
||||
#include <QtPreprocessorSupport>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@ -499,10 +502,11 @@ bool GPT4AllDownloadableModels::filterAcceptsRow(int sourceRow,
|
||||
bool hasDescription = !description.isEmpty();
|
||||
bool isClone = sourceModel()->data(index, ModelList::IsCloneRole).toBool();
|
||||
bool isDiscovered = sourceModel()->data(index, ModelList::IsDiscoveredRole).toBool();
|
||||
bool isOnline = sourceModel()->data(index, ModelList::OnlineRole).toBool();
|
||||
bool satisfiesKeyword = m_keywords.isEmpty();
|
||||
for (const QString &k : m_keywords)
|
||||
satisfiesKeyword = description.contains(k) ? true : satisfiesKeyword;
|
||||
return !isDiscovered && hasDescription && !isClone && satisfiesKeyword;
|
||||
return !isOnline && !isDiscovered && hasDescription && !isClone && satisfiesKeyword;
|
||||
}
|
||||
|
||||
int GPT4AllDownloadableModels::count() const
|
||||
@ -2353,3 +2357,56 @@ void ModelList::handleDiscoveryItemErrorOccurred(QNetworkReply::NetworkError cod
|
||||
qWarning() << u"ERROR: Discovery item failed with error code \"%1-%2\""_s
|
||||
.arg(code).arg(reply->errorString()).toStdString();
|
||||
}
|
||||
|
||||
QStringList ModelList::remoteModelList(const QString &apiKey, const QUrl &baseUrl)
|
||||
{
|
||||
QStringList modelList;
|
||||
|
||||
// Create the request
|
||||
QNetworkRequest request;
|
||||
request.setUrl(baseUrl.resolved(QUrl("models")));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
// Add the Authorization header
|
||||
const QString bearerToken = QString("Bearer %1").arg(apiKey);
|
||||
request.setRawHeader("Authorization", bearerToken.toUtf8());
|
||||
|
||||
// Make the GET request
|
||||
QNetworkReply *reply = m_networkManager.get(request);
|
||||
|
||||
// We use a local event loop to wait for the request to complete
|
||||
QEventLoop loop;
|
||||
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
// Check for errors
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
// Parse the JSON response
|
||||
const QByteArray responseData = reply->readAll();
|
||||
const QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData);
|
||||
|
||||
if (!jsonDoc.isNull() && jsonDoc.isObject()) {
|
||||
QJsonObject rootObj = jsonDoc.object();
|
||||
QJsonValue dataValue = rootObj.value("data");
|
||||
|
||||
if (dataValue.isArray()) {
|
||||
QJsonArray dataArray = dataValue.toArray();
|
||||
for (const QJsonValue &val : dataArray) {
|
||||
if (val.isObject()) {
|
||||
QJsonObject obj = val.toObject();
|
||||
const QString modelId = obj.value("id").toString();
|
||||
modelList.append(modelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Handle network error (e.g. print it to qDebug)
|
||||
qWarning() << "Error retrieving models:" << reply->errorString();
|
||||
}
|
||||
|
||||
// Clean up
|
||||
reply->deleteLater();
|
||||
|
||||
return modelList;
|
||||
}
|
||||
|
@ -5,25 +5,29 @@
|
||||
#include <QByteArray>
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QLatin1StringView>
|
||||
#include <QLatin1StringView> // IWYU pragma: keep
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QQmlEngine>
|
||||
#include <QPair> // IWYU pragma: keep
|
||||
#include <QQmlEngine> // IWYU pragma: keep
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSslError>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <QVector> // IWYU pragma: keep
|
||||
#include <Qt>
|
||||
#include <QtGlobal>
|
||||
#include <QtTypes>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
// IWYU pragma: no_forward_declare QObject
|
||||
// IWYU pragma: no_forward_declare QSslError
|
||||
class QUrl;
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
|
||||
@ -269,7 +273,7 @@ private:
|
||||
std::optional<QString> m_chatTemplate;
|
||||
mutable std::optional<QString> m_modelChatTemplate;
|
||||
QString m_systemMessage;
|
||||
QString m_chatNamePrompt = "Describe the above conversation in seven words or less.";
|
||||
QString m_chatNamePrompt = "Describe the above conversation. Your entire response must be three words or less.";
|
||||
QString m_suggestedFollowUpPrompt = "Suggest three very short factual follow-up questions that have not been answered yet or cannot be found inspired by the previous conversation and excerpts.";
|
||||
friend class MySettings;
|
||||
friend class ModelList;
|
||||
@ -530,6 +534,8 @@ public:
|
||||
|
||||
Q_INVOKABLE void discoverSearch(const QString &discover);
|
||||
|
||||
Q_INVOKABLE QStringList remoteModelList(const QString &apiKey, const QUrl &baseUrl);
|
||||
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
void installedModelsChanged();
|
||||
|
@ -11,22 +11,27 @@
|
||||
#include <QFileInfo>
|
||||
#include <QGlobalStatic>
|
||||
#include <QGuiApplication>
|
||||
#include <QIODevice>
|
||||
#include <QIODevice> // IWYU pragma: keep
|
||||
#include <QMap>
|
||||
#include <QMetaObject>
|
||||
#include <QStandardPaths>
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QtLogging>
|
||||
#include <QtAssert>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#if !(defined(Q_OS_MAC) && defined(__aarch64__))
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
|
||||
// used only for settings serialization, do not translate
|
||||
static const QStringList suggestionModeNames { "LocalDocsOnly", "On", "Off" };
|
||||
static const QStringList chatThemeNames { "Light", "Dark", "LegacyDark" };
|
||||
|
@ -4,20 +4,24 @@
|
||||
#include "modellist.h" // IWYU pragma: keep
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QLatin1StringView>
|
||||
#include <QLatin1StringView> // IWYU pragma: keep
|
||||
#include <QList>
|
||||
#include <QModelIndex>
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QTranslator>
|
||||
#include <QVector>
|
||||
#include <QVariant>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
// IWYU pragma: no_forward_declare QModelIndex
|
||||
class QLocale;
|
||||
|
||||
|
||||
namespace MySettingsEnums {
|
||||
Q_NAMESPACE
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "localdocsmodel.h"
|
||||
#include "modellist.h"
|
||||
#include "mysettings.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <gpt4all-backend/llmodel.h>
|
||||
|
||||
@ -29,7 +28,6 @@
|
||||
#include <QSslSocket>
|
||||
#include <QSysInfo>
|
||||
#include <Qt>
|
||||
#include <QtGlobal>
|
||||
#include <QtLogging>
|
||||
#include <QUrl>
|
||||
#include <QUuid>
|
||||
@ -49,6 +47,7 @@ using namespace Qt::Literals::StringLiterals;
|
||||
#define STR_(x) #x
|
||||
#define STR(x) STR_(x)
|
||||
|
||||
|
||||
static const char MIXPANEL_TOKEN[] = "ce362e568ddaee16ed243eaffb5860a2";
|
||||
|
||||
#ifdef __clang__
|
||||
@ -242,6 +241,12 @@ void Network::handleJsonUploadFinished()
|
||||
|
||||
m_activeUploads.removeAll(jsonReply);
|
||||
|
||||
if (jsonReply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Request to" << jsonReply->url().toString() << "failed:" << jsonReply->errorString();
|
||||
jsonReply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant response = jsonReply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
Q_ASSERT(response.isValid());
|
||||
bool ok;
|
||||
@ -449,6 +454,11 @@ void Network::handleIpifyFinished()
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
if (!reply)
|
||||
return;
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Request to" << reply->url().toString() << "failed:" << reply->errorString();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant response = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
Q_ASSERT(response.isValid());
|
||||
@ -473,6 +483,11 @@ void Network::handleMixpanelFinished()
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
if (!reply)
|
||||
return;
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Request to" << reply->url().toString() << "failed:" << reply->errorString();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant response = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
Q_ASSERT(response.isValid());
|
||||
@ -511,6 +526,11 @@ void Network::handleHealthFinished()
|
||||
QNetworkReply *healthReply = qobject_cast<QNetworkReply *>(sender());
|
||||
if (!healthReply)
|
||||
return;
|
||||
if (healthReply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Request to" << healthReply->url().toString() << "failed:" << healthReply->errorString();
|
||||
healthReply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant response = healthReply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
Q_ASSERT(response.isValid());
|
||||
|
@ -11,7 +11,14 @@
|
||||
#include <QSslError>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <QVariantMap> // IWYU pragma: keep
|
||||
#include <QVector> // IWYU pragma: keep
|
||||
|
||||
// IWYU pragma: no_forward_declare QByteArray
|
||||
// IWYU pragma: no_forward_declare QNetworkReply
|
||||
// IWYU pragma: no_forward_declare QSslError
|
||||
class QUrl;
|
||||
|
||||
|
||||
struct KeyValue {
|
||||
QString key;
|
||||
|
@ -4,9 +4,10 @@
|
||||
#include "chatmodel.h"
|
||||
#include "modellist.h"
|
||||
#include "mysettings.h"
|
||||
#include "utils.h"
|
||||
#include "utils.h" // IWYU pragma: keep
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <gpt4all-backend/llmodel.h>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QCborArray>
|
||||
@ -15,32 +16,38 @@
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QHostAddress>
|
||||
#include <QHttpHeaders>
|
||||
#include <QHttpServer>
|
||||
#include <QHttpServerRequest>
|
||||
#include <QHttpServerResponder>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QLatin1StringView>
|
||||
#include <QPair>
|
||||
#include <QPair> // IWYU pragma: keep
|
||||
#include <QTcpServer>
|
||||
#include <QVariant>
|
||||
#include <Qt>
|
||||
#include <QtAssert>
|
||||
#include <QtCborCommon>
|
||||
#include <QtGlobal>
|
||||
#include <QtLogging>
|
||||
#include <QtMinMax>
|
||||
#include <QtPreprocessorSupport>
|
||||
#include <QtTypes>
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
# include <QTcpServer>
|
||||
#endif
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::string_literals;
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
@ -451,23 +458,17 @@ static QJsonObject requestFromJson(const QByteArray &request)
|
||||
void Server::start()
|
||||
{
|
||||
m_server = std::make_unique<QHttpServer>(this);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
auto *tcpServer = new QTcpServer(m_server.get());
|
||||
#else
|
||||
auto *tcpServer = m_server.get();
|
||||
#endif
|
||||
|
||||
auto port = MySettings::globalInstance()->networkPort();
|
||||
if (!tcpServer->listen(QHostAddress::LocalHost, port)) {
|
||||
qWarning() << "Server ERROR: Failed to listen on port" << port;
|
||||
return;
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
if (!m_server->bind(tcpServer)) {
|
||||
qWarning() << "Server ERROR: Failed to HTTP server to socket" << port;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_server->route("/v1/models", QHttpServerRequest::Method::Get,
|
||||
[](const QHttpServerRequest &) {
|
||||
@ -607,19 +608,12 @@ void Server::start()
|
||||
}
|
||||
);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
m_server->addAfterRequestHandler(this, [](const QHttpServerRequest &req, QHttpServerResponse &resp) {
|
||||
Q_UNUSED(req);
|
||||
auto headers = resp.headers();
|
||||
headers.append("Access-Control-Allow-Origin"_L1, "*"_L1);
|
||||
resp.setHeaders(std::move(headers));
|
||||
});
|
||||
#else
|
||||
m_server->afterRequest([](QHttpServerResponse &&resp) {
|
||||
resp.addHeader("Access-Control-Allow-Origin", "*");
|
||||
return std::move(resp);
|
||||
});
|
||||
#endif
|
||||
|
||||
connect(this, &Server::requestResetResponseState, m_chat, &Chat::resetResponseState, Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <QHttpServerResponse>
|
||||
#include <QJsonObject>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QObject> // IWYU pragma: keep
|
||||
#include <QString>
|
||||
|
||||
#include <memory>
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include "tool.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QtTypes>
|
||||
|
||||
#include <string>
|
||||
|
||||
using json = nlohmann::ordered_json;
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
|
||||
class QDataStream;
|
||||
|
||||
using json = nlohmann::ordered_json;
|
||||
|
||||
|
||||
|
@ -1,17 +1,31 @@
|
||||
#include "toolcallparser.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtGlobal>
|
||||
#include <QtLogging>
|
||||
#include "tool.h"
|
||||
|
||||
#include <QChar>
|
||||
#include <QSet>
|
||||
#include <QtAssert>
|
||||
#include <QtTypes>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
ToolCallParser::ToolCallParser()
|
||||
: ToolCallParser(ToolCallConstants::AllTagNames)
|
||||
{}
|
||||
|
||||
ToolCallParser::ToolCallParser(const QStringList &tagNames)
|
||||
{
|
||||
m_possibleStartTags << ToolCallConstants::CodeInterpreterTag.toUtf8()
|
||||
<< ToolCallConstants::ThinkTag.toUtf8();
|
||||
m_possibleEndTags << ToolCallConstants::CodeInterpreterEndTag.toUtf8()
|
||||
<< ToolCallConstants::ThinkEndTag.toUtf8();
|
||||
QSet<QChar> firstChars;
|
||||
for (auto &name : tagNames) {
|
||||
if (name.isEmpty())
|
||||
throw std::invalid_argument("ToolCallParser(): tag names must not be empty");
|
||||
if (firstChars.contains(name.at(0)))
|
||||
throw std::invalid_argument("ToolCallParser(): tag names must not share any prefix");
|
||||
firstChars << name.at(0);
|
||||
m_possibleStartTags << makeStartTag(name).toUtf8();
|
||||
m_possibleEndTags << makeEndTag (name).toUtf8();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -80,7 +94,7 @@ void ToolCallParser::update(const QByteArray &update)
|
||||
{
|
||||
currentBuffer().append(update);
|
||||
|
||||
for (size_t i = currentBuffer().size() - update.size(); i < currentBuffer().size(); ++i) {
|
||||
for (qsizetype i = currentBuffer().size() - update.size(); i < currentBuffer().size(); ++i) {
|
||||
const char c = currentBuffer()[i];
|
||||
const bool foundMatch = isExpected(c);
|
||||
if (!foundMatch) {
|
||||
|
@ -1,30 +1,22 @@
|
||||
#ifndef TOOLCALLPARSER_H
|
||||
#define TOOLCALLPARSER_H
|
||||
|
||||
#include "tool.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
|
||||
namespace ToolCallConstants
|
||||
{
|
||||
const QString CodeInterpreterFunction = R"(javascript_interpret)";
|
||||
const QString CodeInterpreterTag = R"(<)" + CodeInterpreterFunction + R"(>)";
|
||||
const QString CodeInterpreterEndTag = R"(</)" + CodeInterpreterFunction + R"(>)";
|
||||
const QString CodeInterpreterPrefix = CodeInterpreterTag + "\n```javascript\n";
|
||||
const QString CodeInterpreterSuffix = "```\n" + CodeInterpreterEndTag;
|
||||
namespace ToolEnums { enum class ParseState; }
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
// NB: the parsing code assumes the first char of the various tags differ
|
||||
const QString ThinkTag = QStringLiteral("<think>");
|
||||
const QString ThinkEndTag = QStringLiteral("</think>");
|
||||
}
|
||||
|
||||
class ToolCallParser
|
||||
{
|
||||
public:
|
||||
ToolCallParser();
|
||||
ToolCallParser(const QStringList &tagNames);
|
||||
|
||||
void reset();
|
||||
void update(const QByteArray &update);
|
||||
QString toolCall() const { return QString::fromUtf8(m_toolCall); }
|
||||
@ -37,6 +29,9 @@ public:
|
||||
QStringList buffers() const;
|
||||
int numberOfBuffers() const { return m_buffers.size(); }
|
||||
|
||||
static QString makeStartTag(const QString &name) { return u"<%1>"_s .arg(name); }
|
||||
static QString makeEndTag (const QString &name) { return u"</%1>"_s.arg(name); }
|
||||
|
||||
private:
|
||||
QByteArray ¤tBuffer();
|
||||
void resetSearchState();
|
||||
@ -58,4 +53,21 @@ private:
|
||||
int m_endIndex;
|
||||
};
|
||||
|
||||
namespace ToolCallConstants
|
||||
{
|
||||
// NB: the parsing code assumes the first char of the various tags differ
|
||||
|
||||
inline const QString CodeInterpreterFunction = u"javascript_interpret"_s;
|
||||
inline const QString CodeInterpreterStartTag = ToolCallParser::makeStartTag(CodeInterpreterFunction);
|
||||
inline const QString CodeInterpreterEndTag = ToolCallParser::makeEndTag (CodeInterpreterFunction);
|
||||
inline const QString CodeInterpreterPrefix = u"%1\n```javascript\n"_s.arg(CodeInterpreterStartTag);
|
||||
inline const QString CodeInterpreterSuffix = u"```\n%1"_s .arg(CodeInterpreterEndTag );
|
||||
|
||||
inline const QString ThinkTagName = u"think"_s;
|
||||
inline const QString ThinkStartTag = ToolCallParser::makeStartTag(ThinkTagName);
|
||||
inline const QString ThinkEndTag = ToolCallParser::makeEndTag (ThinkTagName);
|
||||
|
||||
inline const QStringList AllTagNames { CodeInterpreterFunction, ThinkTagName };
|
||||
}
|
||||
|
||||
#endif // TOOLCALLPARSER_H
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <QEvent>
|
||||
#include <QGlobalStatic>
|
||||
|
||||
|
||||
class MyToolModel: public ToolModel { };
|
||||
Q_GLOBAL_STATIC(MyToolModel, toolModelInstance)
|
||||
ToolModel *ToolModel::globalInstance()
|
||||
|
@ -9,7 +9,8 @@
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
#include <QtPreprocessorSupport>
|
||||
|
||||
|
||||
class ToolModel : public QAbstractListModel
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QJsonValue>
|
||||
#include <QLatin1StringView>
|
||||
#include <QLatin1StringView> // IWYU pragma: keep
|
||||
#include <QString>
|
||||
#include <QStringView>
|
||||
#include <QUtf8StringView>
|
||||
@ -13,8 +13,9 @@
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <utility> // IWYU pragma: keep
|
||||
|
||||
// IWYU pragma: no_forward_declare QJsonValue
|
||||
class QJsonObject;
|
||||
|
||||
|
||||
@ -40,4 +41,4 @@ MAKE_FORMATTER(QVariant, value.toString().toUtf8());
|
||||
// alternative to QJsonObject's initializer_list constructor that accepts Latin-1 strings
|
||||
QJsonObject makeJsonObject(std::initializer_list<std::pair<QLatin1StringView, QJsonValue>> args);
|
||||
|
||||
#include "utils.inl"
|
||||
#include "utils.inl" // IWYU pragma: export
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <QJsonObject>
|
||||
|
||||
|
||||
inline QJsonObject makeJsonObject(std::initializer_list<std::pair<QLatin1StringView, QJsonValue>> args)
|
||||
{
|
||||
QJsonObject obj;
|
||||
|
@ -7,15 +7,16 @@
|
||||
#include <xlsxformat.h>
|
||||
#include <xlsxworksheet.h>
|
||||
|
||||
#include <QChar>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QLatin1StringView>
|
||||
#include <QList>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringList> // IWYU pragma: keep
|
||||
#include <QStringView>
|
||||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
#include <QtLogging>
|
||||
|
||||
#include <memory>
|
||||
|
@ -4,6 +4,7 @@
|
||||
class QIODevice;
|
||||
class QString;
|
||||
|
||||
|
||||
class XLSXToMD
|
||||
{
|
||||
public:
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user