Upload 101 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .dockerignore +0 -0
- .env +51 -0
- .env.docker +43 -0
- .eslintrc.json +61 -0
- .gitignore +55 -0
- Dockerfile +30 -0
- LICENSE +21 -0
- README_CN.md +201 -0
- assets/qrcode.jpg +0 -0
- assets/screenshot.jpg +0 -0
- assets/screenshot_cn.jpg +0 -0
- backend/app.ts +63 -0
- backend/cache/index.ts +25 -0
- backend/controller.ts +155 -0
- backend/interface.ts +51 -0
- backend/middleware.ts +22 -0
- backend/provider/aliyun.ts +123 -0
- backend/provider/baidu.ts +108 -0
- backend/provider/base/base.ts +18 -0
- backend/provider/base/openai.ts +77 -0
- backend/provider/chatglm.ts +6 -0
- backend/provider/deepseek.ts +6 -0
- backend/provider/google.ts +122 -0
- backend/provider/index.ts +29 -0
- backend/provider/lepton.ts +53 -0
- backend/provider/lmstudio.ts +69 -0
- backend/provider/moonshot.ts +4 -0
- backend/provider/ollama.ts +63 -0
- backend/provider/openai.ts +6 -0
- backend/provider/tencent.ts +69 -0
- backend/provider/yi.ts +7 -0
- backend/rag/index.ts +210 -0
- backend/rag/prompt.ts +163 -0
- backend/search/chatglm.ts +95 -0
- backend/search/searxng.ts +62 -0
- backend/search/sogou.ts +104 -0
- backend/service.ts +128 -0
- backend/utils/constant.ts +69 -0
- backend/utils/utils.ts +26 -0
- docker-compose.yaml +22 -0
- package-lock.json +0 -0
- package.json +50 -0
- searxng/limiter.toml +3 -0
- searxng/settings.yml +2388 -0
- searxng/settings.yml.new +2409 -0
- searxng/uwsgi.ini +50 -0
- searxng/uwsgi.ini.new +54 -0
- tsconfig.json +29 -0
- web/.eslintrc.json +32 -0
- web/.gitignore +25 -0
.dockerignore
ADDED
File without changes
|
.env
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Bing search key
|
2 |
+
BING_SEARCH_KEY=
|
3 |
+
# Google search key
|
4 |
+
GOOGLE_SEARCH_KEY=
|
5 |
+
GOOGLE_SEARCH_ID=
|
6 |
+
# aliyun key
|
7 |
+
ALIYUN_KEY=
|
8 |
+
# Yi Key
|
9 |
+
YI_KEY=
|
10 |
+
# google gemini
|
11 |
+
GOOGLE_KEY=
|
12 |
+
GOOGLE_PROXY_URL=
|
13 |
+
# baidu
|
14 |
+
BAIDU_KEY=
|
15 |
+
BAIDU_SECRET=
|
16 |
+
# tencent KEY:ID, SECRET:KEY
|
17 |
+
TENCENT_KEY=
|
18 |
+
TENCENT_SECRET=
|
19 |
+
# openai key
|
20 |
+
OPENAI_KEY=
|
21 |
+
# openai proxy
|
22 |
+
OPENAI_PROXY_URL=
|
23 |
+
# deepseek
|
24 |
+
DEEPSEEK_KEY=#your_key
|
25 |
+
# chatglm
|
26 |
+
GLM_KEY=#your_key
|
27 |
+
# moonshot
|
28 |
+
MOONSHOT_KEY=
|
29 |
+
# lepthon key
|
30 |
+
LEPTON_KEY=
|
31 |
+
# Local llm: Ollama hostname, could modify if you need.
|
32 |
+
OLLAMA_HOST=http://host.docker.internal:11434
|
33 |
+
# Local llm: LM Studio host name
|
34 |
+
LMSTUDIO_HOSTNAME=localhost:1234
|
35 |
+
# Searxng hostname, could modify if you need.
|
36 |
+
SEARXNG_HOSTNAME=http://searxng:8080
|
37 |
+
# The count of resources referenced
|
38 |
+
REFERENCE_COUNT=8
|
39 |
+
# Whitelist domains, eg. isou.chat,example.org, skip if empty.
|
40 |
+
WHITELIST_DOMAINS=
|
41 |
+
# Server Port
|
42 |
+
PORT=3000
|
43 |
+
# SearXNG query options, safesearch: Filter search results, 0: None 1: Moderate 2: Strict.
|
44 |
+
SEARXNG_SAFE=0
|
45 |
+
# SearXNG query options, language: default is 'all', eg. all/zh/en/en-US/de/it-IT/fr..., this setting has the highest priority.
|
46 |
+
SEARXNG_LANGUAGE=
|
47 |
+
# document: https://docs.searxng.org/user/configured_engines.html
|
48 |
+
SEARXNG_ENGINES=bing,google
|
49 |
+
SEARXNG_IMAGES_ENGINES=bing,google
|
50 |
+
# enable cache, 1 enable, 0 disable
|
51 |
+
CACHE_ENABLE=1
|
.env.docker
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Bing search key
|
2 |
+
BING_SEARCH_KEY=
|
3 |
+
# Google search key
|
4 |
+
GOOGLE_SEARCH_KEY=
|
5 |
+
GOOGLE_SEARCH_ID=
|
6 |
+
# aliyun key
|
7 |
+
ALIYUN_KEY=
|
8 |
+
# Yi Key
|
9 |
+
YI_KEY=
|
10 |
+
# google gemini
|
11 |
+
GOOGLE_KEY=
|
12 |
+
GOOGLE_PROXY_URL=
|
13 |
+
# baidu
|
14 |
+
BAIDU_KEY=
|
15 |
+
BAIDU_SECRET=
|
16 |
+
# tencent KEY:ID, SECRET:KEY
|
17 |
+
TENCENT_KEY=
|
18 |
+
TENCENT_SECRET=
|
19 |
+
# openai key
|
20 |
+
OPENAI_KEY=freeduckduckgo
|
21 |
+
# openai proxy, default is for docker-compose, could modify if you need.
|
22 |
+
OPENAI_PROXY_URL=http://freeduckduckgo:3456/v1
|
23 |
+
# deepseek
|
24 |
+
DEEPSEEK_KEY=#your_key
|
25 |
+
# chatglm
|
26 |
+
GLM_KEY=#your_key
|
27 |
+
# moonshot
|
28 |
+
MOONSHOT_KEY=
|
29 |
+
# lepthon key
|
30 |
+
LEPTON_KEY=
|
31 |
+
# Local llm: Ollama hostname, could modify if you need.
|
32 |
+
OLLAMA_HOST=http://host.docker.internal:11434
|
33 |
+
# Local llm: LM Studio host name
|
34 |
+
LMSTUDIO_HOSTNAME=localhost:1234
|
35 |
+
# Searxng hostname, could modify if you need.
|
36 |
+
SEARXNG_HOSTNAME=http://searxng:8080
|
37 |
+
# https://github.com/searxng/searxng/tree/master/searx/engines
|
38 |
+
SEARXNG_ENGINES=bing,google
|
39 |
+
SEARXNG_IMAGES_ENGINES=bing,google
|
40 |
+
# The count of resources referenced
|
41 |
+
REFERENCE_COUNT = 8
|
42 |
+
# enable cache, 1 enable, 0 disable
|
43 |
+
CACHE_ENABLE=1
|
.eslintrc.json
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"env": {
|
3 |
+
"es6": true,
|
4 |
+
"node": true
|
5 |
+
},
|
6 |
+
"extends": [
|
7 |
+
"eslint:recommended",
|
8 |
+
"plugin:node/recommended"
|
9 |
+
],
|
10 |
+
"parserOptions": {
|
11 |
+
"sourceType": "module"
|
12 |
+
},
|
13 |
+
"ignorePatterns": [
|
14 |
+
"web/"
|
15 |
+
],
|
16 |
+
"overrides": [
|
17 |
+
{
|
18 |
+
"files": ["./backend/**/*.js", "./backend/**/*.ts"],
|
19 |
+
"extends": [
|
20 |
+
"plugin:@typescript-eslint/recommended"
|
21 |
+
],
|
22 |
+
"parser": "@typescript-eslint/parser",
|
23 |
+
"rules": {
|
24 |
+
"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
|
25 |
+
"@typescript-eslint/no-non-null-assertion": "off",
|
26 |
+
"@typescript-eslint/no-use-before-define": "off",
|
27 |
+
"@typescript-eslint/no-warning-comments": "off",
|
28 |
+
"@typescript-eslint/no-empty-function": "off",
|
29 |
+
"@typescript-eslint/no-explicit-any": "off",
|
30 |
+
"@typescript-eslint/no-var-requires": "off",
|
31 |
+
"@typescript-eslint/explicit-function-return-type": "off",
|
32 |
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
33 |
+
"@typescript-eslint/camelcase": "off",
|
34 |
+
"@typescript-eslint/interface-name-prefix": "off",
|
35 |
+
"node/no-missing-import": "off",
|
36 |
+
"node/no-empty-function": "off",
|
37 |
+
"node/no-unsupported-features/es-syntax": "off",
|
38 |
+
"node/no-missing-require": "off",
|
39 |
+
"node/no-unpublished-import": "warn",
|
40 |
+
"node/shebang": "off",
|
41 |
+
"no-dupe-class-members": "off",
|
42 |
+
"require-atomic-updates": "off"
|
43 |
+
}
|
44 |
+
}
|
45 |
+
],
|
46 |
+
"rules": {
|
47 |
+
"block-scoped-var": "error",
|
48 |
+
"eqeqeq": ["error", "always", {"null": "ignore"}],
|
49 |
+
"no-var": "error",
|
50 |
+
"semi": "error",
|
51 |
+
"indent": ["error", 2, { "SwitchCase": 1 }],
|
52 |
+
"no-tabs": "error",
|
53 |
+
"prefer-const": "error",
|
54 |
+
"eol-last": "error",
|
55 |
+
"prefer-arrow-callback": "error",
|
56 |
+
"no-constant-condition": "off",
|
57 |
+
"no-process-exit": "off",
|
58 |
+
"no-trailing-spaces": "error",
|
59 |
+
"quotes": ["warn", "single", { "avoidEscape": true }]
|
60 |
+
}
|
61 |
+
}
|
.gitignore
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Logs
|
2 |
+
logs
|
3 |
+
*.log
|
4 |
+
npm-debug.log*
|
5 |
+
yarn-debug.log*
|
6 |
+
yarn-error.log*
|
7 |
+
lerna-debug.log*
|
8 |
+
.pnpm-debug.log*
|
9 |
+
|
10 |
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
11 |
+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
12 |
+
|
13 |
+
# Runtime data
|
14 |
+
pids
|
15 |
+
*.pid
|
16 |
+
*.seed
|
17 |
+
*.pid.lock
|
18 |
+
|
19 |
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
20 |
+
lib-cov
|
21 |
+
|
22 |
+
# Coverage directory used by tools like istanbul
|
23 |
+
coverage
|
24 |
+
*.lcov
|
25 |
+
|
26 |
+
# nyc test coverage
|
27 |
+
.nyc_output
|
28 |
+
|
29 |
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
30 |
+
.grunt
|
31 |
+
|
32 |
+
# Bower dependency directory (https://bower.io/)
|
33 |
+
bower_components
|
34 |
+
|
35 |
+
# node-waf configuration
|
36 |
+
.lock-wscript
|
37 |
+
|
38 |
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
39 |
+
build/Release
|
40 |
+
|
41 |
+
# Dependency directories
|
42 |
+
node_modules/
|
43 |
+
|
44 |
+
#build
|
45 |
+
dist/
|
46 |
+
build/
|
47 |
+
|
48 |
+
#env
|
49 |
+
.env.local
|
50 |
+
|
51 |
+
#logs
|
52 |
+
log/
|
53 |
+
logs/
|
54 |
+
|
55 |
+
.DS_Store
|
Dockerfile
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM node:20 AS build
|
2 |
+
|
3 |
+
COPY . /app
|
4 |
+
|
5 |
+
# RUN yarn config set registry https://mirrors.cloud.tencent.com/npm/
|
6 |
+
|
7 |
+
WORKDIR /app
|
8 |
+
RUN yarn install && yarn run build
|
9 |
+
|
10 |
+
WORKDIR /app/web
|
11 |
+
RUN yarn install && yarn run build
|
12 |
+
|
13 |
+
FROM node:20-alpine
|
14 |
+
WORKDIR /app
|
15 |
+
|
16 |
+
# Install dotenvx
|
17 |
+
RUN curl -fsS https://dotenvx.sh/ | sh
|
18 |
+
|
19 |
+
COPY .env /app
|
20 |
+
|
21 |
+
COPY --from=build /app/dist ./dist
|
22 |
+
COPY --from=build /app/backend ./backend
|
23 |
+
COPY --from=build /app/web/build ./web/build
|
24 |
+
COPY --from=build /app/package.json ./
|
25 |
+
|
26 |
+
# RUN yarn config set registry https://mirrors.cloud.tencent.com/npm/
|
27 |
+
RUN yarn install --production && yarn cache clean
|
28 |
+
|
29 |
+
EXPOSE 3000
|
30 |
+
CMD yarn run start
|
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2024 zac_ma
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
README_CN.md
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Search with AI
|
2 |
+
|
3 |
+
[English](./README.md) **中文**
|
4 |
+
|
5 |
+
```更新时间: 2024/09/17```
|
6 |
+
|
7 |
+
基于AI大语言模型的对话式搜索引擎,基于Node.js&Vue3。适合新手入门AI大模型开发参考:),文档后有交流群二维码。 [Live Demo](https://isou.chat/)
|
8 |
+
|
9 |
+
<div align="center">
|
10 |
+
<img src="./assets/screenshot_cn.jpg"></img>
|
11 |
+
</div>
|
12 |
+
|
13 |
+
仓库地址:[GitHub仓库](https://github.com/yokingma/search_with_ai)、 [Gitee仓库](https://gitee.com/zac_ma/search_with_ai)
|
14 |
+
|
15 |
+
## 功能说明
|
16 |
+
|
17 |
+
* 内置主流的LLM接口支持,如OpenAI、Google、通译千问、百度文心一言、Lepton、DeepSeek。
|
18 |
+
* 内置搜索引擎支持,如Bing、Sogou、Google、SearXNG(免费开源)。
|
19 |
+
* 支持ChatGLM Web搜索插件 [作为搜索引擎,目前免费]。
|
20 |
+
* 简洁的搜索对话Web界面。
|
21 |
+
* Web界面支持暗色模式。
|
22 |
+
* Web界面支持移动端。
|
23 |
+
* 支持搜索引擎切换、AI模型切换。
|
24 |
+
* 支持本地大模型(基于Ollama、lmStudio)。
|
25 |
+
* 支持多语言(i18n)。
|
26 |
+
* 支持根据结果上下文继续问答。
|
27 |
+
* 支持缓存结果、强制刷新结果。
|
28 |
+
* 支持图片搜索。
|
29 |
+
|
30 |
+
## 使用 Docker 安装部署
|
31 |
+
|
32 |
+
> 文档后面有微信群二维码,有疑问也可以加入群交流。
|
33 |
+
|
34 |
+
**注意:使用SearXNG搜索引擎请确保你的网络能正常访问到Google**
|
35 |
+
|
36 |
+
[安装Docker](https://docs.docker.com/install/).
|
37 |
+
|
38 |
+
1、**克隆仓库**
|
39 |
+
|
40 |
+
```shell
|
41 |
+
git clone https://github.com/yokingma/search_with_ai.git
|
42 |
+
cd search_with_ai
|
43 |
+
```
|
44 |
+
|
45 |
+
2、**编辑** [.env.docker](https://github.com/yokingma/search_with_ai/blob/main/.env)
|
46 |
+
|
47 |
+
在此处配置你的KEY[如 OpenAI、Google、DeepSeek、阿里云、百度、腾讯]即可。
|
48 |
+
|
49 |
+
```shell
|
50 |
+
# 示例
|
51 |
+
# openai KEY, docker compose 默认带了FreeGPT35,如果你没有自己的Key, 这里保持默认
|
52 |
+
OPENAI_KEY=#your key
|
53 |
+
# openai Base Url,
|
54 |
+
OPENAI_PROXY_URL=#OpenAI Base Url, 或者你的OneAPI接口也是支持的。
|
55 |
+
...
|
56 |
+
# 如果需要在docker中访问本地部署的Ollama, 你可能不用改变这个。
|
57 |
+
OLLAMA_HOST=http://host.docker.internal:11434
|
58 |
+
|
59 |
+
# docker compose 默认带了SearXNG免费聚合搜索, 默认不需要修改
|
60 |
+
SEARXNG_HOSTNAME=http://searxng:8080
|
61 |
+
```
|
62 |
+
|
63 |
+
3、 **运行docker-compose.**
|
64 |
+
|
65 |
+
默认包含了 SearXNG,只需要运行:
|
66 |
+
|
67 |
+
```shell
|
68 |
+
docker compose up -d
|
69 |
+
```
|
70 |
+
|
71 |
+
浏览器访问 <http://localhost:3000>
|
72 |
+
|
73 |
+
4、 **更新**
|
74 |
+
|
75 |
+
1. 运行 ```git pull``` (注意保存你的.env设置)
|
76 |
+
|
77 |
+
2. 删除旧版本的镜像
|
78 |
+
3. 执行 ```docker compose down```
|
79 |
+
4. 执行 ```docker compose up -d```
|
80 |
+
|
81 |
+
## 大模型支持
|
82 |
+
|
83 |
+
#### 基于在线大模型的API(需要Key)
|
84 |
+
|
85 |
+
* OpenAI ChatGPT
|
86 |
+
* Google Gemini
|
87 |
+
* Lepton
|
88 |
+
* 阿里云通译千问
|
89 |
+
* 百度文心一言
|
90 |
+
* 零一万物
|
91 |
+
* 月之暗面
|
92 |
+
* DeepSeek
|
93 |
+
* ChatGLM
|
94 |
+
* 腾讯混元
|
95 |
+
* 本地大模型支持:Ollama、LMStudio
|
96 |
+
|
97 |
+
> 如果有新的模型项目暂时不支持的,可以修改(/backend/utils/constant.ts)文件,添加新的模型名称即可。
|
98 |
+
|
99 |
+
## 搜索引擎配置
|
100 |
+
|
101 |
+
内置了搜索引擎服务:Bing、Sogou、Google、SearXNG。
|
102 |
+
|
103 |
+
#### 推荐使用SearXNG (免费开源,不需要KEY)
|
104 |
+
|
105 |
+
安装 [SearXNG](https://github.com/searxng/searxng) ,推荐用Docker部署 [searxng-docker](https://github.com/searxng/searxng-docker)
|
106 |
+
> SearXNG 是一款免费的互联网元搜索引擎,它集合了来自多个搜索服务和数据库的结果。该服务不会追踪或构建其用户档案,为寻求在线匿名性的用户提供保护。此外,SearXNG 还可通过 Tor 网络来实现在线匿名访问。
|
107 |
+
|
108 |
+
安装 SearXNG 时,默认情况下唯一处于激活状态的输出格式是 HTML 格式。若要使用 API,您需要启用 json 格式。可以通过在 settings.yml 文件中添加以下行来实现:
|
109 |
+
|
110 |
+
```yaml
|
111 |
+
search:
|
112 |
+
formats:
|
113 |
+
- html
|
114 |
+
- json
|
115 |
+
```
|
116 |
+
|
117 |
+
并且需要设置limiter为false:
|
118 |
+
|
119 |
+
```yaml
|
120 |
+
server:
|
121 |
+
limiter: false # default is true
|
122 |
+
```
|
123 |
+
|
124 |
+
也可以设置SEARXNG_HOSTNAME (编辑.env文件):
|
125 |
+
|
126 |
+
```shell
|
127 |
+
# SEARXNG_HOSTNAME=<host>
|
128 |
+
```
|
129 |
+
|
130 |
+
#### Bing搜索
|
131 |
+
|
132 |
+
如果要使用必应搜索,需要注册并订阅[Bing搜索服务](https://www.microsoft.com/en-us/bing/apis/bing-web-search-api),获取必应订阅密钥(key)。
|
133 |
+
|
134 |
+
> Bing搜索接口是收费的,但是每月有1000次免费调用额度。
|
135 |
+
|
136 |
+
#### Google搜索
|
137 |
+
|
138 |
+
如果要使用谷歌搜索引擎, 需要[注册谷歌搜索API服务](https://developers.google.com/custom-search),每天有100次免费搜索额度。
|
139 |
+
|
140 |
+
#### Sogou搜索
|
141 |
+
|
142 |
+
内置的Sogou搜索并非直接调用API实现,只是通过简单的网页爬取获取搜索结果。
|
143 |
+
> 内置的Sogou搜索本地测试用(只是简单的网页爬取),**会触发人机验证**,遇到不返回参考资料的情况可以手动打开sogou.com随便搜索关键词,根据提示手动验证一下解除。
|
144 |
+
|
145 |
+
#### ChatGLM Web Search插件
|
146 |
+
[2024/09/17] 新增智谱AI的ChatGLM Web Search插件,作为中文搜索引擎使用。
|
147 |
+
> 智谱AI的glm-flash目前免费,其Web Search插件目前也是免费,基于结合这两者新增了ChatGLM作为免费的中文搜索引擎。
|
148 |
+
|
149 |
+
## 普通安装部署
|
150 |
+
|
151 |
+
需要:
|
152 |
+
> Node.js >= 20
|
153 |
+
|
154 |
+
国内用户推荐使用阿里云通译千问大模型,在阿里云[模型服务灵积](https://dashscope.aliyun.com/)注册可以获取密钥(key),通译千问部分API使用是免费的(qwen-max、qwen-max-1201、qwen-max-longcontext),除了longcontext模型其他限制是60次请求/分钟。
|
155 |
+
|
156 |
+
* **服务端**
|
157 |
+
|
158 |
+
```shell
|
159 |
+
yarn install && yarn run build
|
160 |
+
```
|
161 |
+
|
162 |
+
* **前端页面**
|
163 |
+
|
164 |
+
```shell
|
165 |
+
cd web && yarn install && yarn run build
|
166 |
+
```
|
167 |
+
|
168 |
+
* **配置** (.env)
|
169 |
+
|
170 |
+
各项配置在[.env](https://github.com/yokingma/search_with_ai/blob/main/.env)文件中,请按照需求配置即可。
|
171 |
+
|
172 |
+
[.env.docker](https://github.com/yokingma/search_with_ai/blob/main/.env.docker) 是docker部署使用到的配置文件。
|
173 |
+
|
174 |
+
* **启动**
|
175 |
+
在项目根目录中执行:
|
176 |
+
|
177 |
+
```shell
|
178 |
+
yarn run start
|
179 |
+
```
|
180 |
+
|
181 |
+
* **更新**
|
182 |
+
在项目根目录执行
|
183 |
+
|
184 |
+
```shell
|
185 |
+
git pull
|
186 |
+
yarn install
|
187 |
+
cd web && yarn install && yarn run build
|
188 |
+
```
|
189 |
+
|
190 |
+
启动成功后可以在浏览器打开<http://localhost:3000> 即可使用。
|
191 |
+
|
192 |
+
## 部署案例展示
|
193 |
+
|
194 |
+
* [UI版本]( https://github.com/onenov/search_with_ai ) 一个漂亮的UI实现
|
195 |
+
* [sou.ffa.chat](https://sou.ffa.chat/)
|
196 |
+
* [orence.net/ai](https://orence.net/ai)
|
197 |
+
* [sou.mofa.chat](https://sou.mofa.chat)
|
198 |
+
|
199 |
+
<div align="center">
|
200 |
+
<img src="./assets/qrcode.jpg"></img>
|
201 |
+
</div>
|
assets/qrcode.jpg
ADDED
![]() |
assets/screenshot.jpg
ADDED
![]() |
assets/screenshot_cn.jpg
ADDED
![]() |
backend/app.ts
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import Koa from 'koa';
|
2 |
+
import Router from '@koa/router';
|
3 |
+
import cors from '@koa/cors';
|
4 |
+
import { bodyParser } from '@koa/bodyparser';
|
5 |
+
import serve from 'koa-static';
|
6 |
+
import path from 'path';
|
7 |
+
import { whiteListMiddleware } from './middleware';
|
8 |
+
import history from 'koa2-connect-history-api-fallback';
|
9 |
+
import { chatStreamController, localChatStreamController, localModelsController, modelsController, searchController, sogouSearchController } from './controller';
|
10 |
+
|
11 |
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
12 |
+
// @ts-ignore
|
13 |
+
import dotenvx from '@dotenvx/dotenvx';
|
14 |
+
dotenvx.config();
|
15 |
+
|
16 |
+
const app = new Koa();
|
17 |
+
const router = new Router();
|
18 |
+
|
19 |
+
const port = process.env.PORT || 3000;
|
20 |
+
|
21 |
+
app.use(history({
|
22 |
+
index: '/index.html',
|
23 |
+
whiteList: ['/api']
|
24 |
+
}));
|
25 |
+
|
26 |
+
// static path
|
27 |
+
const staticPath = path.join(__dirname, '../web/build');
|
28 |
+
app.use(serve(staticPath, {
|
29 |
+
gzip: true,
|
30 |
+
index: 'index.html'
|
31 |
+
}));
|
32 |
+
|
33 |
+
app.use(cors({
|
34 |
+
origin: '*'
|
35 |
+
}));
|
36 |
+
|
37 |
+
app.use(bodyParser());
|
38 |
+
|
39 |
+
// Error handler
|
40 |
+
app.use(async (ctx, next) => {
|
41 |
+
try {
|
42 |
+
await next();
|
43 |
+
} catch(err) {
|
44 |
+
console.error('[server error]', err);
|
45 |
+
ctx.res.statusCode = 422;
|
46 |
+
ctx.body = err;
|
47 |
+
}
|
48 |
+
});
|
49 |
+
|
50 |
+
// router
|
51 |
+
app.use(router.routes()).use(router.allowedMethods());
|
52 |
+
|
53 |
+
// controller
|
54 |
+
router.post('/api/search', whiteListMiddleware(), searchController);
|
55 |
+
router.post('/api/sogou/search', sogouSearchController);
|
56 |
+
router.post('/api/chat', chatStreamController);
|
57 |
+
router.get('/api/models', modelsController);
|
58 |
+
|
59 |
+
// local llm
|
60 |
+
router.get('/api/local/models', localModelsController);
|
61 |
+
router.post('/api/local/chat', localChatStreamController);
|
62 |
+
|
63 |
+
app.listen(port);
|
backend/cache/index.ts
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { createCache, memoryStore } from 'cache-manager';
|
2 |
+
import { createHash } from 'node:crypto';
|
3 |
+
import { TMode } from '../interface';
|
4 |
+
import { ESearXNGCategory } from '../search/searxng';
|
5 |
+
|
6 |
+
const memoryCache = createCache(memoryStore(), {
|
7 |
+
ttl: 60 * 1000 * 60 * 24 // ms
|
8 |
+
});
|
9 |
+
|
10 |
+
export async function setToCache(key: string, val: string, mode: TMode = 'simple', categories: ESearXNGCategory[] = []) {
|
11 |
+
const hash = createHash('sha256');
|
12 |
+
const str = `${key}_${mode}_${categories.join()}`;
|
13 |
+
const hashKey = hash.update(str, 'utf8').digest('hex');
|
14 |
+
await memoryCache.set(hashKey, val);
|
15 |
+
}
|
16 |
+
|
17 |
+
export async function getFromCache(q: string, mode: TMode = 'simple', categories: ESearXNGCategory[] = []) {
|
18 |
+
const hash = createHash('sha256');
|
19 |
+
const str = `${q}_${mode}_${categories.join()}`;
|
20 |
+
const hashKey = hash.update(str, 'utf8').digest('hex');
|
21 |
+
const val = await memoryCache.get<string>(hashKey);
|
22 |
+
return val;
|
23 |
+
}
|
24 |
+
|
25 |
+
export default memoryCache;
|
backend/controller.ts
ADDED
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Context } from 'koa';
|
2 |
+
import { Rag } from './rag';
|
3 |
+
import platform from './provider';
|
4 |
+
import { DefaultQuery, Models } from './utils/constant';
|
5 |
+
import { searchWithSogou } from './service';
|
6 |
+
import { ESearchEngine, IChatInputMessage, Provider, TMode } from './interface';
|
7 |
+
import { getFromCache, setToCache } from './cache';
|
8 |
+
import { ESearXNGCategory } from './search/searxng';
|
9 |
+
|
10 |
+
const CACHE_ENABLED = process.env.CACHE_ENABLE;
|
11 |
+
|
12 |
+
export const searchController = async (ctx: Context) => {
|
13 |
+
const stream = ctx.request.body.stream ?? true;
|
14 |
+
const q = ctx.request.query.q || DefaultQuery;
|
15 |
+
const model: string = ctx.request.body.model;
|
16 |
+
const reload: boolean = ctx.request.body.reload ?? false;
|
17 |
+
const engine: ESearchEngine = ctx.request.body.engine;
|
18 |
+
const locally: boolean = ctx.request.body.locally ?? false;
|
19 |
+
const categories: ESearXNGCategory[] = ctx.request.body.categories ?? [];
|
20 |
+
const mode: TMode = ctx.request.body.mode ?? 'simple';
|
21 |
+
const language: string = ctx.request.body.language || 'all';
|
22 |
+
const provider: Provider = ctx.request.body.provider || 'ollama';
|
23 |
+
|
24 |
+
ctx.res.setHeader('Content-Type', 'text/event-stream');
|
25 |
+
ctx.res.setHeader('Cache-Control', 'no-cache');
|
26 |
+
ctx.res.setHeader('Connection', 'keep-alive');
|
27 |
+
ctx.res.statusCode = 200;
|
28 |
+
|
29 |
+
// get from cache, skip if enable reload
|
30 |
+
if (!reload) {
|
31 |
+
const cached = await getFromCache(q as string, mode, categories);
|
32 |
+
if (cached) {
|
33 |
+
ctx.body = cached;
|
34 |
+
ctx.res.write(cached, 'utf-8');
|
35 |
+
ctx.res.end();
|
36 |
+
return;
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
const rag = new Rag({
|
41 |
+
stream,
|
42 |
+
model,
|
43 |
+
engine,
|
44 |
+
locally,
|
45 |
+
provider
|
46 |
+
});
|
47 |
+
|
48 |
+
if (!stream) {
|
49 |
+
const res = await rag.query(q as string);
|
50 |
+
ctx.body = res;
|
51 |
+
return;
|
52 |
+
}
|
53 |
+
|
54 |
+
let result = '';
|
55 |
+
|
56 |
+
await rag.query(q as string, categories, mode, language, (json: string) => {
|
57 |
+
const eventData = `data:${JSON.stringify({ data: json })}\n\n`;
|
58 |
+
result += eventData;
|
59 |
+
ctx.res.write(eventData, 'utf-8');
|
60 |
+
});
|
61 |
+
|
62 |
+
ctx.res.end();
|
63 |
+
// caching
|
64 |
+
if (CACHE_ENABLED === '1') {
|
65 |
+
setToCache(q as string, result, mode, categories);
|
66 |
+
}
|
67 |
+
};
|
68 |
+
|
69 |
+
export const sogouSearchController = async (ctx: Context) => {
|
70 |
+
const q = ctx.request.query.q || DefaultQuery;
|
71 |
+
const res = await searchWithSogou(q as string);
|
72 |
+
ctx.body = res;
|
73 |
+
};
|
74 |
+
|
75 |
+
export const chatStreamController = async (ctx: Context) => {
|
76 |
+
const messages: IChatInputMessage[] = ctx.request.body.messages || [];
|
77 |
+
const system: string | undefined = ctx.request.body.system;
|
78 |
+
const model: string | undefined = ctx.request.body.model;
|
79 |
+
const locally: boolean = ctx.request.body.locally ?? false;
|
80 |
+
const provider: Provider = ctx.request.body.provider ?? 'ollama';
|
81 |
+
|
82 |
+
if (!model) throw new Error('model is required');
|
83 |
+
|
84 |
+
ctx.res.setHeader('Content-Type', 'text/event-stream');
|
85 |
+
ctx.res.setHeader('Cache-Control', 'no-cache');
|
86 |
+
ctx.res.setHeader('Connection', 'keep-alive');
|
87 |
+
const handler = locally ? platform[provider].chatStream.bind(platform[provider]) : processModel(model);
|
88 |
+
ctx.res.statusCode = 200;
|
89 |
+
|
90 |
+
await handler?.(messages, (data: any) => {
|
91 |
+
const eventData = `data: ${JSON.stringify({ text: data || '' })}\n\n`;
|
92 |
+
ctx.res.write(eventData);
|
93 |
+
}, model, system);
|
94 |
+
|
95 |
+
ctx.res.end();
|
96 |
+
};
|
97 |
+
|
98 |
+
export const modelsController = async (ctx: Context) => {
|
99 |
+
const { GOOGLE_KEY, ALIYUN_KEY, OPENAI_KEY, BAIDU_KEY, TENCENT_KEY, YI_KEY, MOONSHOT_KEY, LEPTON_KEY, DEEPSEEK_KEY, GLM_KEY } = process.env;
|
100 |
+
const keys: Record<string, string | undefined> = {
|
101 |
+
google: GOOGLE_KEY,
|
102 |
+
aliyun: ALIYUN_KEY,
|
103 |
+
openai: OPENAI_KEY,
|
104 |
+
baidu: BAIDU_KEY,
|
105 |
+
tencent: TENCENT_KEY,
|
106 |
+
yi: YI_KEY,
|
107 |
+
moonshot: MOONSHOT_KEY,
|
108 |
+
lepton: LEPTON_KEY,
|
109 |
+
chatglm: GLM_KEY,
|
110 |
+
deepseek: DEEPSEEK_KEY
|
111 |
+
};
|
112 |
+
const models = Models.filter(item => keys[item.platform] !== undefined);
|
113 |
+
const enabledModels: Record<string, string[]> = {};
|
114 |
+
for (const model of models) {
|
115 |
+
if (keys[model.platform]) enabledModels[model.platform] = model.models;
|
116 |
+
}
|
117 |
+
ctx.body = enabledModels;
|
118 |
+
};
|
119 |
+
|
120 |
+
// locally llm models
|
121 |
+
export const localModelsController = async (ctx: Context) => {
|
122 |
+
const provider: Provider = ctx.URL.searchParams.get('provider') as Provider ?? 'ollama';
|
123 |
+
|
124 |
+
const list = await platform[provider].list();
|
125 |
+
ctx.body = list;
|
126 |
+
};
|
127 |
+
|
128 |
+
|
129 |
+
// chat with locally models
|
130 |
+
export const localChatStreamController = async (ctx: Context) => {
|
131 |
+
const messages: IChatInputMessage[] = ctx.request.body.messages || [];
|
132 |
+
const model: string | undefined = ctx.request.body.model;
|
133 |
+
const provider: Provider = ctx.request.body.provider;
|
134 |
+
|
135 |
+
ctx.res.setHeader('Content-Type', 'text/event-stream');
|
136 |
+
ctx.res.setHeader('Cache-Control', 'no-cache');
|
137 |
+
ctx.res.setHeader('Connection', 'keep-alive');
|
138 |
+
ctx.res.statusCode = 200;
|
139 |
+
await platform[provider].chatStream(messages, (data) => {
|
140 |
+
const eventData = `data: ${JSON.stringify({ text: data || '' })}\n\n`;
|
141 |
+
ctx.res.write(eventData);
|
142 |
+
}, model);
|
143 |
+
ctx.res.end();
|
144 |
+
};
|
145 |
+
|
146 |
+
|
147 |
+
function processModel(model: string) {
|
148 |
+
const targetModel = Models.find(item => {
|
149 |
+
return item.models.includes(model);
|
150 |
+
});
|
151 |
+
if (targetModel?.platform) {
|
152 |
+
const target = platform[targetModel.platform];
|
153 |
+
return target.chatStream.bind(target);
|
154 |
+
}
|
155 |
+
}
|
backend/interface.ts
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import platform from './provider';
|
2 |
+
|
3 |
+
export type SearchFunc = (...args: any[]) => Promise<any[]>;
|
4 |
+
|
5 |
+
export enum ESearchEngine {
|
6 |
+
GOOGLE = 'GOOGLE',
|
7 |
+
BING = 'BING',
|
8 |
+
SOGOU = 'SOGOU',
|
9 |
+
SEARXNG = 'SEARXNG',
|
10 |
+
CHATGLM = 'CHATGLM'
|
11 |
+
}
|
12 |
+
|
13 |
+
export type ChatRoleType = 'user' | 'assistant' | 'system';
|
14 |
+
export interface IChatInputMessage {
|
15 |
+
content: string;
|
16 |
+
role: ChatRoleType;
|
17 |
+
}
|
18 |
+
|
19 |
+
export type Provider = 'ollama' | 'lmstudio';
|
20 |
+
|
21 |
+
export interface IChatResponse {
|
22 |
+
text: string;
|
23 |
+
usage?: {
|
24 |
+
outputTokens: number;
|
25 |
+
inputTokens: number;
|
26 |
+
};
|
27 |
+
}
|
28 |
+
|
29 |
+
export interface IModelInfo {
|
30 |
+
platform: keyof typeof platform;
|
31 |
+
type: string;
|
32 |
+
models: string[];
|
33 |
+
}
|
34 |
+
|
35 |
+
|
36 |
+
export interface IStreamHandler {
|
37 |
+
(message: string | null, done: boolean): void
|
38 |
+
}
|
39 |
+
|
40 |
+
// search engine result
|
41 |
+
export interface ISearchResponseResult {
|
42 |
+
name: string;
|
43 |
+
url: string;
|
44 |
+
snippet: string;
|
45 |
+
thumbnail?: string;
|
46 |
+
img?: string;
|
47 |
+
source?: string;
|
48 |
+
[key: string]: string | undefined;
|
49 |
+
}
|
50 |
+
|
51 |
+
export type TMode = 'simple' | 'deep' | 'research'
|
backend/middleware.ts
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Context, Next } from 'koa';
|
2 |
+
|
3 |
+
export function whiteListMiddleware() {
|
4 |
+
return async (ctx: Context, next: Next) => {
|
5 |
+
const host = ctx.request.host;
|
6 |
+
const whiteList = process.env.WHITELIST_DOMAINS;
|
7 |
+
const list = whiteList ? whiteList.split(',') : [];
|
8 |
+
|
9 |
+
console.log('[whiteListMiddleware]', list, host);
|
10 |
+
|
11 |
+
if (!list.length) {
|
12 |
+
return await next();
|
13 |
+
}
|
14 |
+
|
15 |
+
if (list.some(item => host.includes(item.trim()))) {
|
16 |
+
await next();
|
17 |
+
} else {
|
18 |
+
ctx.res.statusCode = 401;
|
19 |
+
ctx.body = 'Unauthorized domain.';
|
20 |
+
}
|
21 |
+
};
|
22 |
+
}
|
backend/provider/aliyun.ts
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { IChatInputMessage, IStreamHandler } from '../interface';
|
2 |
+
import { httpRequest } from '../utils/utils';
|
3 |
+
import { BaseChat } from './base/base';
|
4 |
+
import { fetchEventData } from 'fetch-sse';
|
5 |
+
|
6 |
+
const BaseURL = 'https://dashscope.aliyuncs.com/api/v1/';
|
7 |
+
const APIS = {
|
8 |
+
qwen: 'services/aigc/text-generation/generation',
|
9 |
+
background: 'services/aigc/background-generation/generation',
|
10 |
+
task: 'tasks/%s',
|
11 |
+
embedding: 'services/embeddings/text-embedding/text-embedding',
|
12 |
+
};
|
13 |
+
|
14 |
+
export class AliyunChat implements BaseChat {
|
15 |
+
private key?: string;
|
16 |
+
platform = 'aliyun';
|
17 |
+
|
18 |
+
constructor() {
|
19 |
+
this.key = process.env.ALIYUN_KEY;
|
20 |
+
}
|
21 |
+
|
22 |
+
public async chat(
|
23 |
+
messages: IChatInputMessage[],
|
24 |
+
model: string,
|
25 |
+
system?: string
|
26 |
+
) {
|
27 |
+
if (system) {
|
28 |
+
messages = [
|
29 |
+
{
|
30 |
+
role: 'system',
|
31 |
+
content: system,
|
32 |
+
},
|
33 |
+
...messages,
|
34 |
+
];
|
35 |
+
}
|
36 |
+
const options = {
|
37 |
+
input: {
|
38 |
+
messages,
|
39 |
+
},
|
40 |
+
};
|
41 |
+
const url = `${BaseURL}${APIS.qwen}`;
|
42 |
+
const payload = JSON.stringify({
|
43 |
+
model,
|
44 |
+
input: options.input
|
45 |
+
});
|
46 |
+
const res = await httpRequest({
|
47 |
+
endpoint: url,
|
48 |
+
method: 'POST',
|
49 |
+
headers: {
|
50 |
+
'Content-Type': 'application/json',
|
51 |
+
'Authorization': `Bearer ${this.key}`
|
52 |
+
},
|
53 |
+
data: payload
|
54 |
+
});
|
55 |
+
const data = await res.json();
|
56 |
+
if (data?.message) {
|
57 |
+
console.error(data);
|
58 |
+
throw new Error(data.message ?? 'bad request.');
|
59 |
+
}
|
60 |
+
return data.output.text;
|
61 |
+
}
|
62 |
+
|
63 |
+
public async chatStream(
|
64 |
+
messages: IChatInputMessage[],
|
65 |
+
onMessage: IStreamHandler,
|
66 |
+
model: string,
|
67 |
+
system?: string
|
68 |
+
): Promise<void> {
|
69 |
+
if (system) {
|
70 |
+
messages = [
|
71 |
+
{
|
72 |
+
role: 'system',
|
73 |
+
content: system,
|
74 |
+
},
|
75 |
+
...messages,
|
76 |
+
];
|
77 |
+
}
|
78 |
+
const options = {
|
79 |
+
input: {
|
80 |
+
messages,
|
81 |
+
}
|
82 |
+
};
|
83 |
+
const url = `${BaseURL}${APIS.qwen}`;
|
84 |
+
const payload = {
|
85 |
+
model,
|
86 |
+
input: options.input,
|
87 |
+
parameters: {
|
88 |
+
incremental_output: true
|
89 |
+
}
|
90 |
+
};
|
91 |
+
const abort = new AbortController();
|
92 |
+
const key = this.key;
|
93 |
+
try {
|
94 |
+
await fetchEventData(url, {
|
95 |
+
method: 'POST',
|
96 |
+
headers: {
|
97 |
+
'Authorization': `Bearer ${key}`,
|
98 |
+
'Content-Type': 'application/json'
|
99 |
+
},
|
100 |
+
data: payload,
|
101 |
+
signal: abort.signal,
|
102 |
+
onMessage: (eventData) => {
|
103 |
+
const data = eventData?.data;
|
104 |
+
try {
|
105 |
+
const result = JSON.parse(data || '{}');
|
106 |
+
const msg = result.output?.text ?? '';
|
107 |
+
onMessage(msg, false);
|
108 |
+
} catch(error) {
|
109 |
+
console.error('Aliyun onMessage Error: ', error);
|
110 |
+
}
|
111 |
+
},
|
112 |
+
onClose: () => {
|
113 |
+
onMessage(null, false);
|
114 |
+
}
|
115 |
+
});
|
116 |
+
} catch (err) {
|
117 |
+
console.error(err);
|
118 |
+
abort.abort();
|
119 |
+
}
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
export const aliyun = new AliyunChat();
|
backend/provider/baidu.ts
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { fetchEventData } from 'fetch-sse';
|
2 |
+
import { httpRequest } from '../utils/utils';
|
3 |
+
import memoryCache from '../cache';
|
4 |
+
import { BaseChat } from './base/base';
|
5 |
+
import { IChatInputMessage, IStreamHandler } from '../interface';
|
6 |
+
import { type MemoryCache } from 'cache-manager';
|
7 |
+
|
8 |
+
const BASE_URL =
|
9 |
+
'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat';
|
10 |
+
|
11 |
+
const TokenUrl = 'https://aip.baidubce.com/oauth/2.0/token';
|
12 |
+
|
13 |
+
export class BaiduChat implements BaseChat {
|
14 |
+
private key?: string;
|
15 |
+
private secret?: string;
|
16 |
+
private cache: MemoryCache;
|
17 |
+
public platform = 'baidu';
|
18 |
+
|
19 |
+
constructor() {
|
20 |
+
this.key = process.env.BAIDU_KEY;
|
21 |
+
this.secret = process.env.BAIDU_SECRET;
|
22 |
+
this.cache = memoryCache;
|
23 |
+
}
|
24 |
+
|
25 |
+
public async chat(
|
26 |
+
messages: IChatInputMessage[],
|
27 |
+
model: string,
|
28 |
+
system?: string
|
29 |
+
) {
|
30 |
+
const token = await this.getAccessToken();
|
31 |
+
const res = await httpRequest({
|
32 |
+
endpoint: `${BASE_URL}/${model}`,
|
33 |
+
method: 'POST',
|
34 |
+
query: {
|
35 |
+
access_token: token
|
36 |
+
},
|
37 |
+
data: JSON.stringify({
|
38 |
+
messages,
|
39 |
+
system,
|
40 |
+
stream: false,
|
41 |
+
})
|
42 |
+
});
|
43 |
+
const data = await res.json();
|
44 |
+
if (data.error_code) {
|
45 |
+
const msg = `${data.error_code}: ${data.error_msg}`;
|
46 |
+
throw new Error(msg);
|
47 |
+
}
|
48 |
+
return data.result;
|
49 |
+
}
|
50 |
+
|
51 |
+
public async chatStream(
|
52 |
+
messages: IChatInputMessage[],
|
53 |
+
onMessage: IStreamHandler,
|
54 |
+
model: string,
|
55 |
+
system?: string
|
56 |
+
): Promise<void> {
|
57 |
+
const token = await this.getAccessToken();
|
58 |
+
const url = `${BASE_URL}/${model}?access_token=${token}`;
|
59 |
+
const abort = new AbortController();
|
60 |
+
await fetchEventData(url, {
|
61 |
+
method: 'POST',
|
62 |
+
data: {
|
63 |
+
messages,
|
64 |
+
system,
|
65 |
+
stream: true,
|
66 |
+
},
|
67 |
+
signal: abort.signal,
|
68 |
+
onMessage: (eventData) => {
|
69 |
+
const data = eventData?.data;
|
70 |
+
const result = JSON.parse(data || '{}');
|
71 |
+
const msg = result.result ?? '';
|
72 |
+
onMessage(msg, false);
|
73 |
+
}
|
74 |
+
});
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @description baidu access_token默认有效期30天,单位是秒,生产环境注意及时刷新。
|
79 |
+
*/
|
80 |
+
protected async getAccessToken(): Promise<string> {
|
81 |
+
if (!this.key || !this.secret) {
|
82 |
+
throw new Error('Invalid Baidu params: key or secret');
|
83 |
+
}
|
84 |
+
const { key, secret } = this;
|
85 |
+
const cachedToken: string | undefined = await this.cache.get(key);
|
86 |
+
if (cachedToken) {
|
87 |
+
return cachedToken;
|
88 |
+
}
|
89 |
+
const res = await httpRequest({
|
90 |
+
method: 'POST',
|
91 |
+
endpoint: TokenUrl,
|
92 |
+
query: {
|
93 |
+
grant_type: 'client_credentials',
|
94 |
+
client_id: key,
|
95 |
+
client_secret: secret,
|
96 |
+
}
|
97 |
+
});
|
98 |
+
const data = await res.json();
|
99 |
+
if (data?.error) {
|
100 |
+
throw new Error(data.error);
|
101 |
+
}
|
102 |
+
const { access_token, expires_in } = data;
|
103 |
+
this.cache.set(key, access_token, expires_in - 10);
|
104 |
+
return access_token;
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
export const baidu = new BaiduChat();
|
backend/provider/base/base.ts
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { IChatInputMessage, IStreamHandler } from '../../interface';
|
2 |
+
|
3 |
+
export abstract class BaseChat {
|
4 |
+
platform: string;
|
5 |
+
|
6 |
+
abstract chat?(
|
7 |
+
messages: IChatInputMessage[],
|
8 |
+
model?: string,
|
9 |
+
system?: string
|
10 |
+
): Promise<string | null>;
|
11 |
+
|
12 |
+
abstract chatStream(
|
13 |
+
messages: IChatInputMessage[],
|
14 |
+
onMessage: IStreamHandler,
|
15 |
+
model?: string,
|
16 |
+
system?: string
|
17 |
+
): Promise<void>;
|
18 |
+
}
|
backend/provider/base/openai.ts
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import OpenAI from 'openai';
|
2 |
+
import { IChatInputMessage, IStreamHandler } from '../../interface';
|
3 |
+
import { BaseChat } from './base';
|
4 |
+
|
5 |
+
export class BaseOpenAIChat implements BaseChat {
|
6 |
+
private openai: OpenAI | null;
|
7 |
+
public platform: string;
|
8 |
+
|
9 |
+
constructor(platform: string, apiKey?: string, baseURL?: string) {
|
10 |
+
this.platform = platform;
|
11 |
+
if (apiKey) {
|
12 |
+
this.openai = new OpenAI({
|
13 |
+
baseURL,
|
14 |
+
apiKey,
|
15 |
+
});
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
public async chat(
|
20 |
+
messages: IChatInputMessage[],
|
21 |
+
model: string,
|
22 |
+
system?: string
|
23 |
+
) {
|
24 |
+
if (!this.openai) {
|
25 |
+
throw new Error(`${this.platform} key is not set`);
|
26 |
+
}
|
27 |
+
if (system) {
|
28 |
+
messages = [
|
29 |
+
{
|
30 |
+
role: 'system',
|
31 |
+
content: system,
|
32 |
+
},
|
33 |
+
...messages,
|
34 |
+
];
|
35 |
+
}
|
36 |
+
const res = await this.openai.chat.completions.create({
|
37 |
+
messages,
|
38 |
+
model
|
39 |
+
});
|
40 |
+
return res.choices[0]?.message.content;
|
41 |
+
}
|
42 |
+
|
43 |
+
public async chatStream(
|
44 |
+
messages: IChatInputMessage[],
|
45 |
+
onMessage: IStreamHandler,
|
46 |
+
model: string,
|
47 |
+
system?: string
|
48 |
+
) {
|
49 |
+
if (!this.openai) {
|
50 |
+
throw new Error(`${this.platform} key is not set`);
|
51 |
+
}
|
52 |
+
if (system) {
|
53 |
+
messages = [
|
54 |
+
{
|
55 |
+
role: 'system',
|
56 |
+
content: system,
|
57 |
+
},
|
58 |
+
...messages,
|
59 |
+
];
|
60 |
+
}
|
61 |
+
const stream = await this.openai.chat.completions.create({
|
62 |
+
messages,
|
63 |
+
model,
|
64 |
+
stream: true
|
65 |
+
});
|
66 |
+
for await (const chunk of stream) {
|
67 |
+
onMessage?.(chunk.choices[0].delta.content || null, false);
|
68 |
+
}
|
69 |
+
onMessage?.(null, true);
|
70 |
+
}
|
71 |
+
|
72 |
+
async listModels() {
|
73 |
+
if (!this.openai) throw new Error(`${this.platform} Key is Required.`);
|
74 |
+
const models = await this.openai.models.list();
|
75 |
+
return models.data.map((model) => model.id);
|
76 |
+
}
|
77 |
+
}
|
backend/provider/chatglm.ts
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { BaseOpenAIChat } from './base/openai';
|
2 |
+
|
3 |
+
const ApiKey = process.env.GLM_KEY;
|
4 |
+
const BaseURL = 'https://open.bigmodel.cn/api/paas/v4/';
|
5 |
+
|
6 |
+
export const chatglm = new BaseOpenAIChat('chatglm', ApiKey, BaseURL);
|
backend/provider/deepseek.ts
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { BaseOpenAIChat } from './base/openai';
|
2 |
+
|
3 |
+
const ApiKey = process.env.DEEPSEEK_KEY;
|
4 |
+
const BaseURL = 'https://api.deepseek.com/v1';
|
5 |
+
|
6 |
+
export const deepseek = new BaseOpenAIChat('deepseek', ApiKey, BaseURL);
|
backend/provider/google.ts
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { BaseChat } from './base/base';
|
2 |
+
import { IChatInputMessage, IStreamHandler } from '../interface';
|
3 |
+
import { DefaultSystem } from '../utils/constant';
|
4 |
+
import { httpRequest } from '../utils/utils';
|
5 |
+
import { fetchEventData } from 'fetch-sse';
|
6 |
+
|
7 |
+
const BASE_URL = 'https://generativelanguage.googleapis.com/v1beta';
|
8 |
+
|
9 |
+
const URLS = {
|
10 |
+
geminiPro: '/models/gemini-pro:generateContent',
|
11 |
+
geminiProStream: '/models/gemini-pro:streamGenerateContent?alt=sse',
|
12 |
+
};
|
13 |
+
|
14 |
+
export class GoogleChat implements BaseChat {
|
15 |
+
private key?: string;
|
16 |
+
private baseUrl?: string;
|
17 |
+
public platform = 'google';
|
18 |
+
|
19 |
+
constructor() {
|
20 |
+
this.key = process.env.GOOGLE_KEY;
|
21 |
+
this.baseUrl = process.env.GOOGLE_PROXY_URL || BASE_URL;
|
22 |
+
console.log('GoogleAI BaseURL: ', this.baseUrl);
|
23 |
+
}
|
24 |
+
|
25 |
+
public async chat(
|
26 |
+
messages: IChatInputMessage[],
|
27 |
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
28 |
+
model: string
|
29 |
+
) {
|
30 |
+
const msgs = this.transformMessage(messages);
|
31 |
+
const url = `${this.baseUrl}/${URLS.geminiProStream}`;
|
32 |
+
const res = await httpRequest({
|
33 |
+
endpoint: url,
|
34 |
+
method: 'POST',
|
35 |
+
data: JSON.stringify({
|
36 |
+
contents: msgs
|
37 |
+
}),
|
38 |
+
query: {
|
39 |
+
key: this.key,
|
40 |
+
},
|
41 |
+
});
|
42 |
+
const data = await res.json();
|
43 |
+
const resMsg = data.candidates?.[0];
|
44 |
+
if (res.status !== 200 || !resMsg) {
|
45 |
+
throw new Error(data.message ?? 'Google AI request error.');
|
46 |
+
}
|
47 |
+
return resMsg.content?.parts[0]?.text;
|
48 |
+
}
|
49 |
+
|
50 |
+
public async chatStream(
|
51 |
+
messages: IChatInputMessage[],
|
52 |
+
onMessage: IStreamHandler,
|
53 |
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
54 |
+
model: string,
|
55 |
+
system = DefaultSystem
|
56 |
+
) {
|
57 |
+
const msgs = this.transformMessage(messages);
|
58 |
+
if (system) {
|
59 |
+
msgs.unshift({
|
60 |
+
role: 'user',
|
61 |
+
parts: [
|
62 |
+
{
|
63 |
+
text: system
|
64 |
+
}
|
65 |
+
]
|
66 |
+
}, {
|
67 |
+
role: 'model',
|
68 |
+
parts: [
|
69 |
+
{
|
70 |
+
text: 'ok.'
|
71 |
+
}
|
72 |
+
]
|
73 |
+
});
|
74 |
+
}
|
75 |
+
const url = `${this.baseUrl}${URLS.geminiProStream}`;
|
76 |
+
const data = {
|
77 |
+
contents: msgs
|
78 |
+
};
|
79 |
+
const abort = new AbortController();
|
80 |
+
await fetchEventData(url, {
|
81 |
+
method: 'POST',
|
82 |
+
data,
|
83 |
+
signal: abort.signal,
|
84 |
+
headers: {
|
85 |
+
'Content-Type': 'application/json',
|
86 |
+
'x-goog-api-key': this.key
|
87 |
+
},
|
88 |
+
onOpen: async () => {
|
89 |
+
//
|
90 |
+
},
|
91 |
+
onMessage: (eventData) => {
|
92 |
+
const data = eventData?.data;
|
93 |
+
const result = JSON.parse(data || '{}');
|
94 |
+
const msg = result.candidates?.[0]?.content?.parts[0]?.text ?? '';
|
95 |
+
onMessage(msg, false);
|
96 |
+
},
|
97 |
+
onClose: () => {
|
98 |
+
onMessage(null, true);
|
99 |
+
},
|
100 |
+
onError: (error) => {
|
101 |
+
abort.abort();
|
102 |
+
console.log(error);
|
103 |
+
},
|
104 |
+
});
|
105 |
+
}
|
106 |
+
|
107 |
+
private transformMessage(messages: IChatInputMessage[]) {
|
108 |
+
return messages.map(msg => {
|
109 |
+
const role = msg.role === 'assistant' ? 'model' : 'user';
|
110 |
+
return {
|
111 |
+
role,
|
112 |
+
parts: [
|
113 |
+
{
|
114 |
+
text: msg.content,
|
115 |
+
},
|
116 |
+
],
|
117 |
+
};
|
118 |
+
});
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
export const google = new GoogleChat();
|
backend/provider/index.ts
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { aliyun } from './aliyun';
|
2 |
+
import { openai } from './openai';
|
3 |
+
import { baidu } from './baidu';
|
4 |
+
import { google } from './google';
|
5 |
+
import { tencent } from './tencent';
|
6 |
+
import { yi } from './yi';
|
7 |
+
import { moonshot } from './moonshot';
|
8 |
+
import { lepton } from './lepton';
|
9 |
+
import { deepseek } from './deepseek';
|
10 |
+
import { chatglm } from './chatglm';
|
11 |
+
import { ollama } from './ollama';
|
12 |
+
import { lmstudio } from './lmstudio';
|
13 |
+
|
14 |
+
const platform = {
|
15 |
+
aliyun,
|
16 |
+
openai,
|
17 |
+
baidu,
|
18 |
+
google,
|
19 |
+
tencent,
|
20 |
+
yi,
|
21 |
+
deepseek,
|
22 |
+
chatglm,
|
23 |
+
moonshot,
|
24 |
+
lepton,
|
25 |
+
ollama,
|
26 |
+
lmstudio
|
27 |
+
};
|
28 |
+
|
29 |
+
export default platform;
|
backend/provider/lepton.ts
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { BaseChat } from './base/base';
|
2 |
+
import OpenAI from 'openai';
|
3 |
+
import util from 'util';
|
4 |
+
import { IChatInputMessage, IStreamHandler } from '../interface';
|
5 |
+
import { DefaultSystem } from '../utils/constant';
|
6 |
+
|
7 |
+
const BASE_URLS = 'https://%s.lepton.run/api/v1';
|
8 |
+
|
9 |
+
export class LeptonChat implements BaseChat {
|
10 |
+
private key: string;
|
11 |
+
private openai: OpenAI | null;
|
12 |
+
public platform = 'lepton';
|
13 |
+
|
14 |
+
constructor() {
|
15 |
+
this.key = process.env.LEPTON_KEY || '';
|
16 |
+
if (this.key) {
|
17 |
+
this.openai = new OpenAI({
|
18 |
+
apiKey: this.key
|
19 |
+
});
|
20 |
+
} else {
|
21 |
+
this.openai = null;
|
22 |
+
}
|
23 |
+
console.log('[Lepton AI loaded]');
|
24 |
+
}
|
25 |
+
|
26 |
+
async chatStream(
|
27 |
+
messages: IChatInputMessage[],
|
28 |
+
onMessage: IStreamHandler,
|
29 |
+
model: string,
|
30 |
+
system = DefaultSystem
|
31 |
+
): Promise<void> {
|
32 |
+
if (!this.openai) throw new Error('Lepton AI: Key is Required.');
|
33 |
+
const url = this.getBaseURL(model);
|
34 |
+
this.openai.baseURL = url;
|
35 |
+
if (system) messages.unshift({ role: 'system', content: system });
|
36 |
+
const stream = await this.openai.chat.completions.create({
|
37 |
+
messages,
|
38 |
+
model,
|
39 |
+
stream: true
|
40 |
+
});
|
41 |
+
for await (const chunk of stream) {
|
42 |
+
if (chunk.choices[0]) onMessage?.(chunk.choices[0].delta.content || null, false);
|
43 |
+
}
|
44 |
+
onMessage?.(null, true);
|
45 |
+
}
|
46 |
+
|
47 |
+
private getBaseURL(model: string) {
|
48 |
+
// Mixtral-8*7b -> mixtral-8x7b
|
49 |
+
return util.format(BASE_URLS, model).replace('*', 'x').toLowerCase();
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
export const lepton = new LeptonChat();
|
backend/provider/lmstudio.ts
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { DefaultSystem } from '../utils/constant';
|
2 |
+
import { IChatInputMessage, IStreamHandler } from '../interface';
|
3 |
+
import { BaseChat } from './base/base';
|
4 |
+
import { LMStudioClient } from '@lmstudio/sdk';
|
5 |
+
|
6 |
+
const host = process.env.OLLAMA_HOST || 'localhost:1234';
|
7 |
+
const lmstudioClient = new LMStudioClient({
|
8 |
+
baseUrl: `ws://${host}`
|
9 |
+
});
|
10 |
+
/**
|
11 |
+
* run large language models locally with LMStudio.
|
12 |
+
*/
|
13 |
+
export class LMStudioChat implements BaseChat {
|
14 |
+
public platform = 'lmstudio';
|
15 |
+
|
16 |
+
public async chat(
|
17 |
+
messages: IChatInputMessage[],
|
18 |
+
model = 'lmstudio-community/Meta-Llama-3.1-8B-Instruct-GGUF',
|
19 |
+
system = DefaultSystem
|
20 |
+
): Promise<string | null> {
|
21 |
+
if (system) {
|
22 |
+
messages.unshift({
|
23 |
+
role: 'system',
|
24 |
+
content: system
|
25 |
+
});
|
26 |
+
}
|
27 |
+
|
28 |
+
const llama3 = await lmstudioClient.llm.load(model);
|
29 |
+
const response = await llama3.respond(messages);
|
30 |
+
|
31 |
+
return response.content;
|
32 |
+
}
|
33 |
+
|
34 |
+
public async chatStream(
|
35 |
+
messages: IChatInputMessage[],
|
36 |
+
onMessage: IStreamHandler,
|
37 |
+
model = 'llama2',
|
38 |
+
system = DefaultSystem
|
39 |
+
): Promise<void> {
|
40 |
+
if (system) {
|
41 |
+
messages.unshift({
|
42 |
+
role: 'system',
|
43 |
+
content: system
|
44 |
+
});
|
45 |
+
}
|
46 |
+
const llama3 = await lmstudioClient.llm.load(model);
|
47 |
+
|
48 |
+
const response = llama3.respond(messages);
|
49 |
+
|
50 |
+
for await (const chunk of response) {
|
51 |
+
onMessage?.(chunk, false);
|
52 |
+
}
|
53 |
+
onMessage?.(null, true);
|
54 |
+
}
|
55 |
+
|
56 |
+
public async list() {
|
57 |
+
const models = await lmstudioClient.llm.listLoaded();
|
58 |
+
if (models.length === 0) return Promise.reject('No models loaded.');
|
59 |
+
return {
|
60 |
+
models: models.map((x: any) => {
|
61 |
+
return {
|
62 |
+
name: x.identifier
|
63 |
+
};
|
64 |
+
})
|
65 |
+
};
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
export const lmstudio = new LMStudioChat();
|
backend/provider/moonshot.ts
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { BaseOpenAIChat } from './base/openai';
|
2 |
+
const baseURL = 'https://api.moonshot.cn/v1';
|
3 |
+
|
4 |
+
export const moonshot = new BaseOpenAIChat('moonshot', process.env.MOONSHOT_KEY, baseURL);
|
backend/provider/ollama.ts
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { DefaultSystem } from '../utils/constant';
|
2 |
+
import { IChatInputMessage, IStreamHandler } from '../interface';
|
3 |
+
import { BaseChat } from './base/base';
|
4 |
+
import { Ollama } from 'ollama';
|
5 |
+
|
6 |
+
const host = process.env.OLLAMA_HOST || 'http://localhost:11434';
|
7 |
+
const ollamaClient = new Ollama({
|
8 |
+
host
|
9 |
+
});
|
10 |
+
/**
|
11 |
+
* run large language models locally with Ollama.
|
12 |
+
*/
|
13 |
+
export class OllamaChat implements BaseChat {
|
14 |
+
public platform = 'ollama';
|
15 |
+
|
16 |
+
public async chat(
|
17 |
+
messages: IChatInputMessage[],
|
18 |
+
model = 'llama2',
|
19 |
+
system = DefaultSystem
|
20 |
+
): Promise<string | null> {
|
21 |
+
if (system) {
|
22 |
+
messages.unshift({
|
23 |
+
role: 'system',
|
24 |
+
content: system
|
25 |
+
});
|
26 |
+
}
|
27 |
+
const response = await ollamaClient.chat({
|
28 |
+
model,
|
29 |
+
messages
|
30 |
+
});
|
31 |
+
return response.message.content;
|
32 |
+
}
|
33 |
+
|
34 |
+
public async chatStream(
|
35 |
+
messages: IChatInputMessage[],
|
36 |
+
onMessage: IStreamHandler,
|
37 |
+
model = 'llama2',
|
38 |
+
system = DefaultSystem
|
39 |
+
): Promise<void> {
|
40 |
+
if (system) {
|
41 |
+
messages.unshift({
|
42 |
+
role: 'system',
|
43 |
+
content: system
|
44 |
+
});
|
45 |
+
}
|
46 |
+
const response = await ollamaClient.chat({
|
47 |
+
model,
|
48 |
+
stream: true,
|
49 |
+
messages,
|
50 |
+
});
|
51 |
+
|
52 |
+
for await (const chunk of response) {
|
53 |
+
onMessage?.(chunk.message.content, false);
|
54 |
+
}
|
55 |
+
onMessage?.(null, true);
|
56 |
+
}
|
57 |
+
|
58 |
+
public async list() {
|
59 |
+
return ollamaClient.list();
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
export const ollama = new OllamaChat();
|
backend/provider/openai.ts
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { BaseOpenAIChat } from './base/openai';
|
2 |
+
|
3 |
+
const ApiKey = process.env.OPENAI_KEY;
|
4 |
+
const BaseURL = process.env.OPENAI_PROXY_URL;
|
5 |
+
|
6 |
+
export const openai = new BaseOpenAIChat('openai', ApiKey, BaseURL);
|
backend/provider/tencent.ts
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import * as tencentcloud from 'tencentcloud-sdk-nodejs';
|
2 |
+
import { ClientConfig } from 'tencentcloud-sdk-nodejs/tencentcloud/common/interface';
|
3 |
+
import { Client } from 'tencentcloud-sdk-nodejs/tencentcloud/services/hunyuan/v20230901/hunyuan_client';
|
4 |
+
import { ChatStdResponse } from 'tencentcloud-sdk-nodejs/tencentcloud/services/hunyuan/v20230901/hunyuan_models';
|
5 |
+
import { BaseChat } from './base/base';
|
6 |
+
import { IChatInputMessage, IStreamHandler } from '../interface';
|
7 |
+
import { DefaultSystem } from '../utils/constant';
|
8 |
+
|
9 |
+
export class TencentChat implements BaseChat {
|
10 |
+
private client: Client;
|
11 |
+
public platform = 'tencent';
|
12 |
+
|
13 |
+
constructor() {
|
14 |
+
const key = process.env.TENCENT_KEY;
|
15 |
+
const secret = process.env.TENCENT_SECRET;
|
16 |
+
const config: ClientConfig = {
|
17 |
+
credential: {
|
18 |
+
secretId: key,
|
19 |
+
secretKey: secret
|
20 |
+
},
|
21 |
+
region: '',
|
22 |
+
profile: {
|
23 |
+
httpProfile: {
|
24 |
+
endpoint: 'hunyuan.tencentcloudapi.com'
|
25 |
+
}
|
26 |
+
}
|
27 |
+
};
|
28 |
+
this.client = new tencentcloud.hunyuan.v20230901.Client(config);
|
29 |
+
}
|
30 |
+
|
31 |
+
async chatStream(
|
32 |
+
messages: IChatInputMessage[],
|
33 |
+
onMessage: IStreamHandler,
|
34 |
+
model: string,
|
35 |
+
system = DefaultSystem
|
36 |
+
): Promise<void> {
|
37 |
+
const Messages = this.transformMessage(messages);
|
38 |
+
console.log(model);
|
39 |
+
if (system) {
|
40 |
+
Messages.unshift({
|
41 |
+
Role: 'system',
|
42 |
+
Content: system
|
43 |
+
});
|
44 |
+
}
|
45 |
+
const result: any = await this.client.ChatStd({
|
46 |
+
Messages
|
47 |
+
});
|
48 |
+
return new Promise((resolve) => {
|
49 |
+
result.on('message', (res: any) => {
|
50 |
+
const data: ChatStdResponse = JSON.parse(res.data ?? '{}');
|
51 |
+
const text = data.Choices?.[0].Delta?.Content || '';
|
52 |
+
const stop = data.Choices?.[0].FinishReason === 'stop' ? true : false;
|
53 |
+
onMessage?.(text, stop);
|
54 |
+
if (stop) resolve();
|
55 |
+
});
|
56 |
+
});
|
57 |
+
}
|
58 |
+
|
59 |
+
private transformMessage(messages: IChatInputMessage[]) {
|
60 |
+
return messages.map(msg => {
|
61 |
+
return {
|
62 |
+
Role: msg.role,
|
63 |
+
Content: msg.content
|
64 |
+
};
|
65 |
+
});
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
export const tencent = new TencentChat();
|
backend/provider/yi.ts
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { BaseOpenAIChat } from './base/openai';
|
2 |
+
|
3 |
+
const baseURL = 'https://api.lingyiwanwu.com/v1';
|
4 |
+
const key = process.env.YI_KEY;
|
5 |
+
|
6 |
+
|
7 |
+
export const yi = new BaseOpenAIChat('yi', key, baseURL);
|
backend/rag/index.ts
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ESearchEngine, IChatInputMessage, IStreamHandler, Provider, SearchFunc, TMode } from '../interface';
|
2 |
+
import { searchWithBing, searchWithGoogle, searchWithSogou, searchWithSearXNG, searchWithChatGLM } from '../service';
|
3 |
+
import { DeepQueryPrompt, MoreQuestionsPrompt, RagQueryPrompt, TranslatePrompt } from './prompt';
|
4 |
+
import platform from '../provider';
|
5 |
+
import { Models } from '../utils/constant';
|
6 |
+
import { ESearXNGCategory } from '../search/searxng';
|
7 |
+
import util from 'util';
|
8 |
+
|
9 |
+
interface RagOptions {
|
10 |
+
engine?: ESearchEngine
|
11 |
+
stream?: boolean
|
12 |
+
model?: string
|
13 |
+
// use local llm?
|
14 |
+
locally?: boolean
|
15 |
+
provider?: Provider
|
16 |
+
}
|
17 |
+
|
18 |
+
// const CACHE_NAME = 'search_with_ai';
|
19 |
+
|
20 |
+
export class Rag {
|
21 |
+
private search: SearchFunc;
|
22 |
+
private chat: (...args: any[]) => Promise<any>;
|
23 |
+
private model: string;
|
24 |
+
// enable stream?
|
25 |
+
private stream: boolean;
|
26 |
+
// search engine
|
27 |
+
private engine: ESearchEngine;
|
28 |
+
|
29 |
+
constructor(params?: RagOptions) {
|
30 |
+
const { engine = ESearchEngine.SEARXNG, stream = true, model, locally, provider } = params || {};
|
31 |
+
if (!model) throw new Error('model is required');
|
32 |
+
if (locally && provider) {
|
33 |
+
this.chat = platform[provider].chatStream.bind(platform[provider]);
|
34 |
+
} else {
|
35 |
+
const chat = processModel(model);
|
36 |
+
if (!chat) throw new Error('model is not supported');
|
37 |
+
this.chat = chat;
|
38 |
+
}
|
39 |
+
this.model = model;
|
40 |
+
this.stream = stream;
|
41 |
+
console.info('[query with]:', engine, model);
|
42 |
+
console.info('[query with local llm]:', locally);
|
43 |
+
this.engine = engine;
|
44 |
+
switch (engine) {
|
45 |
+
case ESearchEngine.GOOGLE:
|
46 |
+
this.search = searchWithGoogle;
|
47 |
+
break;
|
48 |
+
case ESearchEngine.BING:
|
49 |
+
this.search = searchWithBing;
|
50 |
+
break;
|
51 |
+
case ESearchEngine.SOGOU:
|
52 |
+
this.search = searchWithSogou;
|
53 |
+
break;
|
54 |
+
case ESearchEngine.SEARXNG:
|
55 |
+
this.search = searchWithSearXNG;
|
56 |
+
break;
|
57 |
+
case ESearchEngine.CHATGLM:
|
58 |
+
this.search = searchWithChatGLM;
|
59 |
+
break;
|
60 |
+
default:
|
61 |
+
this.search = searchWithSearXNG;
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
public async query(query: string, categories = [ESearXNGCategory.GENERAL], mode: TMode = 'simple', language = 'all', onMessage?: (...args: any[]) => void) {
|
66 |
+
let searchQuery = query;
|
67 |
+
// rewrite query for [SCIENCE]
|
68 |
+
if (categories.includes(ESearXNGCategory.SCIENCE) && this.engine === ESearchEngine.SEARXNG) {
|
69 |
+
const rewrite = await this.translate(query);
|
70 |
+
if (rewrite) searchQuery = rewrite;
|
71 |
+
}
|
72 |
+
|
73 |
+
// Parameters supported by searxng: categories.
|
74 |
+
const contexts = await this.search(searchQuery, categories, language);
|
75 |
+
console.log(`[search [${categories}] results]`, contexts.length);
|
76 |
+
console.log('[search mode]', mode);
|
77 |
+
const REFERENCE_COUNT = process.env.REFERENCE_COUNT || 8;
|
78 |
+
const limitContexts = contexts.slice(0, +REFERENCE_COUNT);
|
79 |
+
if (!this.stream) {
|
80 |
+
const relatedPromise = this.getRelatedQuestions(query, limitContexts);
|
81 |
+
const answerPromise = this.getAiAnswer(query, contexts);
|
82 |
+
const [related, answer] = await Promise.all([relatedPromise, answerPromise]);
|
83 |
+
return {
|
84 |
+
related,
|
85 |
+
answer,
|
86 |
+
contexts: limitContexts
|
87 |
+
};
|
88 |
+
}
|
89 |
+
// searxng images search
|
90 |
+
if (this.engine === ESearchEngine.SEARXNG) {
|
91 |
+
const res = await this.search(query, [ESearXNGCategory.IMAGES], language);
|
92 |
+
const engines = process.env.SEARXNG_IMAGES_ENGINES ? process.env.SEARXNG_IMAGES_ENGINES.split(',') : [];
|
93 |
+
|
94 |
+
const images = res.filter(item => {
|
95 |
+
if (!item.thumbnail) return false;
|
96 |
+
if (engines.length > 0)
|
97 |
+
return engines.some(engine => item.engine?.includes(engine));
|
98 |
+
return item.engine?.includes('bing') || item.engine?.includes('google');
|
99 |
+
});
|
100 |
+
|
101 |
+
for (const image of images) {
|
102 |
+
onMessage?.(JSON.stringify({ image }));
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
for (const context of limitContexts) {
|
107 |
+
onMessage?.(JSON.stringify({ context }));
|
108 |
+
}
|
109 |
+
await this.getAiAnswer(query, limitContexts, mode, (msg) => {
|
110 |
+
onMessage?.(JSON.stringify({ answer: msg }));
|
111 |
+
});
|
112 |
+
await this.getRelatedQuestions(query, limitContexts, (msg) => {
|
113 |
+
onMessage?.(JSON.stringify({ related: msg }));
|
114 |
+
});
|
115 |
+
onMessage?.(null, true);
|
116 |
+
}
|
117 |
+
|
118 |
+
// Gets related questions based on the query and context.
|
119 |
+
private async getRelatedQuestions(query: string, contexts: any[], onMessage?: IStreamHandler) {
|
120 |
+
try {
|
121 |
+
const { messages } = this.paramsFormatter(query, undefined, contexts, 'related');
|
122 |
+
const { model, stream } = this;
|
123 |
+
if (!stream) {
|
124 |
+
const res = await this.chat(messages, this.model);
|
125 |
+
return res.split('\n');
|
126 |
+
}
|
127 |
+
await this.chat(messages, onMessage, model);
|
128 |
+
} catch (err) {
|
129 |
+
console.error('[LLM Error]:', err);
|
130 |
+
return [];
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
private async getAiAnswer(query: string, contexts: any[], mode: TMode = 'simple', onMessage?: IStreamHandler) {
|
135 |
+
const { model, stream } = this;
|
136 |
+
try {
|
137 |
+
const { messages } = this.paramsFormatter(query, mode, contexts, 'answer');
|
138 |
+
if (!stream) {
|
139 |
+
const res = await this.chat(messages, this.model);
|
140 |
+
return res;
|
141 |
+
}
|
142 |
+
await this.chat(messages, (msg: string, done: boolean) => {
|
143 |
+
onMessage?.(msg, done);
|
144 |
+
}, model);
|
145 |
+
} catch (err: any) {
|
146 |
+
console.error('[LLM Error]:', err);
|
147 |
+
const msg = `[Oops~ Some errors seem to have occurred]: ${err?.message || 'Please check the console'}`;
|
148 |
+
if (!stream) return msg;
|
149 |
+
else onMessage?.(msg, true);
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
// translate
|
154 |
+
private async translate(text: string, targetLang = 'English'): Promise<string> {
|
155 |
+
try {
|
156 |
+
const content = util.format(TranslatePrompt, targetLang, text);
|
157 |
+
const messages: IChatInputMessage[] = [
|
158 |
+
{
|
159 |
+
role: 'user',
|
160 |
+
content
|
161 |
+
}
|
162 |
+
];
|
163 |
+
// console.log(content);
|
164 |
+
let translated = '';
|
165 |
+
if (!this.stream) {
|
166 |
+
const res = await this.chat(messages, this.model);
|
167 |
+
translated = res;
|
168 |
+
} else {
|
169 |
+
await this.chat(messages, (msg: string) => {
|
170 |
+
if (msg) translated += msg;
|
171 |
+
}, this.model);
|
172 |
+
}
|
173 |
+
return translated;
|
174 |
+
} catch (err) {
|
175 |
+
console.log('[RAG Translate error]', err);
|
176 |
+
return text;
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
private paramsFormatter(query: string, mode: TMode = 'simple', contexts: any[], type: 'answer' | 'related') {
|
181 |
+
const context = contexts.map((item, index) => `[[citation:${index + 1}]] ${item.snippet}`).join('\n\n');
|
182 |
+
let prompt = type === 'answer' ? RagQueryPrompt : MoreQuestionsPrompt;
|
183 |
+
|
184 |
+
// deep answer
|
185 |
+
if (mode === 'deep' && type === 'answer') {
|
186 |
+
prompt = DeepQueryPrompt;
|
187 |
+
}
|
188 |
+
|
189 |
+
const system = util.format(prompt, context);
|
190 |
+
const messages: IChatInputMessage[] = [
|
191 |
+
{
|
192 |
+
role: 'user',
|
193 |
+
content: `${system} ${query}`
|
194 |
+
}
|
195 |
+
];
|
196 |
+
return {
|
197 |
+
messages
|
198 |
+
};
|
199 |
+
}
|
200 |
+
}
|
201 |
+
|
202 |
+
function processModel(model: string) {
|
203 |
+
const targetModel = Models.find(item => {
|
204 |
+
return item.models.includes(model);
|
205 |
+
});
|
206 |
+
if (targetModel?.platform) {
|
207 |
+
const target = platform[targetModel.platform];
|
208 |
+
return target.chatStream.bind(target);
|
209 |
+
}
|
210 |
+
}
|
backend/rag/prompt.ts
ADDED
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* This is really the most important part of the rag model. It gives instructions
|
3 |
+
* to the model on how to generate the answer. Of course, different models may
|
4 |
+
* behave differently, and we haven't tuned the prompt to make it optimal - this
|
5 |
+
* is left to you, application creators, as an open problem.
|
6 |
+
*/
|
7 |
+
export const RagQueryPrompt = `
|
8 |
+
You are a large language AI assistant built by iSOU AI Search. You are given a user question, and please write clean, concise and accurate answer to the question. You will be given a set of related contexts to the question, each starting with a reference number like [[citation:x]], where x is a number. Please use the context and cite the context at the end of each sentence if applicable.
|
9 |
+
|
10 |
+
Your answer must be correct, accurate and written by an expert using an unbiased and professional tone. Please limit to 1024 tokens. Do not give any information that is not related to the question, and do not repeat. Say "information is missing on" followed by the related topic, if the given context do not provide sufficient information.
|
11 |
+
|
12 |
+
Please cite the contexts with the reference numbers, in the format [[citation:x]]. If a sentence comes from multiple contexts, please list all applicable citations, like [[citation:3]][[citation:5]]. Other than code and specific names and citations.
|
13 |
+
|
14 |
+
NEVER write URLs or links. Here are the set of contexts:
|
15 |
+
|
16 |
+
%s
|
17 |
+
|
18 |
+
Remember, don't blindly repeat the contexts verbatim. Your answer must be written in the same language as the user question, For example, if the user question is written in chinese, your answer should be written in chinese too, if user's question is written in english, your answer should be written in english too.
|
19 |
+
|
20 |
+
Today's date is ${new Date().toISOString()}, And here is the user question:
|
21 |
+
`;
|
22 |
+
|
23 |
+
export const DeepQueryPrompt = `
|
24 |
+
# Assistant Background
|
25 |
+
|
26 |
+
You are iSOU AI Search Engine , a helpful search assistant trained by iSOU AI.
|
27 |
+
|
28 |
+
# General Instructions
|
29 |
+
|
30 |
+
Write an accurate, detailed, and comprehensive response to the user''s INITIAL_QUERY.
|
31 |
+
Additional context is provided as "USER_INPUT" after specific questions.
|
32 |
+
Your answer should be informed by the provided "Search results".
|
33 |
+
Your answer must be as detailed and organized as possible, Prioritize the use of lists, tables, and quotes to organize output structures.
|
34 |
+
Your answer must be precise, of high-quality, and written by an expert using an unbiased and journalistic tone.
|
35 |
+
|
36 |
+
You MUST cite the most relevant search results that answer the question. Do not mention any irrelevant results.
|
37 |
+
You MUST ADHERE to the following instructions for citing search results:
|
38 |
+
- each starting with a reference number like [[citation:x]], where x is a number.
|
39 |
+
- to cite a search result, enclose its index located above the summary with double brackets at the end of the corresponding sentence, for example "Ice is less dense than water.[[citation:3]]" or "Paris is the capital of France.[[citation:5]]"
|
40 |
+
- NO SPACE between the last word and the citation, and ALWAYS use double brackets. Only use this format to cite search results. NEVER include a References section at the end of your answer.
|
41 |
+
- If you don't know the answer or the premise is incorrect, explain why.
|
42 |
+
If the search results are empty or unhelpful, answer the question as well as you can with existing knowledge.
|
43 |
+
|
44 |
+
You MUST ADHERE to the following formatting instructions:
|
45 |
+
- Use markdown to format paragraphs, lists, tables, and quotes whenever possible.
|
46 |
+
- Use headings level 4 to separate sections of your response, like "#### Header", but NEVER start an answer with a heading or title of any kind.
|
47 |
+
- Use single new lines for lists and double new lines for paragraphs.
|
48 |
+
- Use markdown to render images given in the search results.
|
49 |
+
- NEVER write URLs or links.
|
50 |
+
|
51 |
+
# Query type specifications
|
52 |
+
|
53 |
+
You must use different instructions to write your answer based on the type of the user's query. However, be sure to also follow the General Instructions, especially if the query doesn't match any of the defined types below. Here are the supported types.
|
54 |
+
|
55 |
+
## Academic Research
|
56 |
+
|
57 |
+
You must provide long and detailed answers for academic research queries.
|
58 |
+
Your answer should be formatted as a scientific write-up, with paragraphs and sections, using markdown and headings.
|
59 |
+
|
60 |
+
## People
|
61 |
+
|
62 |
+
You need to write a short biography for the person mentioned in the query.
|
63 |
+
If search results refer to different people, you MUST describe each person individually and AVOID mixing their information together.
|
64 |
+
NEVER start your answer with the person's name as a header.
|
65 |
+
|
66 |
+
## Coding
|
67 |
+
|
68 |
+
You MUST use markdown code blocks to write code, specifying the language for syntax highlighting, for example: bash or python
|
69 |
+
If the user's query asks for code, you should write the code first and then explain it.
|
70 |
+
|
71 |
+
## Science and Math
|
72 |
+
|
73 |
+
If the user query is about some simple calculation, only answer with the final result.
|
74 |
+
Follow these rules for writing formulas:
|
75 |
+
- Always use $$ and$$ for inline formulas and$$ and$$ for blocks, for example$$x^4 = x - 3 $$
|
76 |
+
- To cite a formula add citations to the end, for example$$ sin(x) $$ or $$x^2-2$$ .
|
77 |
+
- Never use $ or $$ to render LaTeX, even if it is present in the user query.
|
78 |
+
- Never use unicode to render math expressions, ALWAYS use LaTeX.
|
79 |
+
- Never use the label instruction for LaTeX.
|
80 |
+
|
81 |
+
## Cooking Recipes
|
82 |
+
|
83 |
+
You need to provide step-by-step cooking recipes, clearly specifying the ingredient, the amount, and precise instructions during each step.
|
84 |
+
|
85 |
+
## Creative Writing
|
86 |
+
|
87 |
+
If the query requires creative writing, you DO NOT need to use or cite search results, and you may ignore General Instructions pertaining only to search. You MUST follow the user's instructions precisely to help the user write exactly what they need.
|
88 |
+
|
89 |
+
# USER_INPUT
|
90 |
+
|
91 |
+
## Search results
|
92 |
+
|
93 |
+
Here are the set of search results:
|
94 |
+
|
95 |
+
%s
|
96 |
+
|
97 |
+
## User's INITIAL_QUERY
|
98 |
+
|
99 |
+
Your answer MUST be written in the same language as the user question, For example, if the user question is written in chinese, your answer should be written in chinese too, if user's question is written in english, your answer should be written in english too.
|
100 |
+
Today's date is ${new Date().toISOString()}, And here is the user's INITIAL_QUERY:
|
101 |
+
`;
|
102 |
+
|
103 |
+
export const MoreQuestionsPrompt = `
|
104 |
+
## Character
|
105 |
+
|
106 |
+
You help the user to output 3 related questions, based on user's original question and the related contexts. You need identify worthwhile topics that can be follow-ups, and write questions no longer than 20 words each. Please make sure that specifics, like events, names, locations, are included in follow up questions so they can be asked standalone. For example, if the user's original question asks about "the Manhattan project", in the follow up question, do not just say "the project", but use the full name "the Manhattan project".
|
107 |
+
|
108 |
+
## Contexts
|
109 |
+
|
110 |
+
Here are the contexts of the question:
|
111 |
+
|
112 |
+
%s
|
113 |
+
|
114 |
+
## Rules
|
115 |
+
|
116 |
+
- based on the user's original question and related contexts, suggest 3 such further questions.
|
117 |
+
- DO NOT repeat user's original question.
|
118 |
+
- DO NOT cite user's original question and Contexts.
|
119 |
+
- DO NOT output any irrelevant content, like: 'Here are three related questions', 'Base on your original question'.
|
120 |
+
- Each related question should be no longer than 40 tokens.
|
121 |
+
- You must write in the same language as the user's origin question.
|
122 |
+
|
123 |
+
## Output Format
|
124 |
+
|
125 |
+
{{serial number}}. {{related question}}.
|
126 |
+
|
127 |
+
## Example Output
|
128 |
+
|
129 |
+
### Example 1: User's question is written in English, Need to output in English.
|
130 |
+
|
131 |
+
User: what is rust?
|
132 |
+
|
133 |
+
Assistant:
|
134 |
+
1. What is the history of rust?
|
135 |
+
2. What are the characteristics of rust?
|
136 |
+
3. What are the applications of rust?
|
137 |
+
|
138 |
+
### Example 2: User's question is written in Chinese, 需要用中文输出.
|
139 |
+
|
140 |
+
User: 什么是rust?
|
141 |
+
|
142 |
+
Assistant:
|
143 |
+
1. 在rust中什么是所有权?
|
144 |
+
2. rust语言和c语言有什么区别?
|
145 |
+
3. 怎么学习rust编程语言?
|
146 |
+
|
147 |
+
## Original Question
|
148 |
+
|
149 |
+
Here is the user's original question:
|
150 |
+
`;
|
151 |
+
|
152 |
+
export const TranslatePrompt = `
|
153 |
+
You are a professional translation expert, adept at accurately translating source language text into the target language. Please adhere to the following requirements:
|
154 |
+
1. **Faithful Accuracy**: Ensure the translated content is completely faithful to the original text, without adding, omitting, or altering the meaning.
|
155 |
+
2. **Fluent Language**: The translation should be natural and fluent, aligning with the target language's idiomatic expressions.
|
156 |
+
3. **Consistent Terminology**: Maintain consistency in specialized terms, using the recognized translations in the target language.
|
157 |
+
4. **Cultural Sensitivity**: Be mindful of cultural differences to avoid misunderstandings.
|
158 |
+
5. **Contextual Understanding**: Understand the context of the original text and provide the most appropriate translation based on it.
|
159 |
+
6. **Conciseness**: Directly return the translated content without any additional information.
|
160 |
+
|
161 |
+
Please translate the following text to %s:
|
162 |
+
%s
|
163 |
+
`;
|
backend/search/chatglm.ts
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* 来自智谱的搜索接口,标准版和专业版,标准版没有直接接口[免费,并发100]
|
3 |
+
* Web-Search-Pro 专业版联网搜索[付费,并发1~5]
|
4 |
+
* 利用glm-4-flash 免费模型,免费web-search 实现免费搜索
|
5 |
+
* @reference https://bigmodel.cn/dev/api/search-tool/web-search-pro
|
6 |
+
*/
|
7 |
+
|
8 |
+
const BASE_URL = 'https://open.bigmodel.cn/api/paas/v4';
|
9 |
+
const KEY = process.env.GLM_KEY;
|
10 |
+
|
11 |
+
export interface IWebSearchResult {
|
12 |
+
index: number;
|
13 |
+
icon: string;
|
14 |
+
title: string;
|
15 |
+
link: string;
|
16 |
+
content: string;
|
17 |
+
media: string;
|
18 |
+
refer: string;
|
19 |
+
[x: string]: any;
|
20 |
+
}
|
21 |
+
|
22 |
+
export async function webSearch(query: string): Promise<IWebSearchResult[]> {
|
23 |
+
const tools = [
|
24 |
+
{
|
25 |
+
type: 'web_search',
|
26 |
+
web_search: {
|
27 |
+
enable: true,
|
28 |
+
search_result: true,
|
29 |
+
search_query: query,
|
30 |
+
},
|
31 |
+
},
|
32 |
+
];
|
33 |
+
const msg = [
|
34 |
+
{
|
35 |
+
role: 'user',
|
36 |
+
content: 'hi',
|
37 |
+
},
|
38 |
+
];
|
39 |
+
|
40 |
+
try {
|
41 |
+
const baseUrl = `${BASE_URL}/chat/completions`;
|
42 |
+
const res = await fetch(baseUrl, {
|
43 |
+
method: 'POST',
|
44 |
+
headers: {
|
45 |
+
'Content-Type': 'application/json',
|
46 |
+
Authorization: `Bearer ${KEY}`,
|
47 |
+
},
|
48 |
+
body: JSON.stringify({
|
49 |
+
model: 'glm-4-flash',
|
50 |
+
messages: msg,
|
51 |
+
stream: false,
|
52 |
+
tools,
|
53 |
+
}),
|
54 |
+
});
|
55 |
+
|
56 |
+
const data = await res.json();
|
57 |
+
return data?.web_search ?? [];
|
58 |
+
} catch (error) {
|
59 |
+
console.error(error);
|
60 |
+
return [];
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
export async function webSearchPro(query: string): Promise<IWebSearchResult[]> {
|
65 |
+
const tool = 'web-search-pro';
|
66 |
+
const msg = [
|
67 |
+
{
|
68 |
+
role: 'user',
|
69 |
+
content: query,
|
70 |
+
},
|
71 |
+
];
|
72 |
+
|
73 |
+
try {
|
74 |
+
const baseUrl = `${BASE_URL}/tools`;
|
75 |
+
const res = await fetch(baseUrl, {
|
76 |
+
method: 'POST',
|
77 |
+
headers: {
|
78 |
+
'Content-Type': 'application/json',
|
79 |
+
Authorization: `Bearer ${KEY}`,
|
80 |
+
},
|
81 |
+
body: JSON.stringify({
|
82 |
+
messages: msg,
|
83 |
+
stream: false,
|
84 |
+
tool,
|
85 |
+
}),
|
86 |
+
});
|
87 |
+
|
88 |
+
const data = await res.json();
|
89 |
+
const result = data.choices[0]?.message?.tool_calls;
|
90 |
+
return result?.[0] ?? [];
|
91 |
+
} catch (error) {
|
92 |
+
console.error(error);
|
93 |
+
return [];
|
94 |
+
}
|
95 |
+
}
|
backend/search/searxng.ts
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { httpRequest } from '../utils/utils';
|
2 |
+
import { ISearchResponseResult } from '../interface';
|
3 |
+
|
4 |
+
const URL = process.env.SEARXNG_HOSTNAME || 'http://localhost:8080';
|
5 |
+
|
6 |
+
// https://docs.searxng.org/dev/search_api.html
|
7 |
+
export interface ISearXNGOptions {
|
8 |
+
q: string;
|
9 |
+
pageno?: number;
|
10 |
+
categories?: ESearXNGCategory[];
|
11 |
+
language?: string;
|
12 |
+
engines?: string;
|
13 |
+
}
|
14 |
+
|
15 |
+
export enum ESearXNGCategory {
|
16 |
+
SCIENCE = 'science',
|
17 |
+
IT = 'it',
|
18 |
+
GENERAL = 'general',
|
19 |
+
IMAGES = 'images',
|
20 |
+
VIDEOS = 'videos',
|
21 |
+
NEWS = 'news',
|
22 |
+
MUSIC = 'music'
|
23 |
+
}
|
24 |
+
|
25 |
+
export default async function search(params: ISearXNGOptions): Promise<ISearchResponseResult[]> {
|
26 |
+
try {
|
27 |
+
const { q, pageno = 1, categories = [ESearXNGCategory.GENERAL], engines = '', language = 'all' } = params;
|
28 |
+
console.log('searxng language', language);
|
29 |
+
const safesearch = process.env.SEARXNG_SAFE ?? 0;
|
30 |
+
const res = await httpRequest({
|
31 |
+
endpoint: `${URL}/search`,
|
32 |
+
method: 'POST',
|
33 |
+
query: {
|
34 |
+
q,
|
35 |
+
pageno,
|
36 |
+
categories: categories.join(','),
|
37 |
+
format: 'json',
|
38 |
+
safesearch,
|
39 |
+
language,
|
40 |
+
engines
|
41 |
+
}
|
42 |
+
});
|
43 |
+
const result = await res.json();
|
44 |
+
if (result.results) {
|
45 |
+
return result.results.map((item: any, index: number) => {
|
46 |
+
return {
|
47 |
+
id: index + 1,
|
48 |
+
name: item.title,
|
49 |
+
url: item.url,
|
50 |
+
source: item.source,
|
51 |
+
img: item.img_src,
|
52 |
+
thumbnail: item.thumbnail_src,
|
53 |
+
snippet: item.content,
|
54 |
+
engine: item.engine
|
55 |
+
};
|
56 |
+
});
|
57 |
+
}
|
58 |
+
return [];
|
59 |
+
} catch (err) {
|
60 |
+
return [];
|
61 |
+
}
|
62 |
+
}
|
backend/search/sogou.ts
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import * as cheerio from 'cheerio';
|
2 |
+
import { httpRequest } from '../utils/utils';
|
3 |
+
|
4 |
+
const EndPoints = {
|
5 |
+
WEB: 'https://www.sogou.com/web',
|
6 |
+
LINK: 'https://www.sogou.com/'
|
7 |
+
};
|
8 |
+
|
9 |
+
const SELECTOR = {
|
10 |
+
results: '#main .results',
|
11 |
+
resultTitle: '.vr-title',
|
12 |
+
resultLink: '.vr-title > a',
|
13 |
+
resultSnippet: ['.star-wiki', '.fz-mid', '.attribute-centent'],
|
14 |
+
resultSnippetExcluded: ['.text-lightgray', '.zan-box', '.tag-website'],
|
15 |
+
related: '#main .vrwrap.middle-better-hintBox .hint-mid'
|
16 |
+
};
|
17 |
+
|
18 |
+
export class Sogou {
|
19 |
+
private query: string;
|
20 |
+
private $: cheerio.CheerioAPI;
|
21 |
+
|
22 |
+
constructor(query: string) {
|
23 |
+
this.query = query;
|
24 |
+
}
|
25 |
+
|
26 |
+
async init() {
|
27 |
+
const res = await this.search(this.query);
|
28 |
+
this.$ = cheerio.load(res);
|
29 |
+
}
|
30 |
+
|
31 |
+
private async search(query: string) {
|
32 |
+
try {
|
33 |
+
const res = await httpRequest({
|
34 |
+
endpoint: EndPoints.WEB,
|
35 |
+
query: {
|
36 |
+
query,
|
37 |
+
}
|
38 |
+
});
|
39 |
+
const result = await res.text();
|
40 |
+
return result;
|
41 |
+
} catch(err) {
|
42 |
+
return '';
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* 搜狗大家还在搜
|
48 |
+
*/
|
49 |
+
public getRelatedQueries() {
|
50 |
+
const $related = this.$(SELECTOR.related);
|
51 |
+
const texts = $related.children().map((i, el) => {
|
52 |
+
return this.$(el).text();
|
53 |
+
});
|
54 |
+
return texts.toArray();
|
55 |
+
}
|
56 |
+
|
57 |
+
public async getResults() {
|
58 |
+
const $result = this.$(SELECTOR.results);
|
59 |
+
const nodes = $result.children().map((i, el) => {
|
60 |
+
return this.resultFilter(el);
|
61 |
+
});
|
62 |
+
const list = await Promise.all(nodes);
|
63 |
+
return list.filter(item => item.url && item.snippet && item.name);
|
64 |
+
}
|
65 |
+
|
66 |
+
private async resultFilter(el: cheerio.Element) {
|
67 |
+
const $el = this.$(el);
|
68 |
+
const title = $el.find(SELECTOR.resultTitle).text().replace(/\n/g, '').trim();
|
69 |
+
const link = $el.find(SELECTOR.resultLink).get(0)?.attribs.href;
|
70 |
+
const snippets = SELECTOR.resultSnippet.map(item => {
|
71 |
+
SELECTOR.resultSnippetExcluded.forEach(e => {
|
72 |
+
$el.find(e).remove();
|
73 |
+
});
|
74 |
+
return $el.find(item).text().trim() ?? '';
|
75 |
+
});
|
76 |
+
let url = link;
|
77 |
+
if (!link?.includes('http')) url = await this.getRealTargetUrl(link);
|
78 |
+
return {
|
79 |
+
name: title,
|
80 |
+
url,
|
81 |
+
snippet: snippets.join(''),
|
82 |
+
};
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* 解析搜狗搜索结果中的link,获取真实的链接
|
87 |
+
* @param url
|
88 |
+
*/
|
89 |
+
private async getRealTargetUrl(url?: string) {
|
90 |
+
if (!url) return '';
|
91 |
+
const res = await httpRequest({
|
92 |
+
endpoint: EndPoints.LINK + url,
|
93 |
+
headers: {
|
94 |
+
Accept: '*/*'
|
95 |
+
}
|
96 |
+
});
|
97 |
+
const txt = await res.text();
|
98 |
+
const $ = cheerio.load(txt);
|
99 |
+
// eg. <script>window.location.replace("https://www.bilibili.com/video/BV1HL4y1h7gH")</script>
|
100 |
+
const link = $('script').text();
|
101 |
+
const matches = link.match(/"(.*?)"/);
|
102 |
+
return matches?.[1] || '';
|
103 |
+
}
|
104 |
+
}
|
backend/service.ts
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { EndPoint, DEFAULT_SEARCH_ENGINE_TIMEOUT, BING_MKT } from './utils/constant';
|
2 |
+
import { httpRequest } from './utils/utils';
|
3 |
+
import { Sogou } from './search/sogou';
|
4 |
+
import searxng, { ESearXNGCategory } from './search/searxng';
|
5 |
+
import { webSearch } from './search/chatglm';
|
6 |
+
|
7 |
+
|
8 |
+
export const searchWithSearXNG = async (
|
9 |
+
query: string,
|
10 |
+
categories?: ESearXNGCategory[],
|
11 |
+
language = 'all'
|
12 |
+
) => {
|
13 |
+
language = process.env.SEARXNG_LANGUAGE || language;
|
14 |
+
const defaultEngines = process.env.SEARXNG_ENGINES ? process.env.SEARXNG_ENGINES.split(',') : [];
|
15 |
+
const engines = defaultEngines.map(item => item.trim());
|
16 |
+
// Scientific search only supports english, so set to all.
|
17 |
+
if (categories?.includes(ESearXNGCategory.SCIENCE)) language = 'all';
|
18 |
+
const res = await searxng({
|
19 |
+
q: query,
|
20 |
+
categories,
|
21 |
+
language,
|
22 |
+
engines: engines.join(',')
|
23 |
+
});
|
24 |
+
return res;
|
25 |
+
};
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Search with bing and return the contexts.
|
29 |
+
*/
|
30 |
+
export const searchWithBing = async (query: string) => {
|
31 |
+
try {
|
32 |
+
const subscriptionKey = process.env.BING_SEARCH_KEY;
|
33 |
+
if (!subscriptionKey) {
|
34 |
+
throw new Error('Bing search key is not provided.');
|
35 |
+
}
|
36 |
+
const res = await httpRequest({
|
37 |
+
endpoint: EndPoint.BING_SEARCH_V7_ENDPOINT,
|
38 |
+
timeout: DEFAULT_SEARCH_ENGINE_TIMEOUT,
|
39 |
+
query: {
|
40 |
+
q: query,
|
41 |
+
mkt: BING_MKT
|
42 |
+
},
|
43 |
+
headers: {
|
44 |
+
'Ocp-Apim-Subscription-Key': subscriptionKey
|
45 |
+
}
|
46 |
+
});
|
47 |
+
const result = await res.json();
|
48 |
+
const list = result?.webPages?.value || [];
|
49 |
+
return list.map((item: any, index: number) => {
|
50 |
+
return {
|
51 |
+
id: index + 1,
|
52 |
+
name: item.name,
|
53 |
+
url: item.url,
|
54 |
+
snippet: item.snippet
|
55 |
+
};
|
56 |
+
});
|
57 |
+
} catch(err) {
|
58 |
+
console.error('[Bing Search Error]:', err);
|
59 |
+
return [];
|
60 |
+
}
|
61 |
+
};
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Search with google and return the contexts.
|
65 |
+
*/
|
66 |
+
export const searchWithGoogle = async (query: string) => {
|
67 |
+
if (!query.trim()) return [];
|
68 |
+
try {
|
69 |
+
const key = process.env.GOOGLE_SEARCH_KEY;
|
70 |
+
const id = process.env.GOOGLE_SEARCH_ID;
|
71 |
+
const res = await httpRequest({
|
72 |
+
method: 'GET',
|
73 |
+
endpoint: EndPoint.GOOGLE_SEARCH_ENDPOINT,
|
74 |
+
query: {
|
75 |
+
key,
|
76 |
+
cx: id,
|
77 |
+
q: query
|
78 |
+
},
|
79 |
+
timeout: DEFAULT_SEARCH_ENGINE_TIMEOUT
|
80 |
+
});
|
81 |
+
const result = await res.json();
|
82 |
+
const list = result.items ?? [];
|
83 |
+
return list.map((item: any, index: number) => {
|
84 |
+
return {
|
85 |
+
id: index + 1,
|
86 |
+
name: item.title,
|
87 |
+
url: item.link,
|
88 |
+
formattedUrl: item.formattedUrl,
|
89 |
+
snippet: item.snippet,
|
90 |
+
imageLink: item.image?.thumbnailLink,
|
91 |
+
imageContextLink: item.image?.contextLink
|
92 |
+
};
|
93 |
+
});
|
94 |
+
} catch (err) {
|
95 |
+
console.error('Google Search Error:', err);
|
96 |
+
return [];
|
97 |
+
}
|
98 |
+
};
|
99 |
+
|
100 |
+
/**
|
101 |
+
* search with sogou and return the contexts.
|
102 |
+
*/
|
103 |
+
export const searchWithSogou = async (query: string) => {
|
104 |
+
const sogou = new Sogou(query);
|
105 |
+
await sogou.init();
|
106 |
+
// const relatedQueries = sogou.getRelatedQueries();
|
107 |
+
const results = await sogou.getResults();
|
108 |
+
return results.map((item, index) => {
|
109 |
+
return {
|
110 |
+
id: index + 1,
|
111 |
+
...item
|
112 |
+
};
|
113 |
+
});
|
114 |
+
};
|
115 |
+
|
116 |
+
export const searchWithChatGLM = async (query: string) => {
|
117 |
+
const results = await webSearch(query);
|
118 |
+
return results.map((item, index) => {
|
119 |
+
return {
|
120 |
+
id: index + 1,
|
121 |
+
name: item.title,
|
122 |
+
url: item.link,
|
123 |
+
snippet: item.content,
|
124 |
+
icon: item.icon,
|
125 |
+
media: item.media,
|
126 |
+
};
|
127 |
+
});
|
128 |
+
};
|
backend/utils/constant.ts
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { IModelInfo } from '../interface';
|
2 |
+
|
3 |
+
// Search engine related. You don't really need to change this.
|
4 |
+
export const EndPoint = {
|
5 |
+
BING_SEARCH_V7_ENDPOINT: 'https://api.bing.microsoft.com/v7.0/search',
|
6 |
+
GOOGLE_SEARCH_ENDPOINT: 'https://www.googleapis.com/customsearch/v1'
|
7 |
+
};
|
8 |
+
|
9 |
+
export const BING_MKT = 'en-US';
|
10 |
+
|
11 |
+
// default timeout ms
|
12 |
+
export const DEFAULT_SEARCH_ENGINE_TIMEOUT = 20000;
|
13 |
+
|
14 |
+
// default search keywords
|
15 |
+
export const DefaultQuery = 'Who said \'live long and prosper';
|
16 |
+
export const DefaultSystem = 'You are a helpful assistant.';
|
17 |
+
|
18 |
+
export const Models: IModelInfo[] = [
|
19 |
+
{
|
20 |
+
platform: 'aliyun',
|
21 |
+
type: '',
|
22 |
+
models: ['qwen-max', 'qwen-max-0428', 'qwen-turbo', 'qwen-plus']
|
23 |
+
},
|
24 |
+
{
|
25 |
+
platform: 'openai',
|
26 |
+
type: 'openai',
|
27 |
+
models: ['gpt-4o', 'gpt-4o-mini', 'chatgpt-4o-latest', 'gpt-3.5-turbo', 'gpt-4-preview', 'gpt-4-turbo', 'gpt-4']
|
28 |
+
},
|
29 |
+
{
|
30 |
+
platform: 'baidu',
|
31 |
+
type: 'baidu',
|
32 |
+
models: ['eb-instant', 'completions_pro', 'ernie_bot_8k']
|
33 |
+
},
|
34 |
+
{
|
35 |
+
platform: 'google',
|
36 |
+
type: 'gemini',
|
37 |
+
models: ['gemini-1.0-pro', 'gemini-1.5-pro', 'gemini-1.5-flash']
|
38 |
+
},
|
39 |
+
{
|
40 |
+
platform: 'yi',
|
41 |
+
type: 'openai',
|
42 |
+
models: ['yi-large', 'yi-large-turbo', 'yi-medium', 'yi-spark']
|
43 |
+
},
|
44 |
+
{
|
45 |
+
platform: 'moonshot',
|
46 |
+
type: 'openai',
|
47 |
+
models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k']
|
48 |
+
},
|
49 |
+
{
|
50 |
+
platform: 'lepton',
|
51 |
+
type: 'openai',
|
52 |
+
models: ['llama2-7b', 'llama2-13b', 'llama2-70b', 'mixtral-8*7b', 'mixtral-8*22b']
|
53 |
+
},
|
54 |
+
{
|
55 |
+
platform: 'deepseek',
|
56 |
+
type: 'openai',
|
57 |
+
models: ['deepseek-chat', 'deepseek-coder']
|
58 |
+
},
|
59 |
+
{
|
60 |
+
platform: 'chatglm',
|
61 |
+
type: 'openai',
|
62 |
+
models: ['glm-4', 'glm-4-plus', 'glm-4-air', 'glm-4-airx', 'glm-4-flash']
|
63 |
+
},
|
64 |
+
{
|
65 |
+
platform: 'tencent',
|
66 |
+
type: 'tencent',
|
67 |
+
models: ['std', 'pro']
|
68 |
+
}
|
69 |
+
];
|
backend/utils/utils.ts
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import url from 'url';
|
2 |
+
interface RequestConfig {
|
3 |
+
endpoint: string;
|
4 |
+
timeout?: number;
|
5 |
+
query?: Record<string, any>;
|
6 |
+
data?: BodyInit | null;
|
7 |
+
headers?: Record<string, any>;
|
8 |
+
method?: RequestInit['method']
|
9 |
+
}
|
10 |
+
|
11 |
+
export const httpRequest = async (config: RequestConfig) => {
|
12 |
+
const { endpoint, timeout = 10 * 60 * 1000, query, headers, data, method = 'GET' } = config;
|
13 |
+
const controller = new AbortController();
|
14 |
+
const id = setTimeout(() => controller.abort(), timeout);
|
15 |
+
const params = url.format({
|
16 |
+
query: query
|
17 |
+
});
|
18 |
+
const res = await fetch(endpoint + params, {
|
19 |
+
method,
|
20 |
+
headers,
|
21 |
+
body: data,
|
22 |
+
signal: controller.signal
|
23 |
+
});
|
24 |
+
clearTimeout(id);
|
25 |
+
return res;
|
26 |
+
};
|
docker-compose.yaml
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
version: "3.7"
|
2 |
+
|
3 |
+
services:
|
4 |
+
search:
|
5 |
+
build: ./
|
6 |
+
container_name: search
|
7 |
+
volumes:
|
8 |
+
- ./.env.docker:/app/.env
|
9 |
+
ports:
|
10 |
+
- "3000:3000"
|
11 |
+
restart: always
|
12 |
+
|
13 |
+
searxng:
|
14 |
+
container_name: searxng
|
15 |
+
image: docker.io/searxng/searxng:latest
|
16 |
+
restart: always
|
17 |
+
# ports:
|
18 |
+
# - "127.0.0.1:8080:8080"
|
19 |
+
volumes:
|
20 |
+
- ./searxng:/etc/searxng:rw
|
21 |
+
environment:
|
22 |
+
- SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost}/
|
package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
package.json
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "ai_search",
|
3 |
+
"version": "1.0.6",
|
4 |
+
"description": "ai search with node.js",
|
5 |
+
"main": "./dist/app.js",
|
6 |
+
"author": "zac_ma",
|
7 |
+
"license": "MIT",
|
8 |
+
"engines": {
|
9 |
+
"node": ">=20"
|
10 |
+
},
|
11 |
+
"scripts": {
|
12 |
+
"start": "dotenvx run --env-file=.env -- node ./dist/app.js",
|
13 |
+
"dev": "dotenvx run --env-file=.env.local --env-file=.env -- cross-env NODE_ENV=development nodemon ./backend/app.ts",
|
14 |
+
"build": "tsc"
|
15 |
+
},
|
16 |
+
"dependencies": {
|
17 |
+
"@dotenvx/dotenvx": "^0.24.0",
|
18 |
+
"@google/generative-ai": "^0.2.1",
|
19 |
+
"@koa/bodyparser": "^5.1.0",
|
20 |
+
"@koa/cors": "^5.0.0",
|
21 |
+
"@koa/router": "^12.0.1",
|
22 |
+
"@lmstudio/sdk": "^0.1.0",
|
23 |
+
"cache-manager": "^5.4.0",
|
24 |
+
"cheerio": "^1.0.0-rc.12",
|
25 |
+
"fetch-sse": "1.0.23",
|
26 |
+
"koa": "^2.15.0",
|
27 |
+
"koa-static": "^5.0.0",
|
28 |
+
"koa2-connect-history-api-fallback": "^0.1.3",
|
29 |
+
"ollama": "^0.5.9",
|
30 |
+
"openai": "^4.61.1",
|
31 |
+
"tencentcloud-sdk-nodejs": "^4.0.810"
|
32 |
+
},
|
33 |
+
"devDependencies": {
|
34 |
+
"@types/koa": "^2.15.0",
|
35 |
+
"@types/koa-static": "^4.0.4",
|
36 |
+
"@types/koa__cors": "^5.0.0",
|
37 |
+
"@types/koa__router": "^12.0.4",
|
38 |
+
"cross-env": "^7.0.3",
|
39 |
+
"eslint": "^8.57.0",
|
40 |
+
"eslint-config-standard": "^17.1.0",
|
41 |
+
"eslint-plugin-import": "^2.29.1",
|
42 |
+
"eslint-plugin-n": "^16.6.2",
|
43 |
+
"eslint-plugin-node": "^11.1.0",
|
44 |
+
"eslint-plugin-promise": "^6.1.1",
|
45 |
+
"nodemon": "^3.1.0",
|
46 |
+
"ts-node": "^10.9.2",
|
47 |
+
"typescript": "^5.3.3",
|
48 |
+
"typescript-eslint": "^7.0.2"
|
49 |
+
}
|
50 |
+
}
|
searxng/limiter.toml
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
[botdetection.ip_limit]
|
2 |
+
# activate link_token method in the ip_limit method
|
3 |
+
link_token = true
|
searxng/settings.yml
ADDED
@@ -0,0 +1,2388 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
general:
|
2 |
+
# Debug mode, only for development. Is overwritten by ${SEARXNG_DEBUG}
|
3 |
+
debug: false
|
4 |
+
# displayed name
|
5 |
+
instance_name: "searxng"
|
6 |
+
# For example: https://example.com/privacy
|
7 |
+
privacypolicy_url: false
|
8 |
+
# use true to use your own donation page written in searx/info/en/donate.md
|
9 |
+
# use false to disable the donation link
|
10 |
+
donation_url: false
|
11 |
+
# mailto:[email protected]
|
12 |
+
contact_url: false
|
13 |
+
# record stats
|
14 |
+
enable_metrics: true
|
15 |
+
|
16 |
+
brand:
|
17 |
+
new_issue_url: https://github.com/searxng/searxng/issues/new
|
18 |
+
docs_url: https://docs.searxng.org/
|
19 |
+
public_instances: https://searx.space
|
20 |
+
wiki_url: https://github.com/searxng/searxng/wiki
|
21 |
+
issue_url: https://github.com/searxng/searxng/issues
|
22 |
+
# custom:
|
23 |
+
# maintainer: "Jon Doe"
|
24 |
+
# # Custom entries in the footer: [title]: [link]
|
25 |
+
# links:
|
26 |
+
# Uptime: https://uptime.searxng.org/history/darmarit-org
|
27 |
+
# About: "https://searxng.org"
|
28 |
+
|
29 |
+
search:
|
30 |
+
# Filter results. 0: None, 1: Moderate, 2: Strict
|
31 |
+
safe_search: 0
|
32 |
+
# Existing autocomplete backends: "dbpedia", "duckduckgo", "google", "yandex", "mwmbl",
|
33 |
+
# "seznam", "startpage", "stract", "swisscows", "qwant", "wikipedia" - leave blank to turn it off
|
34 |
+
# by default.
|
35 |
+
autocomplete: ""
|
36 |
+
# minimun characters to type before autocompleter starts
|
37 |
+
autocomplete_min: 4
|
38 |
+
# Default search language - leave blank to detect from browser information or
|
39 |
+
# use codes from 'languages.py'
|
40 |
+
default_lang: "auto"
|
41 |
+
# max_page: 0 # if engine supports paging, 0 means unlimited numbers of pages
|
42 |
+
# Available languages
|
43 |
+
# languages:
|
44 |
+
# - all
|
45 |
+
# - en
|
46 |
+
# - en-US
|
47 |
+
# - de
|
48 |
+
# - it-IT
|
49 |
+
# - fr
|
50 |
+
# - fr-BE
|
51 |
+
# ban time in seconds after engine errors
|
52 |
+
ban_time_on_fail: 5
|
53 |
+
# max ban time in seconds after engine errors
|
54 |
+
max_ban_time_on_fail: 120
|
55 |
+
suspended_times:
|
56 |
+
# Engine suspension time after error (in seconds; set to 0 to disable)
|
57 |
+
# For error "Access denied" and "HTTP error [402, 403]"
|
58 |
+
SearxEngineAccessDenied: 86400
|
59 |
+
# For error "CAPTCHA"
|
60 |
+
SearxEngineCaptcha: 86400
|
61 |
+
# For error "Too many request" and "HTTP error 429"
|
62 |
+
SearxEngineTooManyRequests: 3600
|
63 |
+
# Cloudflare CAPTCHA
|
64 |
+
cf_SearxEngineCaptcha: 1296000
|
65 |
+
cf_SearxEngineAccessDenied: 86400
|
66 |
+
# ReCAPTCHA
|
67 |
+
recaptcha_SearxEngineCaptcha: 604800
|
68 |
+
|
69 |
+
# remove format to deny access, use lower case.
|
70 |
+
# formats: [html, csv, json, rss]
|
71 |
+
formats:
|
72 |
+
- html
|
73 |
+
- json
|
74 |
+
|
75 |
+
server:
|
76 |
+
# Is overwritten by ${SEARXNG_PORT} and ${SEARXNG_BIND_ADDRESS}
|
77 |
+
port: 8888
|
78 |
+
bind_address: "127.0.0.1"
|
79 |
+
# public URL of the instance, to ensure correct inbound links. Is overwritten
|
80 |
+
# by ${SEARXNG_URL}.
|
81 |
+
base_url: / # "http://example.com/location"
|
82 |
+
limiter: false # rate limit the number of request on the instance, block some bots
|
83 |
+
public_instance: false # enable features designed only for public instances
|
84 |
+
|
85 |
+
# If your instance owns a /etc/searxng/settings.yml file, then set the following
|
86 |
+
# values there.
|
87 |
+
|
88 |
+
secret_key: "248761c39005d33050fec8bd6b40a170f133ff471f71a0e262154a5903c7d3e3" # Is overwritten by ${SEARXNG_SECRET}
|
89 |
+
# Proxying image results through searx
|
90 |
+
image_proxy: false
|
91 |
+
# 1.0 and 1.1 are supported
|
92 |
+
http_protocol_version: "1.0"
|
93 |
+
# POST queries are more secure as they don't show up in history but may cause
|
94 |
+
# problems when using Firefox containers
|
95 |
+
method: "POST"
|
96 |
+
default_http_headers:
|
97 |
+
X-Content-Type-Options: nosniff
|
98 |
+
X-Download-Options: noopen
|
99 |
+
X-Robots-Tag: noindex, nofollow
|
100 |
+
Referrer-Policy: no-referrer
|
101 |
+
|
102 |
+
redis:
|
103 |
+
# URL to connect redis database. Is overwritten by ${SEARXNG_REDIS_URL}.
|
104 |
+
# https://docs.searxng.org/admin/settings/settings_redis.html#settings-redis
|
105 |
+
url: false
|
106 |
+
|
107 |
+
ui:
|
108 |
+
# Custom static path - leave it blank if you didn't change
|
109 |
+
static_path: ""
|
110 |
+
static_use_hash: false
|
111 |
+
# Custom templates path - leave it blank if you didn't change
|
112 |
+
templates_path: ""
|
113 |
+
# query_in_title: When true, the result page's titles contains the query
|
114 |
+
# it decreases the privacy, since the browser can records the page titles.
|
115 |
+
query_in_title: false
|
116 |
+
# infinite_scroll: When true, automatically loads the next page when scrolling to bottom of the current page.
|
117 |
+
infinite_scroll: false
|
118 |
+
# ui theme
|
119 |
+
default_theme: simple
|
120 |
+
# center the results ?
|
121 |
+
center_alignment: false
|
122 |
+
# URL prefix of the internet archive, don't forget trailing slash (if needed).
|
123 |
+
# cache_url: "https://webcache.googleusercontent.com/search?q=cache:"
|
124 |
+
# Default interface locale - leave blank to detect from browser information or
|
125 |
+
# use codes from the 'locales' config section
|
126 |
+
default_locale: ""
|
127 |
+
# Open result links in a new tab by default
|
128 |
+
# results_on_new_tab: false
|
129 |
+
theme_args:
|
130 |
+
# style of simple theme: auto, light, dark
|
131 |
+
simple_style: auto
|
132 |
+
# Perform search immediately if a category selected.
|
133 |
+
# Disable to select multiple categories at once and start the search manually.
|
134 |
+
search_on_category_select: true
|
135 |
+
# Hotkeys: default or vim
|
136 |
+
hotkeys: default
|
137 |
+
|
138 |
+
# Lock arbitrary settings on the preferences page. To find the ID of the user
|
139 |
+
# setting you want to lock, check the ID of the form on the page "preferences".
|
140 |
+
#
|
141 |
+
# preferences:
|
142 |
+
# lock:
|
143 |
+
# - language
|
144 |
+
# - autocomplete
|
145 |
+
# - method
|
146 |
+
# - query_in_title
|
147 |
+
|
148 |
+
# searx supports result proxification using an external service:
|
149 |
+
# https://github.com/asciimoo/morty uncomment below section if you have running
|
150 |
+
# morty proxy the key is base64 encoded (keep the !!binary notation)
|
151 |
+
# Note: since commit af77ec3, morty accepts a base64 encoded key.
|
152 |
+
#
|
153 |
+
# result_proxy:
|
154 |
+
# url: http://127.0.0.1:3000/
|
155 |
+
# # the key is a base64 encoded string, the YAML !!binary prefix is optional
|
156 |
+
# key: !!binary "your_morty_proxy_key"
|
157 |
+
# # [true|false] enable the "proxy" button next to each result
|
158 |
+
# proxify_results: true
|
159 |
+
|
160 |
+
# communication with search engines
|
161 |
+
#
|
162 |
+
outgoing:
|
163 |
+
# default timeout in seconds, can be override by engine
|
164 |
+
request_timeout: 3.0
|
165 |
+
# the maximum timeout in seconds
|
166 |
+
# max_request_timeout: 10.0
|
167 |
+
# suffix of searx_useragent, could contain information like an email address
|
168 |
+
# to the administrator
|
169 |
+
useragent_suffix: ""
|
170 |
+
# The maximum number of concurrent connections that may be established.
|
171 |
+
pool_connections: 100
|
172 |
+
# Allow the connection pool to maintain keep-alive connections below this
|
173 |
+
# point.
|
174 |
+
pool_maxsize: 20
|
175 |
+
# See https://www.python-httpx.org/http2/
|
176 |
+
enable_http2: true
|
177 |
+
# uncomment below section if you want to use a custom server certificate
|
178 |
+
# see https://www.python-httpx.org/advanced/#changing-the-verification-defaults
|
179 |
+
# and https://www.python-httpx.org/compatibility/#ssl-configuration
|
180 |
+
# verify: ~/.mitmproxy/mitmproxy-ca-cert.cer
|
181 |
+
#
|
182 |
+
# uncomment below section if you want to use a proxyq see: SOCKS proxies
|
183 |
+
# https://2.python-requests.org/en/latest/user/advanced/#proxies
|
184 |
+
# are also supported: see
|
185 |
+
# https://2.python-requests.org/en/latest/user/advanced/#socks
|
186 |
+
#
|
187 |
+
# proxies:
|
188 |
+
# all://:
|
189 |
+
# - http://proxy1:8080
|
190 |
+
# - http://proxy2:8080
|
191 |
+
#
|
192 |
+
# using_tor_proxy: true
|
193 |
+
#
|
194 |
+
# Extra seconds to add in order to account for the time taken by the proxy
|
195 |
+
#
|
196 |
+
# extra_proxy_timeout: 10
|
197 |
+
#
|
198 |
+
# uncomment below section only if you have more than one network interface
|
199 |
+
# which can be the source of outgoing search requests
|
200 |
+
#
|
201 |
+
# source_ips:
|
202 |
+
# - 1.1.1.1
|
203 |
+
# - 1.1.1.2
|
204 |
+
# - fe80::/126
|
205 |
+
|
206 |
+
# External plugin configuration, for more details see
|
207 |
+
# https://docs.searxng.org/dev/plugins.html
|
208 |
+
#
|
209 |
+
# plugins:
|
210 |
+
# - plugin1
|
211 |
+
# - plugin2
|
212 |
+
# - ...
|
213 |
+
|
214 |
+
# Comment or un-comment plugin to activate / deactivate by default.
|
215 |
+
#
|
216 |
+
# enabled_plugins:
|
217 |
+
# # these plugins are enabled if nothing is configured ..
|
218 |
+
# - 'Hash plugin'
|
219 |
+
# - 'Self Information'
|
220 |
+
# - 'Tracker URL remover'
|
221 |
+
# - 'Ahmia blacklist' # activation depends on outgoing.using_tor_proxy
|
222 |
+
# # these plugins are disabled if nothing is configured ..
|
223 |
+
# - 'Hostname replace' # see hostname_replace configuration below
|
224 |
+
# - 'Open Access DOI rewrite'
|
225 |
+
# - 'Tor check plugin'
|
226 |
+
# # Read the docs before activate: auto-detection of the language could be
|
227 |
+
# # detrimental to users expectations / users can activate the plugin in the
|
228 |
+
# # preferences if they want.
|
229 |
+
# - 'Autodetect search language'
|
230 |
+
|
231 |
+
# Configuration of the "Hostname replace" plugin:
|
232 |
+
#
|
233 |
+
# hostname_replace:
|
234 |
+
# '(.*\.)?youtube\.com$': 'invidious.example.com'
|
235 |
+
# '(.*\.)?youtu\.be$': 'invidious.example.com'
|
236 |
+
# '(.*\.)?youtube-noocookie\.com$': 'yotter.example.com'
|
237 |
+
# '(.*\.)?reddit\.com$': 'teddit.example.com'
|
238 |
+
# '(.*\.)?redd\.it$': 'teddit.example.com'
|
239 |
+
# '(www\.)?twitter\.com$': 'nitter.example.com'
|
240 |
+
# # to remove matching host names from result list, set value to false
|
241 |
+
# 'spam\.example\.com': false
|
242 |
+
|
243 |
+
checker:
|
244 |
+
# disable checker when in debug mode
|
245 |
+
off_when_debug: true
|
246 |
+
|
247 |
+
# use "scheduling: false" to disable scheduling
|
248 |
+
# scheduling: interval or int
|
249 |
+
|
250 |
+
# to activate the scheduler:
|
251 |
+
# * uncomment "scheduling" section
|
252 |
+
# * add "cache2 = name=searxngcache,items=2000,blocks=2000,blocksize=4096,bitmap=1"
|
253 |
+
# to your uwsgi.ini
|
254 |
+
|
255 |
+
# scheduling:
|
256 |
+
# start_after: [300, 1800] # delay to start the first run of the checker
|
257 |
+
# every: [86400, 90000] # how often the checker runs
|
258 |
+
|
259 |
+
# additional tests: only for the YAML anchors (see the engines section)
|
260 |
+
#
|
261 |
+
additional_tests:
|
262 |
+
rosebud: &test_rosebud
|
263 |
+
matrix:
|
264 |
+
query: rosebud
|
265 |
+
lang: en
|
266 |
+
result_container:
|
267 |
+
- not_empty
|
268 |
+
- ['one_title_contains', 'citizen kane']
|
269 |
+
test:
|
270 |
+
- unique_results
|
271 |
+
|
272 |
+
android: &test_android
|
273 |
+
matrix:
|
274 |
+
query: ['android']
|
275 |
+
lang: ['en', 'de', 'fr', 'zh-CN']
|
276 |
+
result_container:
|
277 |
+
- not_empty
|
278 |
+
- ['one_title_contains', 'google']
|
279 |
+
test:
|
280 |
+
- unique_results
|
281 |
+
|
282 |
+
# tests: only for the YAML anchors (see the engines section)
|
283 |
+
tests:
|
284 |
+
infobox: &tests_infobox
|
285 |
+
infobox:
|
286 |
+
matrix:
|
287 |
+
query: ["linux", "new york", "bbc"]
|
288 |
+
result_container:
|
289 |
+
- has_infobox
|
290 |
+
|
291 |
+
categories_as_tabs:
|
292 |
+
general:
|
293 |
+
images:
|
294 |
+
videos:
|
295 |
+
news:
|
296 |
+
map:
|
297 |
+
music:
|
298 |
+
it:
|
299 |
+
science:
|
300 |
+
files:
|
301 |
+
social media:
|
302 |
+
|
303 |
+
engines:
|
304 |
+
- name: 9gag
|
305 |
+
engine: 9gag
|
306 |
+
shortcut: 9g
|
307 |
+
disabled: true
|
308 |
+
|
309 |
+
- name: annas archive
|
310 |
+
engine: annas_archive
|
311 |
+
disabled: true
|
312 |
+
shortcut: aa
|
313 |
+
|
314 |
+
# - name: annas articles
|
315 |
+
# engine: annas_archive
|
316 |
+
# shortcut: aaa
|
317 |
+
# # https://docs.searxng.org/dev/engines/online/annas_archive.html
|
318 |
+
# aa_content: 'magazine' # book_fiction, book_unknown, book_nonfiction, book_comic
|
319 |
+
# aa_ext: 'pdf' # pdf, epub, ..
|
320 |
+
# aa_sort: oldest' # newest, oldest, largest, smallest
|
321 |
+
|
322 |
+
- name: apk mirror
|
323 |
+
engine: apkmirror
|
324 |
+
timeout: 4.0
|
325 |
+
shortcut: apkm
|
326 |
+
disabled: true
|
327 |
+
|
328 |
+
- name: apple app store
|
329 |
+
engine: apple_app_store
|
330 |
+
shortcut: aps
|
331 |
+
disabled: true
|
332 |
+
|
333 |
+
# Requires Tor
|
334 |
+
- name: ahmia
|
335 |
+
engine: ahmia
|
336 |
+
categories: onions
|
337 |
+
enable_http: true
|
338 |
+
shortcut: ah
|
339 |
+
|
340 |
+
- name: anaconda
|
341 |
+
engine: xpath
|
342 |
+
paging: true
|
343 |
+
first_page_num: 0
|
344 |
+
search_url: https://anaconda.org/search?q={query}&page={pageno}
|
345 |
+
results_xpath: //tbody/tr
|
346 |
+
url_xpath: ./td/h5/a[last()]/@href
|
347 |
+
title_xpath: ./td/h5
|
348 |
+
content_xpath: ./td[h5]/text()
|
349 |
+
categories: it
|
350 |
+
timeout: 6.0
|
351 |
+
shortcut: conda
|
352 |
+
disabled: true
|
353 |
+
|
354 |
+
- name: arch linux wiki
|
355 |
+
engine: archlinux
|
356 |
+
shortcut: al
|
357 |
+
|
358 |
+
- name: artic
|
359 |
+
engine: artic
|
360 |
+
shortcut: arc
|
361 |
+
timeout: 4.0
|
362 |
+
|
363 |
+
- name: arxiv
|
364 |
+
engine: arxiv
|
365 |
+
shortcut: arx
|
366 |
+
timeout: 4.0
|
367 |
+
|
368 |
+
- name: ask
|
369 |
+
engine: ask
|
370 |
+
shortcut: ask
|
371 |
+
disabled: true
|
372 |
+
|
373 |
+
# tmp suspended: dh key too small
|
374 |
+
# - name: base
|
375 |
+
# engine: base
|
376 |
+
# shortcut: bs
|
377 |
+
|
378 |
+
- name: bandcamp
|
379 |
+
engine: bandcamp
|
380 |
+
shortcut: bc
|
381 |
+
categories: music
|
382 |
+
|
383 |
+
- name: wikipedia
|
384 |
+
engine: wikipedia
|
385 |
+
shortcut: wp
|
386 |
+
# add "list" to the array to get results in the results list
|
387 |
+
display_type: ["infobox"]
|
388 |
+
base_url: 'https://{language}.wikipedia.org/'
|
389 |
+
categories: [general]
|
390 |
+
|
391 |
+
- name: bilibili
|
392 |
+
engine: bilibili
|
393 |
+
shortcut: bil
|
394 |
+
disabled: true
|
395 |
+
|
396 |
+
- name: bing
|
397 |
+
engine: bing
|
398 |
+
shortcut: bi
|
399 |
+
disabled: true
|
400 |
+
|
401 |
+
- name: bing images
|
402 |
+
engine: bing_images
|
403 |
+
shortcut: bii
|
404 |
+
|
405 |
+
- name: bing news
|
406 |
+
engine: bing_news
|
407 |
+
shortcut: bin
|
408 |
+
|
409 |
+
- name: bing videos
|
410 |
+
engine: bing_videos
|
411 |
+
shortcut: biv
|
412 |
+
|
413 |
+
- name: bitbucket
|
414 |
+
engine: xpath
|
415 |
+
paging: true
|
416 |
+
search_url: https://bitbucket.org/repo/all/{pageno}?name={query}
|
417 |
+
url_xpath: //article[@class="repo-summary"]//a[@class="repo-link"]/@href
|
418 |
+
title_xpath: //article[@class="repo-summary"]//a[@class="repo-link"]
|
419 |
+
content_xpath: //article[@class="repo-summary"]/p
|
420 |
+
categories: [it, repos]
|
421 |
+
timeout: 4.0
|
422 |
+
disabled: true
|
423 |
+
shortcut: bb
|
424 |
+
about:
|
425 |
+
website: https://bitbucket.org/
|
426 |
+
wikidata_id: Q2493781
|
427 |
+
official_api_documentation: https://developer.atlassian.com/bitbucket
|
428 |
+
use_official_api: false
|
429 |
+
require_api_key: false
|
430 |
+
results: HTML
|
431 |
+
|
432 |
+
- name: bpb
|
433 |
+
engine: bpb
|
434 |
+
shortcut: bpb
|
435 |
+
disabled: true
|
436 |
+
|
437 |
+
- name: btdigg
|
438 |
+
engine: btdigg
|
439 |
+
shortcut: bt
|
440 |
+
disabled: true
|
441 |
+
|
442 |
+
- name: ccc-tv
|
443 |
+
engine: xpath
|
444 |
+
paging: false
|
445 |
+
search_url: https://media.ccc.de/search/?q={query}
|
446 |
+
url_xpath: //div[@class="caption"]/h3/a/@href
|
447 |
+
title_xpath: //div[@class="caption"]/h3/a/text()
|
448 |
+
content_xpath: //div[@class="caption"]/h4/@title
|
449 |
+
categories: videos
|
450 |
+
disabled: true
|
451 |
+
shortcut: c3tv
|
452 |
+
about:
|
453 |
+
website: https://media.ccc.de/
|
454 |
+
wikidata_id: Q80729951
|
455 |
+
official_api_documentation: https://github.com/voc/voctoweb
|
456 |
+
use_official_api: false
|
457 |
+
require_api_key: false
|
458 |
+
results: HTML
|
459 |
+
# We don't set language: de here because media.ccc.de is not just
|
460 |
+
# for a German audience. It contains many English videos and many
|
461 |
+
# German videos have English subtitles.
|
462 |
+
|
463 |
+
- name: openverse
|
464 |
+
engine: openverse
|
465 |
+
categories: images
|
466 |
+
shortcut: opv
|
467 |
+
|
468 |
+
- name: chefkoch
|
469 |
+
engine: chefkoch
|
470 |
+
shortcut: chef
|
471 |
+
# to show premium or plus results too:
|
472 |
+
# skip_premium: false
|
473 |
+
|
474 |
+
# - name: core.ac.uk
|
475 |
+
# engine: core
|
476 |
+
# categories: science
|
477 |
+
# shortcut: cor
|
478 |
+
# # get your API key from: https://core.ac.uk/api-keys/register/
|
479 |
+
# api_key: 'unset'
|
480 |
+
|
481 |
+
- name: cppreference
|
482 |
+
engine: cppreference
|
483 |
+
shortcut: cpp
|
484 |
+
paging: false
|
485 |
+
disabled: true
|
486 |
+
|
487 |
+
- name: crossref
|
488 |
+
engine: crossref
|
489 |
+
shortcut: cr
|
490 |
+
timeout: 30
|
491 |
+
disabled: true
|
492 |
+
|
493 |
+
- name: crowdview
|
494 |
+
engine: json_engine
|
495 |
+
shortcut: cv
|
496 |
+
categories: general
|
497 |
+
paging: false
|
498 |
+
search_url: https://crowdview-next-js.onrender.com/api/search-v3?query={query}
|
499 |
+
results_query: results
|
500 |
+
url_query: link
|
501 |
+
title_query: title
|
502 |
+
content_query: snippet
|
503 |
+
disabled: true
|
504 |
+
about:
|
505 |
+
website: https://crowdview.ai/
|
506 |
+
|
507 |
+
- name: yep
|
508 |
+
engine: yep
|
509 |
+
shortcut: yep
|
510 |
+
categories: general
|
511 |
+
search_type: web
|
512 |
+
disabled: true
|
513 |
+
|
514 |
+
- name: yep images
|
515 |
+
engine: yep
|
516 |
+
shortcut: yepi
|
517 |
+
categories: images
|
518 |
+
search_type: images
|
519 |
+
disabled: true
|
520 |
+
|
521 |
+
- name: yep news
|
522 |
+
engine: yep
|
523 |
+
shortcut: yepn
|
524 |
+
categories: news
|
525 |
+
search_type: news
|
526 |
+
disabled: true
|
527 |
+
|
528 |
+
- name: curlie
|
529 |
+
engine: xpath
|
530 |
+
shortcut: cl
|
531 |
+
categories: general
|
532 |
+
disabled: true
|
533 |
+
paging: true
|
534 |
+
lang_all: ''
|
535 |
+
search_url: https://curlie.org/search?q={query}&lang={lang}&start={pageno}&stime=92452189
|
536 |
+
page_size: 20
|
537 |
+
results_xpath: //div[@id="site-list-content"]/div[@class="site-item"]
|
538 |
+
url_xpath: ./div[@class="title-and-desc"]/a/@href
|
539 |
+
title_xpath: ./div[@class="title-and-desc"]/a/div
|
540 |
+
content_xpath: ./div[@class="title-and-desc"]/div[@class="site-descr"]
|
541 |
+
about:
|
542 |
+
website: https://curlie.org/
|
543 |
+
wikidata_id: Q60715723
|
544 |
+
use_official_api: false
|
545 |
+
require_api_key: false
|
546 |
+
results: HTML
|
547 |
+
|
548 |
+
- name: currency
|
549 |
+
engine: currency_convert
|
550 |
+
categories: general
|
551 |
+
shortcut: cc
|
552 |
+
|
553 |
+
- name: bahnhof
|
554 |
+
engine: json_engine
|
555 |
+
search_url: https://www.bahnhof.de/api/stations/search/{query}
|
556 |
+
url_prefix: https://www.bahnhof.de/
|
557 |
+
url_query: slug
|
558 |
+
title_query: name
|
559 |
+
content_query: state
|
560 |
+
shortcut: bf
|
561 |
+
disabled: true
|
562 |
+
about:
|
563 |
+
website: https://www.bahn.de
|
564 |
+
wikidata_id: Q22811603
|
565 |
+
use_official_api: false
|
566 |
+
require_api_key: false
|
567 |
+
results: JSON
|
568 |
+
language: de
|
569 |
+
tests:
|
570 |
+
bahnhof:
|
571 |
+
matrix:
|
572 |
+
query: berlin
|
573 |
+
lang: en
|
574 |
+
result_container:
|
575 |
+
- not_empty
|
576 |
+
- ['one_title_contains', 'Berlin Hauptbahnhof']
|
577 |
+
test:
|
578 |
+
- unique_results
|
579 |
+
|
580 |
+
- name: deezer
|
581 |
+
engine: deezer
|
582 |
+
shortcut: dz
|
583 |
+
disabled: true
|
584 |
+
|
585 |
+
- name: destatis
|
586 |
+
engine: destatis
|
587 |
+
shortcut: destat
|
588 |
+
disabled: true
|
589 |
+
|
590 |
+
- name: deviantart
|
591 |
+
engine: deviantart
|
592 |
+
shortcut: da
|
593 |
+
timeout: 3.0
|
594 |
+
|
595 |
+
- name: ddg definitions
|
596 |
+
engine: duckduckgo_definitions
|
597 |
+
shortcut: ddd
|
598 |
+
weight: 2
|
599 |
+
disabled: true
|
600 |
+
tests: *tests_infobox
|
601 |
+
|
602 |
+
# cloudflare protected
|
603 |
+
# - name: digbt
|
604 |
+
# engine: digbt
|
605 |
+
# shortcut: dbt
|
606 |
+
# timeout: 6.0
|
607 |
+
# disabled: true
|
608 |
+
|
609 |
+
- name: docker hub
|
610 |
+
engine: docker_hub
|
611 |
+
shortcut: dh
|
612 |
+
categories: [it, packages]
|
613 |
+
|
614 |
+
- name: erowid
|
615 |
+
engine: xpath
|
616 |
+
paging: true
|
617 |
+
first_page_num: 0
|
618 |
+
page_size: 30
|
619 |
+
search_url: https://www.erowid.org/search.php?q={query}&s={pageno}
|
620 |
+
url_xpath: //dl[@class="results-list"]/dt[@class="result-title"]/a/@href
|
621 |
+
title_xpath: //dl[@class="results-list"]/dt[@class="result-title"]/a/text()
|
622 |
+
content_xpath: //dl[@class="results-list"]/dd[@class="result-details"]
|
623 |
+
categories: []
|
624 |
+
shortcut: ew
|
625 |
+
disabled: true
|
626 |
+
about:
|
627 |
+
website: https://www.erowid.org/
|
628 |
+
wikidata_id: Q1430691
|
629 |
+
official_api_documentation:
|
630 |
+
use_official_api: false
|
631 |
+
require_api_key: false
|
632 |
+
results: HTML
|
633 |
+
|
634 |
+
# - name: elasticsearch
|
635 |
+
# shortcut: es
|
636 |
+
# engine: elasticsearch
|
637 |
+
# base_url: http://localhost:9200
|
638 |
+
# username: elastic
|
639 |
+
# password: changeme
|
640 |
+
# index: my-index
|
641 |
+
# # available options: match, simple_query_string, term, terms, custom
|
642 |
+
# query_type: match
|
643 |
+
# # if query_type is set to custom, provide your query here
|
644 |
+
# #custom_query_json: {"query":{"match_all": {}}}
|
645 |
+
# #show_metadata: false
|
646 |
+
# disabled: true
|
647 |
+
|
648 |
+
- name: wikidata
|
649 |
+
engine: wikidata
|
650 |
+
shortcut: wd
|
651 |
+
timeout: 3.0
|
652 |
+
weight: 2
|
653 |
+
# add "list" to the array to get results in the results list
|
654 |
+
display_type: ["infobox"]
|
655 |
+
tests: *tests_infobox
|
656 |
+
categories: [general]
|
657 |
+
|
658 |
+
- name: duckduckgo
|
659 |
+
engine: duckduckgo
|
660 |
+
shortcut: ddg
|
661 |
+
|
662 |
+
- name: duckduckgo images
|
663 |
+
engine: duckduckgo_extra
|
664 |
+
categories: [images, web]
|
665 |
+
ddg_category: images
|
666 |
+
shortcut: ddi
|
667 |
+
disabled: true
|
668 |
+
|
669 |
+
- name: duckduckgo videos
|
670 |
+
engine: duckduckgo_extra
|
671 |
+
categories: [videos, web]
|
672 |
+
ddg_category: videos
|
673 |
+
shortcut: ddv
|
674 |
+
disabled: true
|
675 |
+
|
676 |
+
- name: duckduckgo news
|
677 |
+
engine: duckduckgo_extra
|
678 |
+
categories: [news, web]
|
679 |
+
ddg_category: news
|
680 |
+
shortcut: ddn
|
681 |
+
disabled: true
|
682 |
+
|
683 |
+
- name: duckduckgo weather
|
684 |
+
engine: duckduckgo_weather
|
685 |
+
shortcut: ddw
|
686 |
+
disabled: true
|
687 |
+
|
688 |
+
- name: apple maps
|
689 |
+
engine: apple_maps
|
690 |
+
shortcut: apm
|
691 |
+
disabled: true
|
692 |
+
timeout: 5.0
|
693 |
+
|
694 |
+
- name: emojipedia
|
695 |
+
engine: emojipedia
|
696 |
+
timeout: 4.0
|
697 |
+
shortcut: em
|
698 |
+
disabled: true
|
699 |
+
|
700 |
+
- name: tineye
|
701 |
+
engine: tineye
|
702 |
+
shortcut: tin
|
703 |
+
timeout: 9.0
|
704 |
+
disabled: true
|
705 |
+
|
706 |
+
- name: etymonline
|
707 |
+
engine: xpath
|
708 |
+
paging: true
|
709 |
+
search_url: https://etymonline.com/search?page={pageno}&q={query}
|
710 |
+
url_xpath: //a[contains(@class, "word__name--")]/@href
|
711 |
+
title_xpath: //a[contains(@class, "word__name--")]
|
712 |
+
content_xpath: //section[contains(@class, "word__defination")]
|
713 |
+
first_page_num: 1
|
714 |
+
shortcut: et
|
715 |
+
categories: [dictionaries]
|
716 |
+
about:
|
717 |
+
website: https://www.etymonline.com/
|
718 |
+
wikidata_id: Q1188617
|
719 |
+
official_api_documentation:
|
720 |
+
use_official_api: false
|
721 |
+
require_api_key: false
|
722 |
+
results: HTML
|
723 |
+
|
724 |
+
# - name: ebay
|
725 |
+
# engine: ebay
|
726 |
+
# shortcut: eb
|
727 |
+
# base_url: 'https://www.ebay.com'
|
728 |
+
# disabled: true
|
729 |
+
# timeout: 5
|
730 |
+
|
731 |
+
- name: 1x
|
732 |
+
engine: www1x
|
733 |
+
shortcut: 1x
|
734 |
+
timeout: 3.0
|
735 |
+
disabled: true
|
736 |
+
|
737 |
+
- name: fdroid
|
738 |
+
engine: fdroid
|
739 |
+
shortcut: fd
|
740 |
+
disabled: true
|
741 |
+
|
742 |
+
- name: flickr
|
743 |
+
categories: images
|
744 |
+
shortcut: fl
|
745 |
+
# You can use the engine using the official stable API, but you need an API
|
746 |
+
# key, see: https://www.flickr.com/services/apps/create/
|
747 |
+
# engine: flickr
|
748 |
+
# api_key: 'apikey' # required!
|
749 |
+
# Or you can use the html non-stable engine, activated by default
|
750 |
+
engine: flickr_noapi
|
751 |
+
|
752 |
+
- name: free software directory
|
753 |
+
engine: mediawiki
|
754 |
+
shortcut: fsd
|
755 |
+
categories: [it, software wikis]
|
756 |
+
base_url: https://directory.fsf.org/
|
757 |
+
search_type: title
|
758 |
+
timeout: 5.0
|
759 |
+
disabled: true
|
760 |
+
about:
|
761 |
+
website: https://directory.fsf.org/
|
762 |
+
wikidata_id: Q2470288
|
763 |
+
|
764 |
+
# - name: freesound
|
765 |
+
# engine: freesound
|
766 |
+
# shortcut: fnd
|
767 |
+
# disabled: true
|
768 |
+
# timeout: 15.0
|
769 |
+
# API key required, see: https://freesound.org/docs/api/overview.html
|
770 |
+
# api_key: MyAPIkey
|
771 |
+
|
772 |
+
- name: frinkiac
|
773 |
+
engine: frinkiac
|
774 |
+
shortcut: frk
|
775 |
+
disabled: true
|
776 |
+
|
777 |
+
- name: fyyd
|
778 |
+
engine: fyyd
|
779 |
+
shortcut: fy
|
780 |
+
timeout: 8.0
|
781 |
+
disabled: true
|
782 |
+
|
783 |
+
- name: genius
|
784 |
+
engine: genius
|
785 |
+
shortcut: gen
|
786 |
+
|
787 |
+
- name: gentoo
|
788 |
+
engine: gentoo
|
789 |
+
shortcut: ge
|
790 |
+
timeout: 10.0
|
791 |
+
|
792 |
+
- name: gitlab
|
793 |
+
engine: json_engine
|
794 |
+
paging: true
|
795 |
+
search_url: https://gitlab.com/api/v4/projects?search={query}&page={pageno}
|
796 |
+
url_query: web_url
|
797 |
+
title_query: name_with_namespace
|
798 |
+
content_query: description
|
799 |
+
page_size: 20
|
800 |
+
categories: [it, repos]
|
801 |
+
shortcut: gl
|
802 |
+
timeout: 10.0
|
803 |
+
disabled: true
|
804 |
+
about:
|
805 |
+
website: https://about.gitlab.com/
|
806 |
+
wikidata_id: Q16639197
|
807 |
+
official_api_documentation: https://docs.gitlab.com/ee/api/
|
808 |
+
use_official_api: false
|
809 |
+
require_api_key: false
|
810 |
+
results: JSON
|
811 |
+
|
812 |
+
- name: github
|
813 |
+
engine: github
|
814 |
+
shortcut: gh
|
815 |
+
|
816 |
+
# This a Gitea service. If you would like to use a different instance,
|
817 |
+
# change codeberg.org to URL of the desired Gitea host. Or you can create a
|
818 |
+
# new engine by copying this and changing the name, shortcut and search_url.
|
819 |
+
|
820 |
+
- name: codeberg
|
821 |
+
engine: json_engine
|
822 |
+
search_url: https://codeberg.org/api/v1/repos/search?q={query}&limit=10
|
823 |
+
url_query: html_url
|
824 |
+
title_query: name
|
825 |
+
content_query: description
|
826 |
+
categories: [it, repos]
|
827 |
+
shortcut: cb
|
828 |
+
disabled: true
|
829 |
+
about:
|
830 |
+
website: https://codeberg.org/
|
831 |
+
wikidata_id:
|
832 |
+
official_api_documentation: https://try.gitea.io/api/swagger
|
833 |
+
use_official_api: false
|
834 |
+
require_api_key: false
|
835 |
+
results: JSON
|
836 |
+
|
837 |
+
- name: goodreads
|
838 |
+
engine: goodreads
|
839 |
+
shortcut: good
|
840 |
+
timeout: 4.0
|
841 |
+
disabled: true
|
842 |
+
|
843 |
+
- name: google
|
844 |
+
engine: google
|
845 |
+
shortcut: go
|
846 |
+
# additional_tests:
|
847 |
+
# android: *test_android
|
848 |
+
|
849 |
+
- name: google images
|
850 |
+
engine: google_images
|
851 |
+
shortcut: goi
|
852 |
+
# additional_tests:
|
853 |
+
# android: *test_android
|
854 |
+
# dali:
|
855 |
+
# matrix:
|
856 |
+
# query: ['Dali Christ']
|
857 |
+
# lang: ['en', 'de', 'fr', 'zh-CN']
|
858 |
+
# result_container:
|
859 |
+
# - ['one_title_contains', 'Salvador']
|
860 |
+
|
861 |
+
- name: google news
|
862 |
+
engine: google_news
|
863 |
+
shortcut: gon
|
864 |
+
# additional_tests:
|
865 |
+
# android: *test_android
|
866 |
+
|
867 |
+
- name: google videos
|
868 |
+
engine: google_videos
|
869 |
+
shortcut: gov
|
870 |
+
# additional_tests:
|
871 |
+
# android: *test_android
|
872 |
+
|
873 |
+
- name: google scholar
|
874 |
+
engine: google_scholar
|
875 |
+
shortcut: gos
|
876 |
+
|
877 |
+
- name: google play apps
|
878 |
+
engine: google_play
|
879 |
+
categories: [files, apps]
|
880 |
+
shortcut: gpa
|
881 |
+
play_categ: apps
|
882 |
+
disabled: true
|
883 |
+
|
884 |
+
- name: google play movies
|
885 |
+
engine: google_play
|
886 |
+
categories: videos
|
887 |
+
shortcut: gpm
|
888 |
+
play_categ: movies
|
889 |
+
disabled: true
|
890 |
+
|
891 |
+
- name: material icons
|
892 |
+
engine: material_icons
|
893 |
+
categories: images
|
894 |
+
shortcut: mi
|
895 |
+
disabled: true
|
896 |
+
|
897 |
+
- name: gpodder
|
898 |
+
engine: json_engine
|
899 |
+
shortcut: gpod
|
900 |
+
timeout: 4.0
|
901 |
+
paging: false
|
902 |
+
search_url: https://gpodder.net/search.json?q={query}
|
903 |
+
url_query: url
|
904 |
+
title_query: title
|
905 |
+
content_query: description
|
906 |
+
page_size: 19
|
907 |
+
categories: music
|
908 |
+
disabled: true
|
909 |
+
about:
|
910 |
+
website: https://gpodder.net
|
911 |
+
wikidata_id: Q3093354
|
912 |
+
official_api_documentation: https://gpoddernet.readthedocs.io/en/latest/api/
|
913 |
+
use_official_api: false
|
914 |
+
requires_api_key: false
|
915 |
+
results: JSON
|
916 |
+
|
917 |
+
- name: habrahabr
|
918 |
+
engine: xpath
|
919 |
+
paging: true
|
920 |
+
search_url: https://habr.com/en/search/page{pageno}/?q={query}
|
921 |
+
results_xpath: //article[contains(@class, "tm-articles-list__item")]
|
922 |
+
url_xpath: .//a[@class="tm-title__link"]/@href
|
923 |
+
title_xpath: .//a[@class="tm-title__link"]
|
924 |
+
content_xpath: .//div[contains(@class, "article-formatted-body")]
|
925 |
+
categories: it
|
926 |
+
timeout: 4.0
|
927 |
+
disabled: true
|
928 |
+
shortcut: habr
|
929 |
+
about:
|
930 |
+
website: https://habr.com/
|
931 |
+
wikidata_id: Q4494434
|
932 |
+
official_api_documentation: https://habr.com/en/docs/help/api/
|
933 |
+
use_official_api: false
|
934 |
+
require_api_key: false
|
935 |
+
results: HTML
|
936 |
+
|
937 |
+
- name: hackernews
|
938 |
+
engine: hackernews
|
939 |
+
shortcut: hn
|
940 |
+
disabled: true
|
941 |
+
|
942 |
+
- name: hoogle
|
943 |
+
engine: xpath
|
944 |
+
search_url: https://hoogle.haskell.org/?hoogle={query}
|
945 |
+
results_xpath: '//div[@class="result"]'
|
946 |
+
title_xpath: './/div[@class="ans"]//a'
|
947 |
+
url_xpath: './/div[@class="ans"]//a/@href'
|
948 |
+
content_xpath: './/div[@class="from"]'
|
949 |
+
page_size: 20
|
950 |
+
categories: [it, packages]
|
951 |
+
shortcut: ho
|
952 |
+
about:
|
953 |
+
website: https://hoogle.haskell.org/
|
954 |
+
wikidata_id: Q34010
|
955 |
+
official_api_documentation: https://hackage.haskell.org/api
|
956 |
+
use_official_api: false
|
957 |
+
require_api_key: false
|
958 |
+
results: JSON
|
959 |
+
|
960 |
+
- name: imdb
|
961 |
+
engine: imdb
|
962 |
+
shortcut: imdb
|
963 |
+
timeout: 6.0
|
964 |
+
disabled: true
|
965 |
+
|
966 |
+
- name: imgur
|
967 |
+
engine: imgur
|
968 |
+
shortcut: img
|
969 |
+
disabled: true
|
970 |
+
|
971 |
+
- name: ina
|
972 |
+
engine: ina
|
973 |
+
shortcut: in
|
974 |
+
timeout: 6.0
|
975 |
+
disabled: true
|
976 |
+
|
977 |
+
- name: invidious
|
978 |
+
engine: invidious
|
979 |
+
# Instanes will be selected randomly, see https://api.invidious.io/ for
|
980 |
+
# instances that are stable (good uptime) and close to you.
|
981 |
+
base_url:
|
982 |
+
- https://invidious.io.lol
|
983 |
+
- https://invidious.fdn.fr
|
984 |
+
- https://yt.artemislena.eu
|
985 |
+
- https://invidious.tiekoetter.com
|
986 |
+
- https://invidious.flokinet.to
|
987 |
+
- https://vid.puffyan.us
|
988 |
+
- https://invidious.privacydev.net
|
989 |
+
- https://inv.tux.pizza
|
990 |
+
shortcut: iv
|
991 |
+
timeout: 3.0
|
992 |
+
disabled: true
|
993 |
+
|
994 |
+
- name: jisho
|
995 |
+
engine: jisho
|
996 |
+
shortcut: js
|
997 |
+
timeout: 3.0
|
998 |
+
disabled: true
|
999 |
+
|
1000 |
+
- name: kickass
|
1001 |
+
engine: kickass
|
1002 |
+
base_url:
|
1003 |
+
- https://kickasstorrents.to
|
1004 |
+
- https://kickasstorrents.cr
|
1005 |
+
- https://kickasstorrent.cr
|
1006 |
+
- https://kickass.sx
|
1007 |
+
- https://kat.am
|
1008 |
+
shortcut: kc
|
1009 |
+
timeout: 4.0
|
1010 |
+
|
1011 |
+
- name: lemmy communities
|
1012 |
+
engine: lemmy
|
1013 |
+
lemmy_type: Communities
|
1014 |
+
shortcut: leco
|
1015 |
+
|
1016 |
+
- name: lemmy users
|
1017 |
+
engine: lemmy
|
1018 |
+
network: lemmy communities
|
1019 |
+
lemmy_type: Users
|
1020 |
+
shortcut: leus
|
1021 |
+
|
1022 |
+
- name: lemmy posts
|
1023 |
+
engine: lemmy
|
1024 |
+
network: lemmy communities
|
1025 |
+
lemmy_type: Posts
|
1026 |
+
shortcut: lepo
|
1027 |
+
|
1028 |
+
- name: lemmy comments
|
1029 |
+
engine: lemmy
|
1030 |
+
network: lemmy communities
|
1031 |
+
lemmy_type: Comments
|
1032 |
+
shortcut: lecom
|
1033 |
+
|
1034 |
+
- name: library genesis
|
1035 |
+
engine: xpath
|
1036 |
+
# search_url: https://libgen.is/search.php?req={query}
|
1037 |
+
search_url: https://libgen.rs/search.php?req={query}
|
1038 |
+
url_xpath: //a[contains(@href,"book/index.php?md5")]/@href
|
1039 |
+
title_xpath: //a[contains(@href,"book/")]/text()[1]
|
1040 |
+
content_xpath: //td/a[1][contains(@href,"=author")]/text()
|
1041 |
+
categories: files
|
1042 |
+
timeout: 7.0
|
1043 |
+
disabled: true
|
1044 |
+
shortcut: lg
|
1045 |
+
about:
|
1046 |
+
website: https://libgen.fun/
|
1047 |
+
wikidata_id: Q22017206
|
1048 |
+
official_api_documentation:
|
1049 |
+
use_official_api: false
|
1050 |
+
require_api_key: false
|
1051 |
+
results: HTML
|
1052 |
+
|
1053 |
+
- name: z-library
|
1054 |
+
engine: zlibrary
|
1055 |
+
shortcut: zlib
|
1056 |
+
categories: files
|
1057 |
+
timeout: 7.0
|
1058 |
+
|
1059 |
+
- name: library of congress
|
1060 |
+
engine: loc
|
1061 |
+
shortcut: loc
|
1062 |
+
categories: images
|
1063 |
+
|
1064 |
+
- name: lingva
|
1065 |
+
engine: lingva
|
1066 |
+
shortcut: lv
|
1067 |
+
# set lingva instance in url, by default it will use the official instance
|
1068 |
+
# url: https://lingva.thedaviddelta.com
|
1069 |
+
|
1070 |
+
- name: lobste.rs
|
1071 |
+
engine: xpath
|
1072 |
+
search_url: https://lobste.rs/search?q={query}&what=stories&order=relevance
|
1073 |
+
results_xpath: //li[contains(@class, "story")]
|
1074 |
+
url_xpath: .//a[@class="u-url"]/@href
|
1075 |
+
title_xpath: .//a[@class="u-url"]
|
1076 |
+
content_xpath: .//a[@class="domain"]
|
1077 |
+
categories: it
|
1078 |
+
shortcut: lo
|
1079 |
+
timeout: 5.0
|
1080 |
+
disabled: true
|
1081 |
+
about:
|
1082 |
+
website: https://lobste.rs/
|
1083 |
+
wikidata_id: Q60762874
|
1084 |
+
official_api_documentation:
|
1085 |
+
use_official_api: false
|
1086 |
+
require_api_key: false
|
1087 |
+
results: HTML
|
1088 |
+
|
1089 |
+
- name: azlyrics
|
1090 |
+
shortcut: lyrics
|
1091 |
+
engine: xpath
|
1092 |
+
timeout: 4.0
|
1093 |
+
disabled: true
|
1094 |
+
categories: [music, lyrics]
|
1095 |
+
paging: true
|
1096 |
+
search_url: https://search.azlyrics.com/search.php?q={query}&w=lyrics&p={pageno}
|
1097 |
+
url_xpath: //td[@class="text-left visitedlyr"]/a/@href
|
1098 |
+
title_xpath: //span/b/text()
|
1099 |
+
content_xpath: //td[@class="text-left visitedlyr"]/a/small
|
1100 |
+
about:
|
1101 |
+
website: https://azlyrics.com
|
1102 |
+
wikidata_id: Q66372542
|
1103 |
+
official_api_documentation:
|
1104 |
+
use_official_api: false
|
1105 |
+
require_api_key: false
|
1106 |
+
results: HTML
|
1107 |
+
|
1108 |
+
- name: mastodon users
|
1109 |
+
engine: mastodon
|
1110 |
+
mastodon_type: accounts
|
1111 |
+
base_url: https://mastodon.social
|
1112 |
+
shortcut: mau
|
1113 |
+
|
1114 |
+
- name: mastodon hashtags
|
1115 |
+
engine: mastodon
|
1116 |
+
mastodon_type: hashtags
|
1117 |
+
base_url: https://mastodon.social
|
1118 |
+
shortcut: mah
|
1119 |
+
|
1120 |
+
# - name: matrixrooms
|
1121 |
+
# engine: mrs
|
1122 |
+
# # https://docs.searxng.org/dev/engines/online/mrs.html
|
1123 |
+
# # base_url: https://mrs-api-host
|
1124 |
+
# shortcut: mtrx
|
1125 |
+
# disabled: true
|
1126 |
+
|
1127 |
+
- name: mdn
|
1128 |
+
shortcut: mdn
|
1129 |
+
engine: json_engine
|
1130 |
+
categories: [it]
|
1131 |
+
paging: true
|
1132 |
+
search_url: https://developer.mozilla.org/api/v1/search?q={query}&page={pageno}
|
1133 |
+
results_query: documents
|
1134 |
+
url_query: mdn_url
|
1135 |
+
url_prefix: https://developer.mozilla.org
|
1136 |
+
title_query: title
|
1137 |
+
content_query: summary
|
1138 |
+
about:
|
1139 |
+
website: https://developer.mozilla.org
|
1140 |
+
wikidata_id: Q3273508
|
1141 |
+
official_api_documentation: null
|
1142 |
+
use_official_api: false
|
1143 |
+
require_api_key: false
|
1144 |
+
results: JSON
|
1145 |
+
|
1146 |
+
- name: metacpan
|
1147 |
+
engine: metacpan
|
1148 |
+
shortcut: cpan
|
1149 |
+
disabled: true
|
1150 |
+
number_of_results: 20
|
1151 |
+
|
1152 |
+
# - name: meilisearch
|
1153 |
+
# engine: meilisearch
|
1154 |
+
# shortcut: mes
|
1155 |
+
# enable_http: true
|
1156 |
+
# base_url: http://localhost:7700
|
1157 |
+
# index: my-index
|
1158 |
+
|
1159 |
+
- name: mixcloud
|
1160 |
+
engine: mixcloud
|
1161 |
+
shortcut: mc
|
1162 |
+
|
1163 |
+
# MongoDB engine
|
1164 |
+
# Required dependency: pymongo
|
1165 |
+
# - name: mymongo
|
1166 |
+
# engine: mongodb
|
1167 |
+
# shortcut: md
|
1168 |
+
# exact_match_only: false
|
1169 |
+
# host: '127.0.0.1'
|
1170 |
+
# port: 27017
|
1171 |
+
# enable_http: true
|
1172 |
+
# results_per_page: 20
|
1173 |
+
# database: 'business'
|
1174 |
+
# collection: 'reviews' # name of the db collection
|
1175 |
+
# key: 'name' # key in the collection to search for
|
1176 |
+
|
1177 |
+
- name: mozhi
|
1178 |
+
engine: mozhi
|
1179 |
+
base_url:
|
1180 |
+
- https://mozhi.aryak.me
|
1181 |
+
- https://translate.bus-hit.me
|
1182 |
+
- https://nyc1.mz.ggtyler.dev
|
1183 |
+
# mozhi_engine: google - see https://mozhi.aryak.me for supported engines
|
1184 |
+
timeout: 4.0
|
1185 |
+
shortcut: mz
|
1186 |
+
disabled: true
|
1187 |
+
|
1188 |
+
- name: mwmbl
|
1189 |
+
engine: mwmbl
|
1190 |
+
# api_url: https://api.mwmbl.org
|
1191 |
+
shortcut: mwm
|
1192 |
+
disabled: true
|
1193 |
+
|
1194 |
+
- name: npm
|
1195 |
+
engine: npm
|
1196 |
+
shortcut: npm
|
1197 |
+
timeout: 5.0
|
1198 |
+
disabled: true
|
1199 |
+
|
1200 |
+
- name: nyaa
|
1201 |
+
engine: nyaa
|
1202 |
+
shortcut: nt
|
1203 |
+
disabled: true
|
1204 |
+
|
1205 |
+
- name: mankier
|
1206 |
+
engine: json_engine
|
1207 |
+
search_url: https://www.mankier.com/api/v2/mans/?q={query}
|
1208 |
+
results_query: results
|
1209 |
+
url_query: url
|
1210 |
+
title_query: name
|
1211 |
+
content_query: description
|
1212 |
+
categories: it
|
1213 |
+
shortcut: man
|
1214 |
+
about:
|
1215 |
+
website: https://www.mankier.com/
|
1216 |
+
official_api_documentation: https://www.mankier.com/api
|
1217 |
+
use_official_api: true
|
1218 |
+
require_api_key: false
|
1219 |
+
results: JSON
|
1220 |
+
|
1221 |
+
# read https://docs.searxng.org/dev/engines/online/mullvad_leta.html
|
1222 |
+
# - name: mullvadleta
|
1223 |
+
# engine: mullvad_leta
|
1224 |
+
# use_cache: true # Only 100 non-cache searches per day, suggested only for private instances
|
1225 |
+
# search_url: https://leta.mullvad.net
|
1226 |
+
# categories: [general, web]
|
1227 |
+
# shortcut: ml
|
1228 |
+
|
1229 |
+
- name: odysee
|
1230 |
+
engine: odysee
|
1231 |
+
shortcut: od
|
1232 |
+
disabled: true
|
1233 |
+
|
1234 |
+
- name: openairedatasets
|
1235 |
+
engine: json_engine
|
1236 |
+
paging: true
|
1237 |
+
search_url: https://api.openaire.eu/search/datasets?format=json&page={pageno}&size=10&title={query}
|
1238 |
+
results_query: response/results/result
|
1239 |
+
url_query: metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
|
1240 |
+
title_query: metadata/oaf:entity/oaf:result/title/$
|
1241 |
+
content_query: metadata/oaf:entity/oaf:result/description/$
|
1242 |
+
content_html_to_text: true
|
1243 |
+
categories: "science"
|
1244 |
+
shortcut: oad
|
1245 |
+
timeout: 5.0
|
1246 |
+
about:
|
1247 |
+
website: https://www.openaire.eu/
|
1248 |
+
wikidata_id: Q25106053
|
1249 |
+
official_api_documentation: https://api.openaire.eu/
|
1250 |
+
use_official_api: false
|
1251 |
+
require_api_key: false
|
1252 |
+
results: JSON
|
1253 |
+
|
1254 |
+
- name: openairepublications
|
1255 |
+
engine: json_engine
|
1256 |
+
paging: true
|
1257 |
+
search_url: https://api.openaire.eu/search/publications?format=json&page={pageno}&size=10&title={query}
|
1258 |
+
results_query: response/results/result
|
1259 |
+
url_query: metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
|
1260 |
+
title_query: metadata/oaf:entity/oaf:result/title/$
|
1261 |
+
content_query: metadata/oaf:entity/oaf:result/description/$
|
1262 |
+
content_html_to_text: true
|
1263 |
+
categories: science
|
1264 |
+
shortcut: oap
|
1265 |
+
timeout: 5.0
|
1266 |
+
about:
|
1267 |
+
website: https://www.openaire.eu/
|
1268 |
+
wikidata_id: Q25106053
|
1269 |
+
official_api_documentation: https://api.openaire.eu/
|
1270 |
+
use_official_api: false
|
1271 |
+
require_api_key: false
|
1272 |
+
results: JSON
|
1273 |
+
|
1274 |
+
- name: openmeteo
|
1275 |
+
engine: open_meteo
|
1276 |
+
shortcut: om
|
1277 |
+
disabled: true
|
1278 |
+
|
1279 |
+
# - name: opensemanticsearch
|
1280 |
+
# engine: opensemantic
|
1281 |
+
# shortcut: oss
|
1282 |
+
# base_url: 'http://localhost:8983/solr/opensemanticsearch/'
|
1283 |
+
|
1284 |
+
- name: openstreetmap
|
1285 |
+
engine: openstreetmap
|
1286 |
+
shortcut: osm
|
1287 |
+
|
1288 |
+
- name: openrepos
|
1289 |
+
engine: xpath
|
1290 |
+
paging: true
|
1291 |
+
search_url: https://openrepos.net/search/node/{query}?page={pageno}
|
1292 |
+
url_xpath: //li[@class="search-result"]//h3[@class="title"]/a/@href
|
1293 |
+
title_xpath: //li[@class="search-result"]//h3[@class="title"]/a
|
1294 |
+
content_xpath: //li[@class="search-result"]//div[@class="search-snippet-info"]//p[@class="search-snippet"]
|
1295 |
+
categories: files
|
1296 |
+
timeout: 4.0
|
1297 |
+
disabled: true
|
1298 |
+
shortcut: or
|
1299 |
+
about:
|
1300 |
+
website: https://openrepos.net/
|
1301 |
+
wikidata_id:
|
1302 |
+
official_api_documentation:
|
1303 |
+
use_official_api: false
|
1304 |
+
require_api_key: false
|
1305 |
+
results: HTML
|
1306 |
+
|
1307 |
+
- name: packagist
|
1308 |
+
engine: json_engine
|
1309 |
+
paging: true
|
1310 |
+
search_url: https://packagist.org/search.json?q={query}&page={pageno}
|
1311 |
+
results_query: results
|
1312 |
+
url_query: url
|
1313 |
+
title_query: name
|
1314 |
+
content_query: description
|
1315 |
+
categories: [it, packages]
|
1316 |
+
disabled: true
|
1317 |
+
timeout: 5.0
|
1318 |
+
shortcut: pack
|
1319 |
+
about:
|
1320 |
+
website: https://packagist.org
|
1321 |
+
wikidata_id: Q108311377
|
1322 |
+
official_api_documentation: https://packagist.org/apidoc
|
1323 |
+
use_official_api: true
|
1324 |
+
require_api_key: false
|
1325 |
+
results: JSON
|
1326 |
+
|
1327 |
+
- name: pdbe
|
1328 |
+
engine: pdbe
|
1329 |
+
shortcut: pdb
|
1330 |
+
# Hide obsolete PDB entries. Default is not to hide obsolete structures
|
1331 |
+
# hide_obsolete: false
|
1332 |
+
|
1333 |
+
- name: photon
|
1334 |
+
engine: photon
|
1335 |
+
shortcut: ph
|
1336 |
+
|
1337 |
+
- name: pinterest
|
1338 |
+
engine: pinterest
|
1339 |
+
shortcut: pin
|
1340 |
+
|
1341 |
+
- name: piped
|
1342 |
+
engine: piped
|
1343 |
+
shortcut: ppd
|
1344 |
+
categories: videos
|
1345 |
+
piped_filter: videos
|
1346 |
+
timeout: 3.0
|
1347 |
+
|
1348 |
+
# URL to use as link and for embeds
|
1349 |
+
frontend_url: https://srv.piped.video
|
1350 |
+
# Instance will be selected randomly, for more see https://piped-instances.kavin.rocks/
|
1351 |
+
backend_url:
|
1352 |
+
- https://pipedapi.kavin.rocks
|
1353 |
+
- https://pipedapi-libre.kavin.rocks
|
1354 |
+
- https://pipedapi.adminforge.de
|
1355 |
+
|
1356 |
+
- name: piped.music
|
1357 |
+
engine: piped
|
1358 |
+
network: piped
|
1359 |
+
shortcut: ppdm
|
1360 |
+
categories: music
|
1361 |
+
piped_filter: music_songs
|
1362 |
+
timeout: 3.0
|
1363 |
+
|
1364 |
+
- name: piratebay
|
1365 |
+
engine: piratebay
|
1366 |
+
shortcut: tpb
|
1367 |
+
# You may need to change this URL to a proxy if piratebay is blocked in your
|
1368 |
+
# country
|
1369 |
+
url: https://thepiratebay.org/
|
1370 |
+
timeout: 3.0
|
1371 |
+
|
1372 |
+
- name: pixiv
|
1373 |
+
shortcut: pv
|
1374 |
+
engine: pixiv
|
1375 |
+
disabled: true
|
1376 |
+
inactive: true
|
1377 |
+
pixiv_image_proxies:
|
1378 |
+
- https://pximg.example.org
|
1379 |
+
# A proxy is required to load the images. Hosting an image proxy server
|
1380 |
+
# for Pixiv:
|
1381 |
+
# --> https://pixivfe.pages.dev/hosting-image-proxy-server/
|
1382 |
+
# Proxies from public instances. Ask the public instances owners if they
|
1383 |
+
# agree to receive traffic from SearXNG!
|
1384 |
+
# --> https://codeberg.org/VnPower/PixivFE#instances
|
1385 |
+
# --> https://github.com/searxng/searxng/pull/3192#issuecomment-1941095047
|
1386 |
+
# image proxy of https://pixiv.cat
|
1387 |
+
# - https://i.pixiv.cat
|
1388 |
+
# image proxy of https://www.pixiv.pics
|
1389 |
+
# - https://pximg.cocomi.eu.org
|
1390 |
+
# image proxy of https://pixivfe.exozy.me
|
1391 |
+
# - https://pximg.exozy.me
|
1392 |
+
# image proxy of https://pixivfe.ducks.party
|
1393 |
+
# - https://pixiv.ducks.party
|
1394 |
+
# image proxy of https://pixiv.perennialte.ch
|
1395 |
+
# - https://pximg.perennialte.ch
|
1396 |
+
|
1397 |
+
- name: podcastindex
|
1398 |
+
engine: podcastindex
|
1399 |
+
shortcut: podcast
|
1400 |
+
|
1401 |
+
# Required dependency: psychopg2
|
1402 |
+
# - name: postgresql
|
1403 |
+
# engine: postgresql
|
1404 |
+
# database: postgres
|
1405 |
+
# username: postgres
|
1406 |
+
# password: postgres
|
1407 |
+
# limit: 10
|
1408 |
+
# query_str: 'SELECT * from my_table WHERE my_column = %(query)s'
|
1409 |
+
# shortcut : psql
|
1410 |
+
|
1411 |
+
- name: presearch
|
1412 |
+
engine: presearch
|
1413 |
+
search_type: search
|
1414 |
+
categories: [general, web]
|
1415 |
+
shortcut: ps
|
1416 |
+
timeout: 4.0
|
1417 |
+
disabled: true
|
1418 |
+
|
1419 |
+
- name: presearch images
|
1420 |
+
engine: presearch
|
1421 |
+
network: presearch
|
1422 |
+
search_type: images
|
1423 |
+
categories: [images, web]
|
1424 |
+
timeout: 4.0
|
1425 |
+
shortcut: psimg
|
1426 |
+
disabled: true
|
1427 |
+
|
1428 |
+
- name: presearch videos
|
1429 |
+
engine: presearch
|
1430 |
+
network: presearch
|
1431 |
+
search_type: videos
|
1432 |
+
categories: [general, web]
|
1433 |
+
timeout: 4.0
|
1434 |
+
shortcut: psvid
|
1435 |
+
disabled: true
|
1436 |
+
|
1437 |
+
- name: presearch news
|
1438 |
+
engine: presearch
|
1439 |
+
network: presearch
|
1440 |
+
search_type: news
|
1441 |
+
categories: [news, web]
|
1442 |
+
timeout: 4.0
|
1443 |
+
shortcut: psnews
|
1444 |
+
disabled: true
|
1445 |
+
|
1446 |
+
- name: pub.dev
|
1447 |
+
engine: xpath
|
1448 |
+
shortcut: pd
|
1449 |
+
search_url: https://pub.dev/packages?q={query}&page={pageno}
|
1450 |
+
paging: true
|
1451 |
+
results_xpath: //div[contains(@class,"packages-item")]
|
1452 |
+
url_xpath: ./div/h3/a/@href
|
1453 |
+
title_xpath: ./div/h3/a
|
1454 |
+
content_xpath: ./div/div/div[contains(@class,"packages-description")]/span
|
1455 |
+
categories: [packages, it]
|
1456 |
+
timeout: 3.0
|
1457 |
+
disabled: true
|
1458 |
+
first_page_num: 1
|
1459 |
+
about:
|
1460 |
+
website: https://pub.dev/
|
1461 |
+
official_api_documentation: https://pub.dev/help/api
|
1462 |
+
use_official_api: false
|
1463 |
+
require_api_key: false
|
1464 |
+
results: HTML
|
1465 |
+
|
1466 |
+
- name: pubmed
|
1467 |
+
engine: pubmed
|
1468 |
+
shortcut: pub
|
1469 |
+
timeout: 3.0
|
1470 |
+
|
1471 |
+
- name: pypi
|
1472 |
+
shortcut: pypi
|
1473 |
+
engine: pypi
|
1474 |
+
|
1475 |
+
- name: qwant
|
1476 |
+
qwant_categ: web
|
1477 |
+
engine: qwant
|
1478 |
+
shortcut: qw
|
1479 |
+
categories: [general, web]
|
1480 |
+
additional_tests:
|
1481 |
+
rosebud: *test_rosebud
|
1482 |
+
|
1483 |
+
- name: qwant news
|
1484 |
+
qwant_categ: news
|
1485 |
+
engine: qwant
|
1486 |
+
shortcut: qwn
|
1487 |
+
categories: news
|
1488 |
+
network: qwant
|
1489 |
+
|
1490 |
+
- name: qwant images
|
1491 |
+
qwant_categ: images
|
1492 |
+
engine: qwant
|
1493 |
+
shortcut: qwi
|
1494 |
+
categories: [images, web]
|
1495 |
+
network: qwant
|
1496 |
+
|
1497 |
+
- name: qwant videos
|
1498 |
+
qwant_categ: videos
|
1499 |
+
engine: qwant
|
1500 |
+
shortcut: qwv
|
1501 |
+
categories: [videos, web]
|
1502 |
+
network: qwant
|
1503 |
+
|
1504 |
+
# - name: library
|
1505 |
+
# engine: recoll
|
1506 |
+
# shortcut: lib
|
1507 |
+
# base_url: 'https://recoll.example.org/'
|
1508 |
+
# search_dir: ''
|
1509 |
+
# mount_prefix: /export
|
1510 |
+
# dl_prefix: 'https://download.example.org'
|
1511 |
+
# timeout: 30.0
|
1512 |
+
# categories: files
|
1513 |
+
# disabled: true
|
1514 |
+
|
1515 |
+
# - name: recoll library reference
|
1516 |
+
# engine: recoll
|
1517 |
+
# base_url: 'https://recoll.example.org/'
|
1518 |
+
# search_dir: reference
|
1519 |
+
# mount_prefix: /export
|
1520 |
+
# dl_prefix: 'https://download.example.org'
|
1521 |
+
# shortcut: libr
|
1522 |
+
# timeout: 30.0
|
1523 |
+
# categories: files
|
1524 |
+
# disabled: true
|
1525 |
+
|
1526 |
+
- name: radio browser
|
1527 |
+
engine: radio_browser
|
1528 |
+
shortcut: rb
|
1529 |
+
|
1530 |
+
- name: reddit
|
1531 |
+
engine: reddit
|
1532 |
+
shortcut: re
|
1533 |
+
page_size: 25
|
1534 |
+
|
1535 |
+
- name: rottentomatoes
|
1536 |
+
engine: rottentomatoes
|
1537 |
+
shortcut: rt
|
1538 |
+
disabled: true
|
1539 |
+
|
1540 |
+
# Required dependency: redis
|
1541 |
+
# - name: myredis
|
1542 |
+
# shortcut : rds
|
1543 |
+
# engine: redis_server
|
1544 |
+
# exact_match_only: false
|
1545 |
+
# host: '127.0.0.1'
|
1546 |
+
# port: 6379
|
1547 |
+
# enable_http: true
|
1548 |
+
# password: ''
|
1549 |
+
# db: 0
|
1550 |
+
|
1551 |
+
# tmp suspended: bad certificate
|
1552 |
+
# - name: scanr structures
|
1553 |
+
# shortcut: scs
|
1554 |
+
# engine: scanr_structures
|
1555 |
+
# disabled: true
|
1556 |
+
|
1557 |
+
- name: sepiasearch
|
1558 |
+
engine: sepiasearch
|
1559 |
+
shortcut: sep
|
1560 |
+
|
1561 |
+
- name: soundcloud
|
1562 |
+
engine: soundcloud
|
1563 |
+
shortcut: sc
|
1564 |
+
|
1565 |
+
- name: stackoverflow
|
1566 |
+
engine: stackexchange
|
1567 |
+
shortcut: st
|
1568 |
+
api_site: 'stackoverflow'
|
1569 |
+
categories: [it, q&a]
|
1570 |
+
|
1571 |
+
- name: askubuntu
|
1572 |
+
engine: stackexchange
|
1573 |
+
shortcut: ubuntu
|
1574 |
+
api_site: 'askubuntu'
|
1575 |
+
categories: [it, q&a]
|
1576 |
+
|
1577 |
+
- name: internetarchivescholar
|
1578 |
+
engine: internet_archive_scholar
|
1579 |
+
shortcut: ias
|
1580 |
+
timeout: 15.0
|
1581 |
+
|
1582 |
+
- name: superuser
|
1583 |
+
engine: stackexchange
|
1584 |
+
shortcut: su
|
1585 |
+
api_site: 'superuser'
|
1586 |
+
categories: [it, q&a]
|
1587 |
+
|
1588 |
+
- name: searchcode code
|
1589 |
+
engine: searchcode_code
|
1590 |
+
shortcut: scc
|
1591 |
+
disabled: true
|
1592 |
+
|
1593 |
+
# - name: searx
|
1594 |
+
# engine: searx_engine
|
1595 |
+
# shortcut: se
|
1596 |
+
# instance_urls :
|
1597 |
+
# - http://127.0.0.1:8888/
|
1598 |
+
# - ...
|
1599 |
+
# disabled: true
|
1600 |
+
|
1601 |
+
- name: semantic scholar
|
1602 |
+
engine: semantic_scholar
|
1603 |
+
disabled: true
|
1604 |
+
shortcut: se
|
1605 |
+
|
1606 |
+
# Spotify needs API credentials
|
1607 |
+
# - name: spotify
|
1608 |
+
# engine: spotify
|
1609 |
+
# shortcut: stf
|
1610 |
+
# api_client_id: *******
|
1611 |
+
# api_client_secret: *******
|
1612 |
+
|
1613 |
+
# - name: solr
|
1614 |
+
# engine: solr
|
1615 |
+
# shortcut: slr
|
1616 |
+
# base_url: http://localhost:8983
|
1617 |
+
# collection: collection_name
|
1618 |
+
# sort: '' # sorting: asc or desc
|
1619 |
+
# field_list: '' # comma separated list of field names to display on the UI
|
1620 |
+
# default_fields: '' # default field to query
|
1621 |
+
# query_fields: '' # query fields
|
1622 |
+
# enable_http: true
|
1623 |
+
|
1624 |
+
# - name: springer nature
|
1625 |
+
# engine: springer
|
1626 |
+
# # get your API key from: https://dev.springernature.com/signup
|
1627 |
+
# # working API key, for test & debug: "a69685087d07eca9f13db62f65b8f601"
|
1628 |
+
# api_key: 'unset'
|
1629 |
+
# shortcut: springer
|
1630 |
+
# timeout: 15.0
|
1631 |
+
|
1632 |
+
- name: startpage
|
1633 |
+
engine: startpage
|
1634 |
+
shortcut: sp
|
1635 |
+
timeout: 6.0
|
1636 |
+
disabled: true
|
1637 |
+
additional_tests:
|
1638 |
+
rosebud: *test_rosebud
|
1639 |
+
|
1640 |
+
- name: tokyotoshokan
|
1641 |
+
engine: tokyotoshokan
|
1642 |
+
shortcut: tt
|
1643 |
+
timeout: 6.0
|
1644 |
+
disabled: true
|
1645 |
+
|
1646 |
+
- name: solidtorrents
|
1647 |
+
engine: solidtorrents
|
1648 |
+
shortcut: solid
|
1649 |
+
timeout: 4.0
|
1650 |
+
base_url:
|
1651 |
+
- https://solidtorrents.to
|
1652 |
+
- https://bitsearch.to
|
1653 |
+
|
1654 |
+
# For this demo of the sqlite engine download:
|
1655 |
+
# https://liste.mediathekview.de/filmliste-v2.db.bz2
|
1656 |
+
# and unpack into searx/data/filmliste-v2.db
|
1657 |
+
# Query to test: "!demo concert"
|
1658 |
+
#
|
1659 |
+
# - name: demo
|
1660 |
+
# engine: sqlite
|
1661 |
+
# shortcut: demo
|
1662 |
+
# categories: general
|
1663 |
+
# result_template: default.html
|
1664 |
+
# database: searx/data/filmliste-v2.db
|
1665 |
+
# query_str: >-
|
1666 |
+
# SELECT title || ' (' || time(duration, 'unixepoch') || ')' AS title,
|
1667 |
+
# COALESCE( NULLIF(url_video_hd,''), NULLIF(url_video_sd,''), url_video) AS url,
|
1668 |
+
# description AS content
|
1669 |
+
# FROM film
|
1670 |
+
# WHERE title LIKE :wildcard OR description LIKE :wildcard
|
1671 |
+
# ORDER BY duration DESC
|
1672 |
+
|
1673 |
+
- name: tagesschau
|
1674 |
+
engine: tagesschau
|
1675 |
+
# when set to false, display URLs from Tagesschau, and not the actual source
|
1676 |
+
# (e.g. NDR, WDR, SWR, HR, ...)
|
1677 |
+
use_source_url: true
|
1678 |
+
shortcut: ts
|
1679 |
+
disabled: true
|
1680 |
+
|
1681 |
+
- name: tmdb
|
1682 |
+
engine: xpath
|
1683 |
+
paging: true
|
1684 |
+
categories: movies
|
1685 |
+
search_url: https://www.themoviedb.org/search?page={pageno}&query={query}
|
1686 |
+
results_xpath: //div[contains(@class,"movie") or contains(@class,"tv")]//div[contains(@class,"card")]
|
1687 |
+
url_xpath: .//div[contains(@class,"poster")]/a/@href
|
1688 |
+
thumbnail_xpath: .//img/@src
|
1689 |
+
title_xpath: .//div[contains(@class,"title")]//h2
|
1690 |
+
content_xpath: .//div[contains(@class,"overview")]
|
1691 |
+
shortcut: tm
|
1692 |
+
disabled: true
|
1693 |
+
|
1694 |
+
# Requires Tor
|
1695 |
+
- name: torch
|
1696 |
+
engine: xpath
|
1697 |
+
paging: true
|
1698 |
+
search_url:
|
1699 |
+
http://xmh57jrknzkhv6y3ls3ubitzfqnkrwxhopf5aygthi7d6rplyvk3noyd.onion/cgi-bin/omega/omega?P={query}&DEFAULTOP=and
|
1700 |
+
results_xpath: //table//tr
|
1701 |
+
url_xpath: ./td[2]/a
|
1702 |
+
title_xpath: ./td[2]/b
|
1703 |
+
content_xpath: ./td[2]/small
|
1704 |
+
categories: onions
|
1705 |
+
enable_http: true
|
1706 |
+
shortcut: tch
|
1707 |
+
|
1708 |
+
# torznab engine lets you query any torznab compatible indexer. Using this
|
1709 |
+
# engine in combination with Jackett opens the possibility to query a lot of
|
1710 |
+
# public and private indexers directly from SearXNG. More details at:
|
1711 |
+
# https://docs.searxng.org/dev/engines/online/torznab.html
|
1712 |
+
#
|
1713 |
+
# - name: Torznab EZTV
|
1714 |
+
# engine: torznab
|
1715 |
+
# shortcut: eztv
|
1716 |
+
# base_url: http://localhost:9117/api/v2.0/indexers/eztv/results/torznab
|
1717 |
+
# enable_http: true # if using localhost
|
1718 |
+
# api_key: xxxxxxxxxxxxxxx
|
1719 |
+
# show_magnet_links: true
|
1720 |
+
# show_torrent_files: false
|
1721 |
+
# # https://github.com/Jackett/Jackett/wiki/Jackett-Categories
|
1722 |
+
# torznab_categories: # optional
|
1723 |
+
# - 2000
|
1724 |
+
# - 5000
|
1725 |
+
|
1726 |
+
# tmp suspended - too slow, too many errors
|
1727 |
+
# - name: urbandictionary
|
1728 |
+
# engine : xpath
|
1729 |
+
# search_url : https://www.urbandictionary.com/define.php?term={query}
|
1730 |
+
# url_xpath : //*[@class="word"]/@href
|
1731 |
+
# title_xpath : //*[@class="def-header"]
|
1732 |
+
# content_xpath: //*[@class="meaning"]
|
1733 |
+
# shortcut: ud
|
1734 |
+
|
1735 |
+
- name: unsplash
|
1736 |
+
engine: unsplash
|
1737 |
+
shortcut: us
|
1738 |
+
|
1739 |
+
- name: yandex music
|
1740 |
+
engine: yandex_music
|
1741 |
+
shortcut: ydm
|
1742 |
+
disabled: true
|
1743 |
+
# https://yandex.com/support/music/access.html
|
1744 |
+
inactive: true
|
1745 |
+
|
1746 |
+
- name: yahoo
|
1747 |
+
engine: yahoo
|
1748 |
+
shortcut: yh
|
1749 |
+
disabled: true
|
1750 |
+
|
1751 |
+
- name: yahoo news
|
1752 |
+
engine: yahoo_news
|
1753 |
+
shortcut: yhn
|
1754 |
+
|
1755 |
+
- name: youtube
|
1756 |
+
shortcut: yt
|
1757 |
+
# You can use the engine using the official stable API, but you need an API
|
1758 |
+
# key See: https://console.developers.google.com/project
|
1759 |
+
#
|
1760 |
+
# engine: youtube_api
|
1761 |
+
# api_key: 'apikey' # required!
|
1762 |
+
#
|
1763 |
+
# Or you can use the html non-stable engine, activated by default
|
1764 |
+
engine: youtube_noapi
|
1765 |
+
|
1766 |
+
- name: dailymotion
|
1767 |
+
engine: dailymotion
|
1768 |
+
shortcut: dm
|
1769 |
+
|
1770 |
+
- name: vimeo
|
1771 |
+
engine: vimeo
|
1772 |
+
shortcut: vm
|
1773 |
+
|
1774 |
+
- name: wiby
|
1775 |
+
engine: json_engine
|
1776 |
+
paging: true
|
1777 |
+
search_url: https://wiby.me/json/?q={query}&p={pageno}
|
1778 |
+
url_query: URL
|
1779 |
+
title_query: Title
|
1780 |
+
content_query: Snippet
|
1781 |
+
categories: [general, web]
|
1782 |
+
shortcut: wib
|
1783 |
+
disabled: true
|
1784 |
+
about:
|
1785 |
+
website: https://wiby.me/
|
1786 |
+
|
1787 |
+
- name: alexandria
|
1788 |
+
engine: json_engine
|
1789 |
+
shortcut: alx
|
1790 |
+
categories: general
|
1791 |
+
paging: true
|
1792 |
+
search_url: https://api.alexandria.org/?a=1&q={query}&p={pageno}
|
1793 |
+
results_query: results
|
1794 |
+
title_query: title
|
1795 |
+
url_query: url
|
1796 |
+
content_query: snippet
|
1797 |
+
timeout: 1.5
|
1798 |
+
disabled: true
|
1799 |
+
about:
|
1800 |
+
website: https://alexandria.org/
|
1801 |
+
official_api_documentation: https://github.com/alexandria-org/alexandria-api/raw/master/README.md
|
1802 |
+
use_official_api: true
|
1803 |
+
require_api_key: false
|
1804 |
+
results: JSON
|
1805 |
+
|
1806 |
+
- name: wikibooks
|
1807 |
+
engine: mediawiki
|
1808 |
+
weight: 0.5
|
1809 |
+
shortcut: wb
|
1810 |
+
categories: [general, wikimedia]
|
1811 |
+
base_url: "https://{language}.wikibooks.org/"
|
1812 |
+
search_type: text
|
1813 |
+
disabled: true
|
1814 |
+
about:
|
1815 |
+
website: https://www.wikibooks.org/
|
1816 |
+
wikidata_id: Q367
|
1817 |
+
|
1818 |
+
- name: wikinews
|
1819 |
+
engine: mediawiki
|
1820 |
+
shortcut: wn
|
1821 |
+
categories: [news, wikimedia]
|
1822 |
+
base_url: "https://{language}.wikinews.org/"
|
1823 |
+
search_type: text
|
1824 |
+
srsort: create_timestamp_desc
|
1825 |
+
about:
|
1826 |
+
website: https://www.wikinews.org/
|
1827 |
+
wikidata_id: Q964
|
1828 |
+
|
1829 |
+
- name: wikiquote
|
1830 |
+
engine: mediawiki
|
1831 |
+
weight: 0.5
|
1832 |
+
shortcut: wq
|
1833 |
+
categories: [general, wikimedia]
|
1834 |
+
base_url: "https://{language}.wikiquote.org/"
|
1835 |
+
search_type: text
|
1836 |
+
disabled: true
|
1837 |
+
additional_tests:
|
1838 |
+
rosebud: *test_rosebud
|
1839 |
+
about:
|
1840 |
+
website: https://www.wikiquote.org/
|
1841 |
+
wikidata_id: Q369
|
1842 |
+
|
1843 |
+
- name: wikisource
|
1844 |
+
engine: mediawiki
|
1845 |
+
weight: 0.5
|
1846 |
+
shortcut: ws
|
1847 |
+
categories: [general, wikimedia]
|
1848 |
+
base_url: "https://{language}.wikisource.org/"
|
1849 |
+
search_type: text
|
1850 |
+
disabled: true
|
1851 |
+
about:
|
1852 |
+
website: https://www.wikisource.org/
|
1853 |
+
wikidata_id: Q263
|
1854 |
+
|
1855 |
+
- name: wikispecies
|
1856 |
+
engine: mediawiki
|
1857 |
+
shortcut: wsp
|
1858 |
+
categories: [general, science, wikimedia]
|
1859 |
+
base_url: "https://species.wikimedia.org/"
|
1860 |
+
search_type: text
|
1861 |
+
disabled: true
|
1862 |
+
about:
|
1863 |
+
website: https://species.wikimedia.org/
|
1864 |
+
wikidata_id: Q13679
|
1865 |
+
tests:
|
1866 |
+
wikispecies:
|
1867 |
+
matrix:
|
1868 |
+
query: "Campbell, L.I. et al. 2011: MicroRNAs"
|
1869 |
+
lang: en
|
1870 |
+
result_container:
|
1871 |
+
- not_empty
|
1872 |
+
- ['one_title_contains', 'Tardigrada']
|
1873 |
+
test:
|
1874 |
+
- unique_results
|
1875 |
+
|
1876 |
+
- name: wiktionary
|
1877 |
+
engine: mediawiki
|
1878 |
+
shortcut: wt
|
1879 |
+
categories: [dictionaries, wikimedia]
|
1880 |
+
base_url: "https://{language}.wiktionary.org/"
|
1881 |
+
search_type: text
|
1882 |
+
about:
|
1883 |
+
website: https://www.wiktionary.org/
|
1884 |
+
wikidata_id: Q151
|
1885 |
+
|
1886 |
+
- name: wikiversity
|
1887 |
+
engine: mediawiki
|
1888 |
+
weight: 0.5
|
1889 |
+
shortcut: wv
|
1890 |
+
categories: [general, wikimedia]
|
1891 |
+
base_url: "https://{language}.wikiversity.org/"
|
1892 |
+
search_type: text
|
1893 |
+
disabled: true
|
1894 |
+
about:
|
1895 |
+
website: https://www.wikiversity.org/
|
1896 |
+
wikidata_id: Q370
|
1897 |
+
|
1898 |
+
- name: wikivoyage
|
1899 |
+
engine: mediawiki
|
1900 |
+
weight: 0.5
|
1901 |
+
shortcut: wy
|
1902 |
+
categories: [general, wikimedia]
|
1903 |
+
base_url: "https://{language}.wikivoyage.org/"
|
1904 |
+
search_type: text
|
1905 |
+
disabled: true
|
1906 |
+
about:
|
1907 |
+
website: https://www.wikivoyage.org/
|
1908 |
+
wikidata_id: Q373
|
1909 |
+
|
1910 |
+
- name: wikicommons.images
|
1911 |
+
engine: wikicommons
|
1912 |
+
shortcut: wc
|
1913 |
+
categories: images
|
1914 |
+
number_of_results: 10
|
1915 |
+
|
1916 |
+
- name: wolframalpha
|
1917 |
+
shortcut: wa
|
1918 |
+
# You can use the engine using the official stable API, but you need an API
|
1919 |
+
# key. See: https://products.wolframalpha.com/api/
|
1920 |
+
#
|
1921 |
+
# engine: wolframalpha_api
|
1922 |
+
# api_key: ''
|
1923 |
+
#
|
1924 |
+
# Or you can use the html non-stable engine, activated by default
|
1925 |
+
engine: wolframalpha_noapi
|
1926 |
+
timeout: 6.0
|
1927 |
+
categories: general
|
1928 |
+
disabled: true
|
1929 |
+
|
1930 |
+
- name: dictzone
|
1931 |
+
engine: dictzone
|
1932 |
+
shortcut: dc
|
1933 |
+
|
1934 |
+
- name: mymemory translated
|
1935 |
+
engine: translated
|
1936 |
+
shortcut: tl
|
1937 |
+
timeout: 5.0
|
1938 |
+
# You can use without an API key, but you are limited to 1000 words/day
|
1939 |
+
# See: https://mymemory.translated.net/doc/usagelimits.php
|
1940 |
+
# api_key: ''
|
1941 |
+
|
1942 |
+
# Required dependency: mysql-connector-python
|
1943 |
+
# - name: mysql
|
1944 |
+
# engine: mysql_server
|
1945 |
+
# database: mydatabase
|
1946 |
+
# username: user
|
1947 |
+
# password: pass
|
1948 |
+
# limit: 10
|
1949 |
+
# query_str: 'SELECT * from mytable WHERE fieldname=%(query)s'
|
1950 |
+
# shortcut: mysql
|
1951 |
+
|
1952 |
+
- name: 1337x
|
1953 |
+
engine: 1337x
|
1954 |
+
shortcut: 1337x
|
1955 |
+
disabled: true
|
1956 |
+
|
1957 |
+
- name: duden
|
1958 |
+
engine: duden
|
1959 |
+
shortcut: du
|
1960 |
+
disabled: true
|
1961 |
+
|
1962 |
+
- name: seznam
|
1963 |
+
shortcut: szn
|
1964 |
+
engine: seznam
|
1965 |
+
disabled: true
|
1966 |
+
|
1967 |
+
# - name: deepl
|
1968 |
+
# engine: deepl
|
1969 |
+
# shortcut: dpl
|
1970 |
+
# # You can use the engine using the official stable API, but you need an API key
|
1971 |
+
# # See: https://www.deepl.com/pro-api?cta=header-pro-api
|
1972 |
+
# api_key: '' # required!
|
1973 |
+
# timeout: 5.0
|
1974 |
+
# disabled: true
|
1975 |
+
|
1976 |
+
- name: mojeek
|
1977 |
+
shortcut: mjk
|
1978 |
+
engine: xpath
|
1979 |
+
paging: true
|
1980 |
+
categories: [general, web]
|
1981 |
+
search_url: https://www.mojeek.com/search?q={query}&s={pageno}&lang={lang}&lb={lang}
|
1982 |
+
results_xpath: //ul[@class="results-standard"]/li/a[@class="ob"]
|
1983 |
+
url_xpath: ./@href
|
1984 |
+
title_xpath: ../h2/a
|
1985 |
+
content_xpath: ..//p[@class="s"]
|
1986 |
+
suggestion_xpath: //div[@class="top-info"]/p[@class="top-info spell"]/em/a
|
1987 |
+
first_page_num: 0
|
1988 |
+
page_size: 10
|
1989 |
+
max_page: 100
|
1990 |
+
disabled: true
|
1991 |
+
about:
|
1992 |
+
website: https://www.mojeek.com/
|
1993 |
+
wikidata_id: Q60747299
|
1994 |
+
official_api_documentation: https://www.mojeek.com/services/api.html/
|
1995 |
+
use_official_api: false
|
1996 |
+
require_api_key: false
|
1997 |
+
results: HTML
|
1998 |
+
|
1999 |
+
- name: moviepilot
|
2000 |
+
engine: moviepilot
|
2001 |
+
shortcut: mp
|
2002 |
+
disabled: true
|
2003 |
+
|
2004 |
+
- name: naver
|
2005 |
+
shortcut: nvr
|
2006 |
+
categories: [general, web]
|
2007 |
+
engine: xpath
|
2008 |
+
paging: true
|
2009 |
+
search_url: https://search.naver.com/search.naver?where=webkr&sm=osp_hty&ie=UTF-8&query={query}&start={pageno}
|
2010 |
+
url_xpath: //a[@class="link_tit"]/@href
|
2011 |
+
title_xpath: //a[@class="link_tit"]
|
2012 |
+
content_xpath: //div[@class="total_dsc_wrap"]/a
|
2013 |
+
first_page_num: 1
|
2014 |
+
page_size: 10
|
2015 |
+
disabled: true
|
2016 |
+
about:
|
2017 |
+
website: https://www.naver.com/
|
2018 |
+
wikidata_id: Q485639
|
2019 |
+
official_api_documentation: https://developers.naver.com/docs/nmt/examples/
|
2020 |
+
use_official_api: false
|
2021 |
+
require_api_key: false
|
2022 |
+
results: HTML
|
2023 |
+
language: ko
|
2024 |
+
|
2025 |
+
- name: rubygems
|
2026 |
+
shortcut: rbg
|
2027 |
+
engine: xpath
|
2028 |
+
paging: true
|
2029 |
+
search_url: https://rubygems.org/search?page={pageno}&query={query}
|
2030 |
+
results_xpath: /html/body/main/div/a[@class="gems__gem"]
|
2031 |
+
url_xpath: ./@href
|
2032 |
+
title_xpath: ./span/h2
|
2033 |
+
content_xpath: ./span/p
|
2034 |
+
suggestion_xpath: /html/body/main/div/div[@class="search__suggestions"]/p/a
|
2035 |
+
first_page_num: 1
|
2036 |
+
categories: [it, packages]
|
2037 |
+
disabled: true
|
2038 |
+
about:
|
2039 |
+
website: https://rubygems.org/
|
2040 |
+
wikidata_id: Q1853420
|
2041 |
+
official_api_documentation: https://guides.rubygems.org/rubygems-org-api/
|
2042 |
+
use_official_api: false
|
2043 |
+
require_api_key: false
|
2044 |
+
results: HTML
|
2045 |
+
|
2046 |
+
- name: peertube
|
2047 |
+
engine: peertube
|
2048 |
+
shortcut: ptb
|
2049 |
+
paging: true
|
2050 |
+
# alternatives see: https://instances.joinpeertube.org/instances
|
2051 |
+
# base_url: https://tube.4aem.com
|
2052 |
+
categories: videos
|
2053 |
+
disabled: true
|
2054 |
+
timeout: 6.0
|
2055 |
+
|
2056 |
+
- name: mediathekviewweb
|
2057 |
+
engine: mediathekviewweb
|
2058 |
+
shortcut: mvw
|
2059 |
+
disabled: true
|
2060 |
+
|
2061 |
+
- name: yacy
|
2062 |
+
engine: yacy
|
2063 |
+
categories: general
|
2064 |
+
search_type: text
|
2065 |
+
base_url: https://yacy.searchlab.eu
|
2066 |
+
shortcut: ya
|
2067 |
+
disabled: true
|
2068 |
+
# required if you aren't using HTTPS for your local yacy instance
|
2069 |
+
# https://docs.searxng.org/dev/engines/online/yacy.html
|
2070 |
+
# enable_http: true
|
2071 |
+
# timeout: 3.0
|
2072 |
+
# search_mode: 'global'
|
2073 |
+
|
2074 |
+
- name: yacy images
|
2075 |
+
engine: yacy
|
2076 |
+
categories: images
|
2077 |
+
search_type: image
|
2078 |
+
base_url: https://yacy.searchlab.eu
|
2079 |
+
shortcut: yai
|
2080 |
+
disabled: true
|
2081 |
+
|
2082 |
+
- name: rumble
|
2083 |
+
engine: rumble
|
2084 |
+
shortcut: ru
|
2085 |
+
base_url: https://rumble.com/
|
2086 |
+
paging: true
|
2087 |
+
categories: videos
|
2088 |
+
disabled: true
|
2089 |
+
|
2090 |
+
- name: livespace
|
2091 |
+
engine: livespace
|
2092 |
+
shortcut: ls
|
2093 |
+
categories: videos
|
2094 |
+
disabled: true
|
2095 |
+
timeout: 5.0
|
2096 |
+
|
2097 |
+
- name: wordnik
|
2098 |
+
engine: wordnik
|
2099 |
+
shortcut: def
|
2100 |
+
base_url: https://www.wordnik.com/
|
2101 |
+
categories: [dictionaries]
|
2102 |
+
timeout: 5.0
|
2103 |
+
|
2104 |
+
- name: woxikon.de synonyme
|
2105 |
+
engine: xpath
|
2106 |
+
shortcut: woxi
|
2107 |
+
categories: [dictionaries]
|
2108 |
+
timeout: 5.0
|
2109 |
+
disabled: true
|
2110 |
+
search_url: https://synonyme.woxikon.de/synonyme/{query}.php
|
2111 |
+
url_xpath: //div[@class="upper-synonyms"]/a/@href
|
2112 |
+
content_xpath: //div[@class="synonyms-list-group"]
|
2113 |
+
title_xpath: //div[@class="upper-synonyms"]/a
|
2114 |
+
no_result_for_http_status: [404]
|
2115 |
+
about:
|
2116 |
+
website: https://www.woxikon.de/
|
2117 |
+
wikidata_id: # No Wikidata ID
|
2118 |
+
use_official_api: false
|
2119 |
+
require_api_key: false
|
2120 |
+
results: HTML
|
2121 |
+
language: de
|
2122 |
+
|
2123 |
+
- name: seekr news
|
2124 |
+
engine: seekr
|
2125 |
+
shortcut: senews
|
2126 |
+
categories: news
|
2127 |
+
seekr_category: news
|
2128 |
+
disabled: true
|
2129 |
+
|
2130 |
+
- name: seekr images
|
2131 |
+
engine: seekr
|
2132 |
+
network: seekr news
|
2133 |
+
shortcut: seimg
|
2134 |
+
categories: images
|
2135 |
+
seekr_category: images
|
2136 |
+
disabled: true
|
2137 |
+
|
2138 |
+
- name: seekr videos
|
2139 |
+
engine: seekr
|
2140 |
+
network: seekr news
|
2141 |
+
shortcut: sevid
|
2142 |
+
categories: videos
|
2143 |
+
seekr_category: videos
|
2144 |
+
disabled: true
|
2145 |
+
|
2146 |
+
- name: sjp.pwn
|
2147 |
+
engine: sjp
|
2148 |
+
shortcut: sjp
|
2149 |
+
base_url: https://sjp.pwn.pl/
|
2150 |
+
timeout: 5.0
|
2151 |
+
disabled: true
|
2152 |
+
|
2153 |
+
- name: stract
|
2154 |
+
engine: stract
|
2155 |
+
shortcut: str
|
2156 |
+
disabled: true
|
2157 |
+
|
2158 |
+
- name: svgrepo
|
2159 |
+
engine: svgrepo
|
2160 |
+
shortcut: svg
|
2161 |
+
timeout: 10.0
|
2162 |
+
disabled: true
|
2163 |
+
|
2164 |
+
- name: tootfinder
|
2165 |
+
engine: tootfinder
|
2166 |
+
shortcut: toot
|
2167 |
+
|
2168 |
+
- name: voidlinux
|
2169 |
+
engine: voidlinux
|
2170 |
+
shortcut: void
|
2171 |
+
disabled: true
|
2172 |
+
|
2173 |
+
- name: wallhaven
|
2174 |
+
engine: wallhaven
|
2175 |
+
# api_key: abcdefghijklmnopqrstuvwxyz
|
2176 |
+
shortcut: wh
|
2177 |
+
|
2178 |
+
# wikimini: online encyclopedia for children
|
2179 |
+
# The fulltext and title parameter is necessary for Wikimini because
|
2180 |
+
# sometimes it will not show the results and redirect instead
|
2181 |
+
- name: wikimini
|
2182 |
+
engine: xpath
|
2183 |
+
shortcut: wkmn
|
2184 |
+
search_url: https://fr.wikimini.org/w/index.php?search={query}&title=Sp%C3%A9cial%3ASearch&fulltext=Search
|
2185 |
+
url_xpath: //li/div[@class="mw-search-result-heading"]/a/@href
|
2186 |
+
title_xpath: //li//div[@class="mw-search-result-heading"]/a
|
2187 |
+
content_xpath: //li/div[@class="searchresult"]
|
2188 |
+
categories: general
|
2189 |
+
disabled: true
|
2190 |
+
about:
|
2191 |
+
website: https://wikimini.org/
|
2192 |
+
wikidata_id: Q3568032
|
2193 |
+
use_official_api: false
|
2194 |
+
require_api_key: false
|
2195 |
+
results: HTML
|
2196 |
+
language: fr
|
2197 |
+
|
2198 |
+
- name: wttr.in
|
2199 |
+
engine: wttr
|
2200 |
+
shortcut: wttr
|
2201 |
+
timeout: 9.0
|
2202 |
+
|
2203 |
+
- name: yummly
|
2204 |
+
engine: yummly
|
2205 |
+
shortcut: yum
|
2206 |
+
disabled: true
|
2207 |
+
|
2208 |
+
- name: brave
|
2209 |
+
engine: brave
|
2210 |
+
shortcut: br
|
2211 |
+
time_range_support: true
|
2212 |
+
paging: true
|
2213 |
+
categories: [general, web]
|
2214 |
+
brave_category: search
|
2215 |
+
# brave_spellcheck: true
|
2216 |
+
|
2217 |
+
- name: brave.images
|
2218 |
+
engine: brave
|
2219 |
+
network: brave
|
2220 |
+
shortcut: brimg
|
2221 |
+
categories: [images, web]
|
2222 |
+
brave_category: images
|
2223 |
+
|
2224 |
+
- name: brave.videos
|
2225 |
+
engine: brave
|
2226 |
+
network: brave
|
2227 |
+
shortcut: brvid
|
2228 |
+
categories: [videos, web]
|
2229 |
+
brave_category: videos
|
2230 |
+
|
2231 |
+
- name: brave.news
|
2232 |
+
engine: brave
|
2233 |
+
network: brave
|
2234 |
+
shortcut: brnews
|
2235 |
+
categories: news
|
2236 |
+
brave_category: news
|
2237 |
+
|
2238 |
+
# - name: brave.goggles
|
2239 |
+
# engine: brave
|
2240 |
+
# network: brave
|
2241 |
+
# shortcut: brgog
|
2242 |
+
# time_range_support: true
|
2243 |
+
# paging: true
|
2244 |
+
# categories: [general, web]
|
2245 |
+
# brave_category: goggles
|
2246 |
+
# Goggles: # required! This should be a URL ending in .goggle
|
2247 |
+
|
2248 |
+
- name: lib.rs
|
2249 |
+
shortcut: lrs
|
2250 |
+
engine: lib_rs
|
2251 |
+
disabled: true
|
2252 |
+
|
2253 |
+
- name: sourcehut
|
2254 |
+
shortcut: srht
|
2255 |
+
engine: xpath
|
2256 |
+
paging: true
|
2257 |
+
search_url: https://sr.ht/projects?page={pageno}&search={query}
|
2258 |
+
results_xpath: (//div[@class="event-list"])[1]/div[@class="event"]
|
2259 |
+
url_xpath: ./h4/a[2]/@href
|
2260 |
+
title_xpath: ./h4/a[2]
|
2261 |
+
content_xpath: ./p
|
2262 |
+
first_page_num: 1
|
2263 |
+
categories: [it, repos]
|
2264 |
+
disabled: true
|
2265 |
+
about:
|
2266 |
+
website: https://sr.ht
|
2267 |
+
wikidata_id: Q78514485
|
2268 |
+
official_api_documentation: https://man.sr.ht/
|
2269 |
+
use_official_api: false
|
2270 |
+
require_api_key: false
|
2271 |
+
results: HTML
|
2272 |
+
|
2273 |
+
- name: goo
|
2274 |
+
shortcut: goo
|
2275 |
+
engine: xpath
|
2276 |
+
paging: true
|
2277 |
+
search_url: https://search.goo.ne.jp/web.jsp?MT={query}&FR={pageno}0
|
2278 |
+
url_xpath: //div[@class="result"]/p[@class='title fsL1']/a/@href
|
2279 |
+
title_xpath: //div[@class="result"]/p[@class='title fsL1']/a
|
2280 |
+
content_xpath: //p[contains(@class,'url fsM')]/following-sibling::p
|
2281 |
+
first_page_num: 0
|
2282 |
+
categories: [general, web]
|
2283 |
+
disabled: true
|
2284 |
+
timeout: 4.0
|
2285 |
+
about:
|
2286 |
+
website: https://search.goo.ne.jp
|
2287 |
+
wikidata_id: Q249044
|
2288 |
+
use_official_api: false
|
2289 |
+
require_api_key: false
|
2290 |
+
results: HTML
|
2291 |
+
language: ja
|
2292 |
+
|
2293 |
+
- name: bt4g
|
2294 |
+
engine: bt4g
|
2295 |
+
shortcut: bt4g
|
2296 |
+
|
2297 |
+
- name: pkg.go.dev
|
2298 |
+
engine: pkg_go_dev
|
2299 |
+
shortcut: pgo
|
2300 |
+
disabled: true
|
2301 |
+
|
2302 |
+
# Doku engine lets you access to any Doku wiki instance:
|
2303 |
+
# A public one or a privete/corporate one.
|
2304 |
+
# - name: ubuntuwiki
|
2305 |
+
# engine: doku
|
2306 |
+
# shortcut: uw
|
2307 |
+
# base_url: 'https://doc.ubuntu-fr.org'
|
2308 |
+
|
2309 |
+
# Be careful when enabling this engine if you are
|
2310 |
+
# running a public instance. Do not expose any sensitive
|
2311 |
+
# information. You can restrict access by configuring a list
|
2312 |
+
# of access tokens under tokens.
|
2313 |
+
# - name: git grep
|
2314 |
+
# engine: command
|
2315 |
+
# command: ['git', 'grep', '{{QUERY}}']
|
2316 |
+
# shortcut: gg
|
2317 |
+
# tokens: []
|
2318 |
+
# disabled: true
|
2319 |
+
# delimiter:
|
2320 |
+
# chars: ':'
|
2321 |
+
# keys: ['filepath', 'code']
|
2322 |
+
|
2323 |
+
# Be careful when enabling this engine if you are
|
2324 |
+
# running a public instance. Do not expose any sensitive
|
2325 |
+
# information. You can restrict access by configuring a list
|
2326 |
+
# of access tokens under tokens.
|
2327 |
+
# - name: locate
|
2328 |
+
# engine: command
|
2329 |
+
# command: ['locate', '{{QUERY}}']
|
2330 |
+
# shortcut: loc
|
2331 |
+
# tokens: []
|
2332 |
+
# disabled: true
|
2333 |
+
# delimiter:
|
2334 |
+
# chars: ' '
|
2335 |
+
# keys: ['line']
|
2336 |
+
|
2337 |
+
# Be careful when enabling this engine if you are
|
2338 |
+
# running a public instance. Do not expose any sensitive
|
2339 |
+
# information. You can restrict access by configuring a list
|
2340 |
+
# of access tokens under tokens.
|
2341 |
+
# - name: find
|
2342 |
+
# engine: command
|
2343 |
+
# command: ['find', '.', '-name', '{{QUERY}}']
|
2344 |
+
# query_type: path
|
2345 |
+
# shortcut: fnd
|
2346 |
+
# tokens: []
|
2347 |
+
# disabled: true
|
2348 |
+
# delimiter:
|
2349 |
+
# chars: ' '
|
2350 |
+
# keys: ['line']
|
2351 |
+
|
2352 |
+
# Be careful when enabling this engine if you are
|
2353 |
+
# running a public instance. Do not expose any sensitive
|
2354 |
+
# information. You can restrict access by configuring a list
|
2355 |
+
# of access tokens under tokens.
|
2356 |
+
# - name: pattern search in files
|
2357 |
+
# engine: command
|
2358 |
+
# command: ['fgrep', '{{QUERY}}']
|
2359 |
+
# shortcut: fgr
|
2360 |
+
# tokens: []
|
2361 |
+
# disabled: true
|
2362 |
+
# delimiter:
|
2363 |
+
# chars: ' '
|
2364 |
+
# keys: ['line']
|
2365 |
+
|
2366 |
+
# Be careful when enabling this engine if you are
|
2367 |
+
# running a public instance. Do not expose any sensitive
|
2368 |
+
# information. You can restrict access by configuring a list
|
2369 |
+
# of access tokens under tokens.
|
2370 |
+
# - name: regex search in files
|
2371 |
+
# engine: command
|
2372 |
+
# command: ['grep', '{{QUERY}}']
|
2373 |
+
# shortcut: gr
|
2374 |
+
# tokens: []
|
2375 |
+
# disabled: true
|
2376 |
+
# delimiter:
|
2377 |
+
# chars: ' '
|
2378 |
+
# keys: ['line']
|
2379 |
+
|
2380 |
+
doi_resolvers:
|
2381 |
+
oadoi.org: 'https://oadoi.org/'
|
2382 |
+
doi.org: 'https://doi.org/'
|
2383 |
+
doai.io: 'https://dissem.in/'
|
2384 |
+
sci-hub.se: 'https://sci-hub.se/'
|
2385 |
+
sci-hub.st: 'https://sci-hub.st/'
|
2386 |
+
sci-hub.ru: 'https://sci-hub.ru/'
|
2387 |
+
|
2388 |
+
default_doi_resolver: 'oadoi.org'
|
searxng/settings.yml.new
ADDED
@@ -0,0 +1,2409 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
general:
|
2 |
+
# Debug mode, only for development. Is overwritten by ${SEARXNG_DEBUG}
|
3 |
+
debug: false
|
4 |
+
# displayed name
|
5 |
+
instance_name: "searxng"
|
6 |
+
# For example: https://example.com/privacy
|
7 |
+
privacypolicy_url: false
|
8 |
+
# use true to use your own donation page written in searx/info/en/donate.md
|
9 |
+
# use false to disable the donation link
|
10 |
+
donation_url: false
|
11 |
+
# mailto:[email protected]
|
12 |
+
contact_url: false
|
13 |
+
# record stats
|
14 |
+
enable_metrics: true
|
15 |
+
|
16 |
+
brand:
|
17 |
+
new_issue_url: https://github.com/searxng/searxng/issues/new
|
18 |
+
docs_url: https://docs.searxng.org/
|
19 |
+
public_instances: https://searx.space
|
20 |
+
wiki_url: https://github.com/searxng/searxng/wiki
|
21 |
+
issue_url: https://github.com/searxng/searxng/issues
|
22 |
+
# custom:
|
23 |
+
# maintainer: "Jon Doe"
|
24 |
+
# # Custom entries in the footer: [title]: [link]
|
25 |
+
# links:
|
26 |
+
# Uptime: https://uptime.searxng.org/history/darmarit-org
|
27 |
+
# About: "https://searxng.org"
|
28 |
+
|
29 |
+
search:
|
30 |
+
# Filter results. 0: None, 1: Moderate, 2: Strict
|
31 |
+
safe_search: 0
|
32 |
+
# Existing autocomplete backends: "dbpedia", "duckduckgo", "google", "yandex", "mwmbl",
|
33 |
+
# "seznam", "startpage", "stract", "swisscows", "qwant", "wikipedia" - leave blank to turn it off
|
34 |
+
# by default.
|
35 |
+
autocomplete: ""
|
36 |
+
# minimun characters to type before autocompleter starts
|
37 |
+
autocomplete_min: 4
|
38 |
+
# Default search language - leave blank to detect from browser information or
|
39 |
+
# use codes from 'languages.py'
|
40 |
+
default_lang: "auto"
|
41 |
+
# max_page: 0 # if engine supports paging, 0 means unlimited numbers of pages
|
42 |
+
# Available languages
|
43 |
+
# languages:
|
44 |
+
# - all
|
45 |
+
# - en
|
46 |
+
# - en-US
|
47 |
+
# - de
|
48 |
+
# - it-IT
|
49 |
+
# - fr
|
50 |
+
# - fr-BE
|
51 |
+
# ban time in seconds after engine errors
|
52 |
+
ban_time_on_fail: 5
|
53 |
+
# max ban time in seconds after engine errors
|
54 |
+
max_ban_time_on_fail: 120
|
55 |
+
suspended_times:
|
56 |
+
# Engine suspension time after error (in seconds; set to 0 to disable)
|
57 |
+
# For error "Access denied" and "HTTP error [402, 403]"
|
58 |
+
SearxEngineAccessDenied: 86400
|
59 |
+
# For error "CAPTCHA"
|
60 |
+
SearxEngineCaptcha: 86400
|
61 |
+
# For error "Too many request" and "HTTP error 429"
|
62 |
+
SearxEngineTooManyRequests: 3600
|
63 |
+
# Cloudflare CAPTCHA
|
64 |
+
cf_SearxEngineCaptcha: 1296000
|
65 |
+
cf_SearxEngineAccessDenied: 86400
|
66 |
+
# ReCAPTCHA
|
67 |
+
recaptcha_SearxEngineCaptcha: 604800
|
68 |
+
|
69 |
+
# remove format to deny access, use lower case.
|
70 |
+
# formats: [html, csv, json, rss]
|
71 |
+
formats:
|
72 |
+
- html
|
73 |
+
|
74 |
+
server:
|
75 |
+
# Is overwritten by ${SEARXNG_PORT} and ${SEARXNG_BIND_ADDRESS}
|
76 |
+
port: 8888
|
77 |
+
bind_address: "127.0.0.1"
|
78 |
+
# public URL of the instance, to ensure correct inbound links. Is overwritten
|
79 |
+
# by ${SEARXNG_URL}.
|
80 |
+
base_url: / # "http://example.com/location"
|
81 |
+
limiter: false # rate limit the number of request on the instance, block some bots
|
82 |
+
public_instance: false # enable features designed only for public instances
|
83 |
+
|
84 |
+
# If your instance owns a /etc/searxng/settings.yml file, then set the following
|
85 |
+
# values there.
|
86 |
+
|
87 |
+
secret_key: "6ad06405d0e28c84acd82593225781fa7d9523c91f52412c2a156591c3ad7600" # Is overwritten by ${SEARXNG_SECRET}
|
88 |
+
# Proxying image results through searx
|
89 |
+
image_proxy: false
|
90 |
+
# 1.0 and 1.1 are supported
|
91 |
+
http_protocol_version: "1.0"
|
92 |
+
# POST queries are more secure as they don't show up in history but may cause
|
93 |
+
# problems when using Firefox containers
|
94 |
+
method: "POST"
|
95 |
+
default_http_headers:
|
96 |
+
X-Content-Type-Options: nosniff
|
97 |
+
X-Download-Options: noopen
|
98 |
+
X-Robots-Tag: noindex, nofollow
|
99 |
+
Referrer-Policy: no-referrer
|
100 |
+
|
101 |
+
redis:
|
102 |
+
# URL to connect redis database. Is overwritten by ${SEARXNG_REDIS_URL}.
|
103 |
+
# https://docs.searxng.org/admin/settings/settings_redis.html#settings-redis
|
104 |
+
url: false
|
105 |
+
|
106 |
+
ui:
|
107 |
+
# Custom static path - leave it blank if you didn't change
|
108 |
+
static_path: ""
|
109 |
+
static_use_hash: false
|
110 |
+
# Custom templates path - leave it blank if you didn't change
|
111 |
+
templates_path: ""
|
112 |
+
# query_in_title: When true, the result page's titles contains the query
|
113 |
+
# it decreases the privacy, since the browser can records the page titles.
|
114 |
+
query_in_title: false
|
115 |
+
# infinite_scroll: When true, automatically loads the next page when scrolling to bottom of the current page.
|
116 |
+
infinite_scroll: false
|
117 |
+
# ui theme
|
118 |
+
default_theme: simple
|
119 |
+
# center the results ?
|
120 |
+
center_alignment: false
|
121 |
+
# URL prefix of the internet archive, don't forget trailing slash (if needed).
|
122 |
+
# cache_url: "https://webcache.googleusercontent.com/search?q=cache:"
|
123 |
+
# Default interface locale - leave blank to detect from browser information or
|
124 |
+
# use codes from the 'locales' config section
|
125 |
+
default_locale: ""
|
126 |
+
# Open result links in a new tab by default
|
127 |
+
# results_on_new_tab: false
|
128 |
+
theme_args:
|
129 |
+
# style of simple theme: auto, light, dark
|
130 |
+
simple_style: auto
|
131 |
+
# Perform search immediately if a category selected.
|
132 |
+
# Disable to select multiple categories at once and start the search manually.
|
133 |
+
search_on_category_select: true
|
134 |
+
# Hotkeys: default or vim
|
135 |
+
hotkeys: default
|
136 |
+
|
137 |
+
# Lock arbitrary settings on the preferences page. To find the ID of the user
|
138 |
+
# setting you want to lock, check the ID of the form on the page "preferences".
|
139 |
+
#
|
140 |
+
# preferences:
|
141 |
+
# lock:
|
142 |
+
# - language
|
143 |
+
# - autocomplete
|
144 |
+
# - method
|
145 |
+
# - query_in_title
|
146 |
+
|
147 |
+
# searx supports result proxification using an external service:
|
148 |
+
# https://github.com/asciimoo/morty uncomment below section if you have running
|
149 |
+
# morty proxy the key is base64 encoded (keep the !!binary notation)
|
150 |
+
# Note: since commit af77ec3, morty accepts a base64 encoded key.
|
151 |
+
#
|
152 |
+
# result_proxy:
|
153 |
+
# url: http://127.0.0.1:3000/
|
154 |
+
# # the key is a base64 encoded string, the YAML !!binary prefix is optional
|
155 |
+
# key: !!binary "your_morty_proxy_key"
|
156 |
+
# # [true|false] enable the "proxy" button next to each result
|
157 |
+
# proxify_results: true
|
158 |
+
|
159 |
+
# communication with search engines
|
160 |
+
#
|
161 |
+
outgoing:
|
162 |
+
# default timeout in seconds, can be override by engine
|
163 |
+
request_timeout: 3.0
|
164 |
+
# the maximum timeout in seconds
|
165 |
+
# max_request_timeout: 10.0
|
166 |
+
# suffix of searx_useragent, could contain information like an email address
|
167 |
+
# to the administrator
|
168 |
+
useragent_suffix: ""
|
169 |
+
# The maximum number of concurrent connections that may be established.
|
170 |
+
pool_connections: 100
|
171 |
+
# Allow the connection pool to maintain keep-alive connections below this
|
172 |
+
# point.
|
173 |
+
pool_maxsize: 20
|
174 |
+
# See https://www.python-httpx.org/http2/
|
175 |
+
enable_http2: true
|
176 |
+
# uncomment below section if you want to use a custom server certificate
|
177 |
+
# see https://www.python-httpx.org/advanced/#changing-the-verification-defaults
|
178 |
+
# and https://www.python-httpx.org/compatibility/#ssl-configuration
|
179 |
+
# verify: ~/.mitmproxy/mitmproxy-ca-cert.cer
|
180 |
+
#
|
181 |
+
# uncomment below section if you want to use a proxyq see: SOCKS proxies
|
182 |
+
# https://2.python-requests.org/en/latest/user/advanced/#proxies
|
183 |
+
# are also supported: see
|
184 |
+
# https://2.python-requests.org/en/latest/user/advanced/#socks
|
185 |
+
#
|
186 |
+
# proxies:
|
187 |
+
# all://:
|
188 |
+
# - http://proxy1:8080
|
189 |
+
# - http://proxy2:8080
|
190 |
+
#
|
191 |
+
# using_tor_proxy: true
|
192 |
+
#
|
193 |
+
# Extra seconds to add in order to account for the time taken by the proxy
|
194 |
+
#
|
195 |
+
# extra_proxy_timeout: 10
|
196 |
+
#
|
197 |
+
# uncomment below section only if you have more than one network interface
|
198 |
+
# which can be the source of outgoing search requests
|
199 |
+
#
|
200 |
+
# source_ips:
|
201 |
+
# - 1.1.1.1
|
202 |
+
# - 1.1.1.2
|
203 |
+
# - fe80::/126
|
204 |
+
|
205 |
+
# External plugin configuration, for more details see
|
206 |
+
# https://docs.searxng.org/dev/plugins.html
|
207 |
+
#
|
208 |
+
# plugins:
|
209 |
+
# - plugin1
|
210 |
+
# - plugin2
|
211 |
+
# - ...
|
212 |
+
|
213 |
+
# Comment or un-comment plugin to activate / deactivate by default.
|
214 |
+
#
|
215 |
+
# enabled_plugins:
|
216 |
+
# # these plugins are enabled if nothing is configured ..
|
217 |
+
# - 'Hash plugin'
|
218 |
+
# - 'Self Information'
|
219 |
+
# - 'Tracker URL remover'
|
220 |
+
# - 'Ahmia blacklist' # activation depends on outgoing.using_tor_proxy
|
221 |
+
# # these plugins are disabled if nothing is configured ..
|
222 |
+
# - 'Hostname replace' # see hostname_replace configuration below
|
223 |
+
# - 'Calculator plugin'
|
224 |
+
# - 'Open Access DOI rewrite'
|
225 |
+
# - 'Tor check plugin'
|
226 |
+
# # Read the docs before activate: auto-detection of the language could be
|
227 |
+
# # detrimental to users expectations / users can activate the plugin in the
|
228 |
+
# # preferences if they want.
|
229 |
+
# - 'Autodetect search language'
|
230 |
+
|
231 |
+
# Configuration of the "Hostname replace" plugin:
|
232 |
+
#
|
233 |
+
# hostname_replace:
|
234 |
+
# '(.*\.)?youtube\.com$': 'invidious.example.com'
|
235 |
+
# '(.*\.)?youtu\.be$': 'invidious.example.com'
|
236 |
+
# '(.*\.)?youtube-noocookie\.com$': 'yotter.example.com'
|
237 |
+
# '(.*\.)?reddit\.com$': 'teddit.example.com'
|
238 |
+
# '(.*\.)?redd\.it$': 'teddit.example.com'
|
239 |
+
# '(www\.)?twitter\.com$': 'nitter.example.com'
|
240 |
+
# # to remove matching host names from result list, set value to false
|
241 |
+
# 'spam\.example\.com': false
|
242 |
+
|
243 |
+
checker:
|
244 |
+
# disable checker when in debug mode
|
245 |
+
off_when_debug: true
|
246 |
+
|
247 |
+
# use "scheduling: false" to disable scheduling
|
248 |
+
# scheduling: interval or int
|
249 |
+
|
250 |
+
# to activate the scheduler:
|
251 |
+
# * uncomment "scheduling" section
|
252 |
+
# * add "cache2 = name=searxngcache,items=2000,blocks=2000,blocksize=4096,bitmap=1"
|
253 |
+
# to your uwsgi.ini
|
254 |
+
|
255 |
+
# scheduling:
|
256 |
+
# start_after: [300, 1800] # delay to start the first run of the checker
|
257 |
+
# every: [86400, 90000] # how often the checker runs
|
258 |
+
|
259 |
+
# additional tests: only for the YAML anchors (see the engines section)
|
260 |
+
#
|
261 |
+
additional_tests:
|
262 |
+
rosebud: &test_rosebud
|
263 |
+
matrix:
|
264 |
+
query: rosebud
|
265 |
+
lang: en
|
266 |
+
result_container:
|
267 |
+
- not_empty
|
268 |
+
- ['one_title_contains', 'citizen kane']
|
269 |
+
test:
|
270 |
+
- unique_results
|
271 |
+
|
272 |
+
android: &test_android
|
273 |
+
matrix:
|
274 |
+
query: ['android']
|
275 |
+
lang: ['en', 'de', 'fr', 'zh-CN']
|
276 |
+
result_container:
|
277 |
+
- not_empty
|
278 |
+
- ['one_title_contains', 'google']
|
279 |
+
test:
|
280 |
+
- unique_results
|
281 |
+
|
282 |
+
# tests: only for the YAML anchors (see the engines section)
|
283 |
+
tests:
|
284 |
+
infobox: &tests_infobox
|
285 |
+
infobox:
|
286 |
+
matrix:
|
287 |
+
query: ["linux", "new york", "bbc"]
|
288 |
+
result_container:
|
289 |
+
- has_infobox
|
290 |
+
|
291 |
+
categories_as_tabs:
|
292 |
+
general:
|
293 |
+
images:
|
294 |
+
videos:
|
295 |
+
news:
|
296 |
+
map:
|
297 |
+
music:
|
298 |
+
it:
|
299 |
+
science:
|
300 |
+
files:
|
301 |
+
social media:
|
302 |
+
|
303 |
+
engines:
|
304 |
+
- name: 9gag
|
305 |
+
engine: 9gag
|
306 |
+
shortcut: 9g
|
307 |
+
disabled: true
|
308 |
+
|
309 |
+
- name: annas archive
|
310 |
+
engine: annas_archive
|
311 |
+
disabled: true
|
312 |
+
shortcut: aa
|
313 |
+
|
314 |
+
# - name: annas articles
|
315 |
+
# engine: annas_archive
|
316 |
+
# shortcut: aaa
|
317 |
+
# # https://docs.searxng.org/dev/engines/online/annas_archive.html
|
318 |
+
# aa_content: 'magazine' # book_fiction, book_unknown, book_nonfiction, book_comic
|
319 |
+
# aa_ext: 'pdf' # pdf, epub, ..
|
320 |
+
# aa_sort: oldest' # newest, oldest, largest, smallest
|
321 |
+
|
322 |
+
- name: apk mirror
|
323 |
+
engine: apkmirror
|
324 |
+
timeout: 4.0
|
325 |
+
shortcut: apkm
|
326 |
+
disabled: true
|
327 |
+
|
328 |
+
- name: apple app store
|
329 |
+
engine: apple_app_store
|
330 |
+
shortcut: aps
|
331 |
+
disabled: true
|
332 |
+
|
333 |
+
# Requires Tor
|
334 |
+
- name: ahmia
|
335 |
+
engine: ahmia
|
336 |
+
categories: onions
|
337 |
+
enable_http: true
|
338 |
+
shortcut: ah
|
339 |
+
|
340 |
+
- name: anaconda
|
341 |
+
engine: xpath
|
342 |
+
paging: true
|
343 |
+
first_page_num: 0
|
344 |
+
search_url: https://anaconda.org/search?q={query}&page={pageno}
|
345 |
+
results_xpath: //tbody/tr
|
346 |
+
url_xpath: ./td/h5/a[last()]/@href
|
347 |
+
title_xpath: ./td/h5
|
348 |
+
content_xpath: ./td[h5]/text()
|
349 |
+
categories: it
|
350 |
+
timeout: 6.0
|
351 |
+
shortcut: conda
|
352 |
+
disabled: true
|
353 |
+
|
354 |
+
- name: arch linux wiki
|
355 |
+
engine: archlinux
|
356 |
+
shortcut: al
|
357 |
+
|
358 |
+
- name: artic
|
359 |
+
engine: artic
|
360 |
+
shortcut: arc
|
361 |
+
timeout: 4.0
|
362 |
+
|
363 |
+
- name: arxiv
|
364 |
+
engine: arxiv
|
365 |
+
shortcut: arx
|
366 |
+
timeout: 4.0
|
367 |
+
|
368 |
+
- name: ask
|
369 |
+
engine: ask
|
370 |
+
shortcut: ask
|
371 |
+
disabled: true
|
372 |
+
|
373 |
+
# tmp suspended: dh key too small
|
374 |
+
# - name: base
|
375 |
+
# engine: base
|
376 |
+
# shortcut: bs
|
377 |
+
|
378 |
+
- name: bandcamp
|
379 |
+
engine: bandcamp
|
380 |
+
shortcut: bc
|
381 |
+
categories: music
|
382 |
+
|
383 |
+
- name: wikipedia
|
384 |
+
engine: wikipedia
|
385 |
+
shortcut: wp
|
386 |
+
# add "list" to the array to get results in the results list
|
387 |
+
display_type: ["infobox"]
|
388 |
+
base_url: 'https://{language}.wikipedia.org/'
|
389 |
+
categories: [general]
|
390 |
+
|
391 |
+
- name: bilibili
|
392 |
+
engine: bilibili
|
393 |
+
shortcut: bil
|
394 |
+
disabled: true
|
395 |
+
|
396 |
+
- name: bing
|
397 |
+
engine: bing
|
398 |
+
shortcut: bi
|
399 |
+
disabled: true
|
400 |
+
|
401 |
+
- name: bing images
|
402 |
+
engine: bing_images
|
403 |
+
shortcut: bii
|
404 |
+
|
405 |
+
- name: bing news
|
406 |
+
engine: bing_news
|
407 |
+
shortcut: bin
|
408 |
+
|
409 |
+
- name: bing videos
|
410 |
+
engine: bing_videos
|
411 |
+
shortcut: biv
|
412 |
+
|
413 |
+
- name: bitbucket
|
414 |
+
engine: xpath
|
415 |
+
paging: true
|
416 |
+
search_url: https://bitbucket.org/repo/all/{pageno}?name={query}
|
417 |
+
url_xpath: //article[@class="repo-summary"]//a[@class="repo-link"]/@href
|
418 |
+
title_xpath: //article[@class="repo-summary"]//a[@class="repo-link"]
|
419 |
+
content_xpath: //article[@class="repo-summary"]/p
|
420 |
+
categories: [it, repos]
|
421 |
+
timeout: 4.0
|
422 |
+
disabled: true
|
423 |
+
shortcut: bb
|
424 |
+
about:
|
425 |
+
website: https://bitbucket.org/
|
426 |
+
wikidata_id: Q2493781
|
427 |
+
official_api_documentation: https://developer.atlassian.com/bitbucket
|
428 |
+
use_official_api: false
|
429 |
+
require_api_key: false
|
430 |
+
results: HTML
|
431 |
+
|
432 |
+
- name: bpb
|
433 |
+
engine: bpb
|
434 |
+
shortcut: bpb
|
435 |
+
disabled: true
|
436 |
+
|
437 |
+
- name: btdigg
|
438 |
+
engine: btdigg
|
439 |
+
shortcut: bt
|
440 |
+
disabled: true
|
441 |
+
|
442 |
+
- name: openverse
|
443 |
+
engine: openverse
|
444 |
+
categories: images
|
445 |
+
shortcut: opv
|
446 |
+
|
447 |
+
- name: media.ccc.de
|
448 |
+
engine: ccc_media
|
449 |
+
shortcut: c3tv
|
450 |
+
# We don't set language: de here because media.ccc.de is not just
|
451 |
+
# for a German audience. It contains many English videos and many
|
452 |
+
# German videos have English subtitles.
|
453 |
+
disabled: true
|
454 |
+
|
455 |
+
- name: chefkoch
|
456 |
+
engine: chefkoch
|
457 |
+
shortcut: chef
|
458 |
+
# to show premium or plus results too:
|
459 |
+
# skip_premium: false
|
460 |
+
|
461 |
+
# - name: core.ac.uk
|
462 |
+
# engine: core
|
463 |
+
# categories: science
|
464 |
+
# shortcut: cor
|
465 |
+
# # get your API key from: https://core.ac.uk/api-keys/register/
|
466 |
+
# api_key: 'unset'
|
467 |
+
|
468 |
+
- name: cppreference
|
469 |
+
engine: cppreference
|
470 |
+
shortcut: cpp
|
471 |
+
paging: false
|
472 |
+
disabled: true
|
473 |
+
|
474 |
+
- name: crossref
|
475 |
+
engine: crossref
|
476 |
+
shortcut: cr
|
477 |
+
timeout: 30
|
478 |
+
disabled: true
|
479 |
+
|
480 |
+
- name: crowdview
|
481 |
+
engine: json_engine
|
482 |
+
shortcut: cv
|
483 |
+
categories: general
|
484 |
+
paging: false
|
485 |
+
search_url: https://crowdview-next-js.onrender.com/api/search-v3?query={query}
|
486 |
+
results_query: results
|
487 |
+
url_query: link
|
488 |
+
title_query: title
|
489 |
+
content_query: snippet
|
490 |
+
disabled: true
|
491 |
+
about:
|
492 |
+
website: https://crowdview.ai/
|
493 |
+
|
494 |
+
- name: yep
|
495 |
+
engine: yep
|
496 |
+
shortcut: yep
|
497 |
+
categories: general
|
498 |
+
search_type: web
|
499 |
+
timeout: 5
|
500 |
+
disabled: true
|
501 |
+
|
502 |
+
- name: yep images
|
503 |
+
engine: yep
|
504 |
+
shortcut: yepi
|
505 |
+
categories: images
|
506 |
+
search_type: images
|
507 |
+
disabled: true
|
508 |
+
|
509 |
+
- name: yep news
|
510 |
+
engine: yep
|
511 |
+
shortcut: yepn
|
512 |
+
categories: news
|
513 |
+
search_type: news
|
514 |
+
disabled: true
|
515 |
+
|
516 |
+
- name: curlie
|
517 |
+
engine: xpath
|
518 |
+
shortcut: cl
|
519 |
+
categories: general
|
520 |
+
disabled: true
|
521 |
+
paging: true
|
522 |
+
lang_all: ''
|
523 |
+
search_url: https://curlie.org/search?q={query}&lang={lang}&start={pageno}&stime=92452189
|
524 |
+
page_size: 20
|
525 |
+
results_xpath: //div[@id="site-list-content"]/div[@class="site-item"]
|
526 |
+
url_xpath: ./div[@class="title-and-desc"]/a/@href
|
527 |
+
title_xpath: ./div[@class="title-and-desc"]/a/div
|
528 |
+
content_xpath: ./div[@class="title-and-desc"]/div[@class="site-descr"]
|
529 |
+
about:
|
530 |
+
website: https://curlie.org/
|
531 |
+
wikidata_id: Q60715723
|
532 |
+
use_official_api: false
|
533 |
+
require_api_key: false
|
534 |
+
results: HTML
|
535 |
+
|
536 |
+
- name: currency
|
537 |
+
engine: currency_convert
|
538 |
+
categories: general
|
539 |
+
shortcut: cc
|
540 |
+
|
541 |
+
- name: bahnhof
|
542 |
+
engine: json_engine
|
543 |
+
search_url: https://www.bahnhof.de/api/stations/search/{query}
|
544 |
+
url_prefix: https://www.bahnhof.de/
|
545 |
+
url_query: slug
|
546 |
+
title_query: name
|
547 |
+
content_query: state
|
548 |
+
shortcut: bf
|
549 |
+
disabled: true
|
550 |
+
about:
|
551 |
+
website: https://www.bahn.de
|
552 |
+
wikidata_id: Q22811603
|
553 |
+
use_official_api: false
|
554 |
+
require_api_key: false
|
555 |
+
results: JSON
|
556 |
+
language: de
|
557 |
+
tests:
|
558 |
+
bahnhof:
|
559 |
+
matrix:
|
560 |
+
query: berlin
|
561 |
+
lang: en
|
562 |
+
result_container:
|
563 |
+
- not_empty
|
564 |
+
- ['one_title_contains', 'Berlin Hauptbahnhof']
|
565 |
+
test:
|
566 |
+
- unique_results
|
567 |
+
|
568 |
+
- name: deezer
|
569 |
+
engine: deezer
|
570 |
+
shortcut: dz
|
571 |
+
disabled: true
|
572 |
+
|
573 |
+
- name: destatis
|
574 |
+
engine: destatis
|
575 |
+
shortcut: destat
|
576 |
+
disabled: true
|
577 |
+
|
578 |
+
- name: deviantart
|
579 |
+
engine: deviantart
|
580 |
+
shortcut: da
|
581 |
+
timeout: 3.0
|
582 |
+
|
583 |
+
- name: ddg definitions
|
584 |
+
engine: duckduckgo_definitions
|
585 |
+
shortcut: ddd
|
586 |
+
weight: 2
|
587 |
+
disabled: true
|
588 |
+
tests: *tests_infobox
|
589 |
+
|
590 |
+
# cloudflare protected
|
591 |
+
# - name: digbt
|
592 |
+
# engine: digbt
|
593 |
+
# shortcut: dbt
|
594 |
+
# timeout: 6.0
|
595 |
+
# disabled: true
|
596 |
+
|
597 |
+
- name: docker hub
|
598 |
+
engine: docker_hub
|
599 |
+
shortcut: dh
|
600 |
+
categories: [it, packages]
|
601 |
+
|
602 |
+
- name: erowid
|
603 |
+
engine: xpath
|
604 |
+
paging: true
|
605 |
+
first_page_num: 0
|
606 |
+
page_size: 30
|
607 |
+
search_url: https://www.erowid.org/search.php?q={query}&s={pageno}
|
608 |
+
url_xpath: //dl[@class="results-list"]/dt[@class="result-title"]/a/@href
|
609 |
+
title_xpath: //dl[@class="results-list"]/dt[@class="result-title"]/a/text()
|
610 |
+
content_xpath: //dl[@class="results-list"]/dd[@class="result-details"]
|
611 |
+
categories: []
|
612 |
+
shortcut: ew
|
613 |
+
disabled: true
|
614 |
+
about:
|
615 |
+
website: https://www.erowid.org/
|
616 |
+
wikidata_id: Q1430691
|
617 |
+
official_api_documentation:
|
618 |
+
use_official_api: false
|
619 |
+
require_api_key: false
|
620 |
+
results: HTML
|
621 |
+
|
622 |
+
# - name: elasticsearch
|
623 |
+
# shortcut: es
|
624 |
+
# engine: elasticsearch
|
625 |
+
# base_url: http://localhost:9200
|
626 |
+
# username: elastic
|
627 |
+
# password: changeme
|
628 |
+
# index: my-index
|
629 |
+
# # available options: match, simple_query_string, term, terms, custom
|
630 |
+
# query_type: match
|
631 |
+
# # if query_type is set to custom, provide your query here
|
632 |
+
# #custom_query_json: {"query":{"match_all": {}}}
|
633 |
+
# #show_metadata: false
|
634 |
+
# disabled: true
|
635 |
+
|
636 |
+
- name: wikidata
|
637 |
+
engine: wikidata
|
638 |
+
shortcut: wd
|
639 |
+
timeout: 3.0
|
640 |
+
weight: 2
|
641 |
+
# add "list" to the array to get results in the results list
|
642 |
+
display_type: ["infobox"]
|
643 |
+
tests: *tests_infobox
|
644 |
+
categories: [general]
|
645 |
+
|
646 |
+
- name: duckduckgo
|
647 |
+
engine: duckduckgo
|
648 |
+
shortcut: ddg
|
649 |
+
|
650 |
+
- name: duckduckgo images
|
651 |
+
engine: duckduckgo_extra
|
652 |
+
categories: [images, web]
|
653 |
+
ddg_category: images
|
654 |
+
shortcut: ddi
|
655 |
+
disabled: true
|
656 |
+
|
657 |
+
- name: duckduckgo videos
|
658 |
+
engine: duckduckgo_extra
|
659 |
+
categories: [videos, web]
|
660 |
+
ddg_category: videos
|
661 |
+
shortcut: ddv
|
662 |
+
disabled: true
|
663 |
+
|
664 |
+
- name: duckduckgo news
|
665 |
+
engine: duckduckgo_extra
|
666 |
+
categories: [news, web]
|
667 |
+
ddg_category: news
|
668 |
+
shortcut: ddn
|
669 |
+
disabled: true
|
670 |
+
|
671 |
+
- name: duckduckgo weather
|
672 |
+
engine: duckduckgo_weather
|
673 |
+
shortcut: ddw
|
674 |
+
disabled: true
|
675 |
+
|
676 |
+
- name: apple maps
|
677 |
+
engine: apple_maps
|
678 |
+
shortcut: apm
|
679 |
+
disabled: true
|
680 |
+
timeout: 5.0
|
681 |
+
|
682 |
+
- name: emojipedia
|
683 |
+
engine: emojipedia
|
684 |
+
timeout: 4.0
|
685 |
+
shortcut: em
|
686 |
+
disabled: true
|
687 |
+
|
688 |
+
- name: tineye
|
689 |
+
engine: tineye
|
690 |
+
shortcut: tin
|
691 |
+
timeout: 9.0
|
692 |
+
disabled: true
|
693 |
+
|
694 |
+
- name: etymonline
|
695 |
+
engine: xpath
|
696 |
+
paging: true
|
697 |
+
search_url: https://etymonline.com/search?page={pageno}&q={query}
|
698 |
+
url_xpath: //a[contains(@class, "word__name--")]/@href
|
699 |
+
title_xpath: //a[contains(@class, "word__name--")]
|
700 |
+
content_xpath: //section[contains(@class, "word__defination")]
|
701 |
+
first_page_num: 1
|
702 |
+
shortcut: et
|
703 |
+
categories: [dictionaries]
|
704 |
+
about:
|
705 |
+
website: https://www.etymonline.com/
|
706 |
+
wikidata_id: Q1188617
|
707 |
+
official_api_documentation:
|
708 |
+
use_official_api: false
|
709 |
+
require_api_key: false
|
710 |
+
results: HTML
|
711 |
+
|
712 |
+
# - name: ebay
|
713 |
+
# engine: ebay
|
714 |
+
# shortcut: eb
|
715 |
+
# base_url: 'https://www.ebay.com'
|
716 |
+
# disabled: true
|
717 |
+
# timeout: 5
|
718 |
+
|
719 |
+
- name: 1x
|
720 |
+
engine: www1x
|
721 |
+
shortcut: 1x
|
722 |
+
timeout: 3.0
|
723 |
+
disabled: true
|
724 |
+
|
725 |
+
- name: fdroid
|
726 |
+
engine: fdroid
|
727 |
+
shortcut: fd
|
728 |
+
disabled: true
|
729 |
+
|
730 |
+
- name: flickr
|
731 |
+
categories: images
|
732 |
+
shortcut: fl
|
733 |
+
# You can use the engine using the official stable API, but you need an API
|
734 |
+
# key, see: https://www.flickr.com/services/apps/create/
|
735 |
+
# engine: flickr
|
736 |
+
# api_key: 'apikey' # required!
|
737 |
+
# Or you can use the html non-stable engine, activated by default
|
738 |
+
engine: flickr_noapi
|
739 |
+
|
740 |
+
- name: free software directory
|
741 |
+
engine: mediawiki
|
742 |
+
shortcut: fsd
|
743 |
+
categories: [it, software wikis]
|
744 |
+
base_url: https://directory.fsf.org/
|
745 |
+
search_type: title
|
746 |
+
timeout: 5.0
|
747 |
+
disabled: true
|
748 |
+
about:
|
749 |
+
website: https://directory.fsf.org/
|
750 |
+
wikidata_id: Q2470288
|
751 |
+
|
752 |
+
# - name: freesound
|
753 |
+
# engine: freesound
|
754 |
+
# shortcut: fnd
|
755 |
+
# disabled: true
|
756 |
+
# timeout: 15.0
|
757 |
+
# API key required, see: https://freesound.org/docs/api/overview.html
|
758 |
+
# api_key: MyAPIkey
|
759 |
+
|
760 |
+
- name: frinkiac
|
761 |
+
engine: frinkiac
|
762 |
+
shortcut: frk
|
763 |
+
disabled: true
|
764 |
+
|
765 |
+
- name: fyyd
|
766 |
+
engine: fyyd
|
767 |
+
shortcut: fy
|
768 |
+
timeout: 8.0
|
769 |
+
disabled: true
|
770 |
+
|
771 |
+
- name: genius
|
772 |
+
engine: genius
|
773 |
+
shortcut: gen
|
774 |
+
|
775 |
+
- name: gentoo
|
776 |
+
engine: gentoo
|
777 |
+
shortcut: ge
|
778 |
+
timeout: 10.0
|
779 |
+
|
780 |
+
- name: gitlab
|
781 |
+
engine: json_engine
|
782 |
+
paging: true
|
783 |
+
search_url: https://gitlab.com/api/v4/projects?search={query}&page={pageno}
|
784 |
+
url_query: web_url
|
785 |
+
title_query: name_with_namespace
|
786 |
+
content_query: description
|
787 |
+
page_size: 20
|
788 |
+
categories: [it, repos]
|
789 |
+
shortcut: gl
|
790 |
+
timeout: 10.0
|
791 |
+
disabled: true
|
792 |
+
about:
|
793 |
+
website: https://about.gitlab.com/
|
794 |
+
wikidata_id: Q16639197
|
795 |
+
official_api_documentation: https://docs.gitlab.com/ee/api/
|
796 |
+
use_official_api: false
|
797 |
+
require_api_key: false
|
798 |
+
results: JSON
|
799 |
+
|
800 |
+
- name: github
|
801 |
+
engine: github
|
802 |
+
shortcut: gh
|
803 |
+
|
804 |
+
- name: codeberg
|
805 |
+
# https://docs.searxng.org/dev/engines/online/gitea.html
|
806 |
+
engine: gitea
|
807 |
+
base_url: https://codeberg.org
|
808 |
+
shortcut: cb
|
809 |
+
disabled: true
|
810 |
+
|
811 |
+
- name: gitea.com
|
812 |
+
engine: gitea
|
813 |
+
base_url: https://gitea.com
|
814 |
+
shortcut: gitea
|
815 |
+
disabled: true
|
816 |
+
|
817 |
+
- name: goodreads
|
818 |
+
engine: goodreads
|
819 |
+
shortcut: good
|
820 |
+
timeout: 4.0
|
821 |
+
disabled: true
|
822 |
+
|
823 |
+
- name: google
|
824 |
+
engine: google
|
825 |
+
shortcut: go
|
826 |
+
# additional_tests:
|
827 |
+
# android: *test_android
|
828 |
+
|
829 |
+
- name: google images
|
830 |
+
engine: google_images
|
831 |
+
shortcut: goi
|
832 |
+
# additional_tests:
|
833 |
+
# android: *test_android
|
834 |
+
# dali:
|
835 |
+
# matrix:
|
836 |
+
# query: ['Dali Christ']
|
837 |
+
# lang: ['en', 'de', 'fr', 'zh-CN']
|
838 |
+
# result_container:
|
839 |
+
# - ['one_title_contains', 'Salvador']
|
840 |
+
|
841 |
+
- name: google news
|
842 |
+
engine: google_news
|
843 |
+
shortcut: gon
|
844 |
+
# additional_tests:
|
845 |
+
# android: *test_android
|
846 |
+
|
847 |
+
- name: google videos
|
848 |
+
engine: google_videos
|
849 |
+
shortcut: gov
|
850 |
+
# additional_tests:
|
851 |
+
# android: *test_android
|
852 |
+
|
853 |
+
- name: google scholar
|
854 |
+
engine: google_scholar
|
855 |
+
shortcut: gos
|
856 |
+
|
857 |
+
- name: google play apps
|
858 |
+
engine: google_play
|
859 |
+
categories: [files, apps]
|
860 |
+
shortcut: gpa
|
861 |
+
play_categ: apps
|
862 |
+
disabled: true
|
863 |
+
|
864 |
+
- name: google play movies
|
865 |
+
engine: google_play
|
866 |
+
categories: videos
|
867 |
+
shortcut: gpm
|
868 |
+
play_categ: movies
|
869 |
+
disabled: true
|
870 |
+
|
871 |
+
- name: material icons
|
872 |
+
engine: material_icons
|
873 |
+
categories: images
|
874 |
+
shortcut: mi
|
875 |
+
disabled: true
|
876 |
+
|
877 |
+
- name: gpodder
|
878 |
+
engine: json_engine
|
879 |
+
shortcut: gpod
|
880 |
+
timeout: 4.0
|
881 |
+
paging: false
|
882 |
+
search_url: https://gpodder.net/search.json?q={query}
|
883 |
+
url_query: url
|
884 |
+
title_query: title
|
885 |
+
content_query: description
|
886 |
+
page_size: 19
|
887 |
+
categories: music
|
888 |
+
disabled: true
|
889 |
+
about:
|
890 |
+
website: https://gpodder.net
|
891 |
+
wikidata_id: Q3093354
|
892 |
+
official_api_documentation: https://gpoddernet.readthedocs.io/en/latest/api/
|
893 |
+
use_official_api: false
|
894 |
+
requires_api_key: false
|
895 |
+
results: JSON
|
896 |
+
|
897 |
+
- name: habrahabr
|
898 |
+
engine: xpath
|
899 |
+
paging: true
|
900 |
+
search_url: https://habr.com/en/search/page{pageno}/?q={query}
|
901 |
+
results_xpath: //article[contains(@class, "tm-articles-list__item")]
|
902 |
+
url_xpath: .//a[@class="tm-title__link"]/@href
|
903 |
+
title_xpath: .//a[@class="tm-title__link"]
|
904 |
+
content_xpath: .//div[contains(@class, "article-formatted-body")]
|
905 |
+
categories: it
|
906 |
+
timeout: 4.0
|
907 |
+
disabled: true
|
908 |
+
shortcut: habr
|
909 |
+
about:
|
910 |
+
website: https://habr.com/
|
911 |
+
wikidata_id: Q4494434
|
912 |
+
official_api_documentation: https://habr.com/en/docs/help/api/
|
913 |
+
use_official_api: false
|
914 |
+
require_api_key: false
|
915 |
+
results: HTML
|
916 |
+
|
917 |
+
- name: hackernews
|
918 |
+
engine: hackernews
|
919 |
+
shortcut: hn
|
920 |
+
disabled: true
|
921 |
+
|
922 |
+
- name: hex
|
923 |
+
engine: hex
|
924 |
+
shortcut: hex
|
925 |
+
disabled: true
|
926 |
+
|
927 |
+
- name: crates.io
|
928 |
+
engine: crates
|
929 |
+
shortcut: crates
|
930 |
+
disabled: true
|
931 |
+
timeout: 6.0
|
932 |
+
|
933 |
+
- name: hoogle
|
934 |
+
engine: xpath
|
935 |
+
search_url: https://hoogle.haskell.org/?hoogle={query}
|
936 |
+
results_xpath: '//div[@class="result"]'
|
937 |
+
title_xpath: './/div[@class="ans"]//a'
|
938 |
+
url_xpath: './/div[@class="ans"]//a/@href'
|
939 |
+
content_xpath: './/div[@class="from"]'
|
940 |
+
page_size: 20
|
941 |
+
categories: [it, packages]
|
942 |
+
shortcut: ho
|
943 |
+
about:
|
944 |
+
website: https://hoogle.haskell.org/
|
945 |
+
wikidata_id: Q34010
|
946 |
+
official_api_documentation: https://hackage.haskell.org/api
|
947 |
+
use_official_api: false
|
948 |
+
require_api_key: false
|
949 |
+
results: JSON
|
950 |
+
|
951 |
+
- name: imdb
|
952 |
+
engine: imdb
|
953 |
+
shortcut: imdb
|
954 |
+
timeout: 6.0
|
955 |
+
disabled: true
|
956 |
+
|
957 |
+
- name: imgur
|
958 |
+
engine: imgur
|
959 |
+
shortcut: img
|
960 |
+
disabled: true
|
961 |
+
|
962 |
+
- name: ina
|
963 |
+
engine: ina
|
964 |
+
shortcut: in
|
965 |
+
timeout: 6.0
|
966 |
+
disabled: true
|
967 |
+
|
968 |
+
- name: invidious
|
969 |
+
engine: invidious
|
970 |
+
# Instanes will be selected randomly, see https://api.invidious.io/ for
|
971 |
+
# instances that are stable (good uptime) and close to you.
|
972 |
+
base_url:
|
973 |
+
- https://invidious.io.lol
|
974 |
+
- https://invidious.fdn.fr
|
975 |
+
- https://yt.artemislena.eu
|
976 |
+
- https://invidious.tiekoetter.com
|
977 |
+
- https://invidious.flokinet.to
|
978 |
+
- https://vid.puffyan.us
|
979 |
+
- https://invidious.privacydev.net
|
980 |
+
- https://inv.tux.pizza
|
981 |
+
shortcut: iv
|
982 |
+
timeout: 3.0
|
983 |
+
disabled: true
|
984 |
+
|
985 |
+
- name: jisho
|
986 |
+
engine: jisho
|
987 |
+
shortcut: js
|
988 |
+
timeout: 3.0
|
989 |
+
disabled: true
|
990 |
+
|
991 |
+
- name: kickass
|
992 |
+
engine: kickass
|
993 |
+
base_url:
|
994 |
+
- https://kickasstorrents.to
|
995 |
+
- https://kickasstorrents.cr
|
996 |
+
- https://kickasstorrent.cr
|
997 |
+
- https://kickass.sx
|
998 |
+
- https://kat.am
|
999 |
+
shortcut: kc
|
1000 |
+
timeout: 4.0
|
1001 |
+
|
1002 |
+
- name: lemmy communities
|
1003 |
+
engine: lemmy
|
1004 |
+
lemmy_type: Communities
|
1005 |
+
shortcut: leco
|
1006 |
+
|
1007 |
+
- name: lemmy users
|
1008 |
+
engine: lemmy
|
1009 |
+
network: lemmy communities
|
1010 |
+
lemmy_type: Users
|
1011 |
+
shortcut: leus
|
1012 |
+
|
1013 |
+
- name: lemmy posts
|
1014 |
+
engine: lemmy
|
1015 |
+
network: lemmy communities
|
1016 |
+
lemmy_type: Posts
|
1017 |
+
shortcut: lepo
|
1018 |
+
|
1019 |
+
- name: lemmy comments
|
1020 |
+
engine: lemmy
|
1021 |
+
network: lemmy communities
|
1022 |
+
lemmy_type: Comments
|
1023 |
+
shortcut: lecom
|
1024 |
+
|
1025 |
+
- name: library genesis
|
1026 |
+
engine: xpath
|
1027 |
+
# search_url: https://libgen.is/search.php?req={query}
|
1028 |
+
search_url: https://libgen.rs/search.php?req={query}
|
1029 |
+
url_xpath: //a[contains(@href,"book/index.php?md5")]/@href
|
1030 |
+
title_xpath: //a[contains(@href,"book/")]/text()[1]
|
1031 |
+
content_xpath: //td/a[1][contains(@href,"=author")]/text()
|
1032 |
+
categories: files
|
1033 |
+
timeout: 7.0
|
1034 |
+
disabled: true
|
1035 |
+
shortcut: lg
|
1036 |
+
about:
|
1037 |
+
website: https://libgen.fun/
|
1038 |
+
wikidata_id: Q22017206
|
1039 |
+
official_api_documentation:
|
1040 |
+
use_official_api: false
|
1041 |
+
require_api_key: false
|
1042 |
+
results: HTML
|
1043 |
+
|
1044 |
+
- name: z-library
|
1045 |
+
engine: zlibrary
|
1046 |
+
shortcut: zlib
|
1047 |
+
categories: files
|
1048 |
+
timeout: 7.0
|
1049 |
+
|
1050 |
+
- name: library of congress
|
1051 |
+
engine: loc
|
1052 |
+
shortcut: loc
|
1053 |
+
categories: images
|
1054 |
+
|
1055 |
+
- name: libretranslate
|
1056 |
+
engine: libretranslate
|
1057 |
+
# https://github.com/LibreTranslate/LibreTranslate?tab=readme-ov-file#mirrors
|
1058 |
+
base_url:
|
1059 |
+
- https://translate.terraprint.co
|
1060 |
+
- https://trans.zillyhuhn.com
|
1061 |
+
# api_key: abc123
|
1062 |
+
shortcut: lt
|
1063 |
+
disabled: true
|
1064 |
+
|
1065 |
+
- name: lingva
|
1066 |
+
engine: lingva
|
1067 |
+
shortcut: lv
|
1068 |
+
# set lingva instance in url, by default it will use the official instance
|
1069 |
+
# url: https://lingva.thedaviddelta.com
|
1070 |
+
|
1071 |
+
- name: lobste.rs
|
1072 |
+
engine: xpath
|
1073 |
+
search_url: https://lobste.rs/search?q={query}&what=stories&order=relevance
|
1074 |
+
results_xpath: //li[contains(@class, "story")]
|
1075 |
+
url_xpath: .//a[@class="u-url"]/@href
|
1076 |
+
title_xpath: .//a[@class="u-url"]
|
1077 |
+
content_xpath: .//a[@class="domain"]
|
1078 |
+
categories: it
|
1079 |
+
shortcut: lo
|
1080 |
+
timeout: 5.0
|
1081 |
+
disabled: true
|
1082 |
+
about:
|
1083 |
+
website: https://lobste.rs/
|
1084 |
+
wikidata_id: Q60762874
|
1085 |
+
official_api_documentation:
|
1086 |
+
use_official_api: false
|
1087 |
+
require_api_key: false
|
1088 |
+
results: HTML
|
1089 |
+
|
1090 |
+
- name: mastodon users
|
1091 |
+
engine: mastodon
|
1092 |
+
mastodon_type: accounts
|
1093 |
+
base_url: https://mastodon.social
|
1094 |
+
shortcut: mau
|
1095 |
+
|
1096 |
+
- name: mastodon hashtags
|
1097 |
+
engine: mastodon
|
1098 |
+
mastodon_type: hashtags
|
1099 |
+
base_url: https://mastodon.social
|
1100 |
+
shortcut: mah
|
1101 |
+
|
1102 |
+
# - name: matrixrooms
|
1103 |
+
# engine: mrs
|
1104 |
+
# # https://docs.searxng.org/dev/engines/online/mrs.html
|
1105 |
+
# # base_url: https://mrs-api-host
|
1106 |
+
# shortcut: mtrx
|
1107 |
+
# disabled: true
|
1108 |
+
|
1109 |
+
- name: mdn
|
1110 |
+
shortcut: mdn
|
1111 |
+
engine: json_engine
|
1112 |
+
categories: [it]
|
1113 |
+
paging: true
|
1114 |
+
search_url: https://developer.mozilla.org/api/v1/search?q={query}&page={pageno}
|
1115 |
+
results_query: documents
|
1116 |
+
url_query: mdn_url
|
1117 |
+
url_prefix: https://developer.mozilla.org
|
1118 |
+
title_query: title
|
1119 |
+
content_query: summary
|
1120 |
+
about:
|
1121 |
+
website: https://developer.mozilla.org
|
1122 |
+
wikidata_id: Q3273508
|
1123 |
+
official_api_documentation: null
|
1124 |
+
use_official_api: false
|
1125 |
+
require_api_key: false
|
1126 |
+
results: JSON
|
1127 |
+
|
1128 |
+
- name: metacpan
|
1129 |
+
engine: metacpan
|
1130 |
+
shortcut: cpan
|
1131 |
+
disabled: true
|
1132 |
+
number_of_results: 20
|
1133 |
+
|
1134 |
+
# - name: meilisearch
|
1135 |
+
# engine: meilisearch
|
1136 |
+
# shortcut: mes
|
1137 |
+
# enable_http: true
|
1138 |
+
# base_url: http://localhost:7700
|
1139 |
+
# index: my-index
|
1140 |
+
|
1141 |
+
- name: mixcloud
|
1142 |
+
engine: mixcloud
|
1143 |
+
shortcut: mc
|
1144 |
+
|
1145 |
+
# MongoDB engine
|
1146 |
+
# Required dependency: pymongo
|
1147 |
+
# - name: mymongo
|
1148 |
+
# engine: mongodb
|
1149 |
+
# shortcut: md
|
1150 |
+
# exact_match_only: false
|
1151 |
+
# host: '127.0.0.1'
|
1152 |
+
# port: 27017
|
1153 |
+
# enable_http: true
|
1154 |
+
# results_per_page: 20
|
1155 |
+
# database: 'business'
|
1156 |
+
# collection: 'reviews' # name of the db collection
|
1157 |
+
# key: 'name' # key in the collection to search for
|
1158 |
+
|
1159 |
+
- name: mozhi
|
1160 |
+
engine: mozhi
|
1161 |
+
base_url:
|
1162 |
+
- https://mozhi.aryak.me
|
1163 |
+
- https://translate.bus-hit.me
|
1164 |
+
- https://nyc1.mz.ggtyler.dev
|
1165 |
+
# mozhi_engine: google - see https://mozhi.aryak.me for supported engines
|
1166 |
+
timeout: 4.0
|
1167 |
+
shortcut: mz
|
1168 |
+
disabled: true
|
1169 |
+
|
1170 |
+
- name: mwmbl
|
1171 |
+
engine: mwmbl
|
1172 |
+
# api_url: https://api.mwmbl.org
|
1173 |
+
shortcut: mwm
|
1174 |
+
disabled: true
|
1175 |
+
|
1176 |
+
- name: npm
|
1177 |
+
engine: npm
|
1178 |
+
shortcut: npm
|
1179 |
+
timeout: 5.0
|
1180 |
+
disabled: true
|
1181 |
+
|
1182 |
+
- name: nyaa
|
1183 |
+
engine: nyaa
|
1184 |
+
shortcut: nt
|
1185 |
+
disabled: true
|
1186 |
+
|
1187 |
+
- name: mankier
|
1188 |
+
engine: json_engine
|
1189 |
+
search_url: https://www.mankier.com/api/v2/mans/?q={query}
|
1190 |
+
results_query: results
|
1191 |
+
url_query: url
|
1192 |
+
title_query: name
|
1193 |
+
content_query: description
|
1194 |
+
categories: it
|
1195 |
+
shortcut: man
|
1196 |
+
about:
|
1197 |
+
website: https://www.mankier.com/
|
1198 |
+
official_api_documentation: https://www.mankier.com/api
|
1199 |
+
use_official_api: true
|
1200 |
+
require_api_key: false
|
1201 |
+
results: JSON
|
1202 |
+
|
1203 |
+
# read https://docs.searxng.org/dev/engines/online/mullvad_leta.html
|
1204 |
+
# - name: mullvadleta
|
1205 |
+
# engine: mullvad_leta
|
1206 |
+
# use_cache: true # Only 100 non-cache searches per day, suggested only for private instances
|
1207 |
+
# search_url: https://leta.mullvad.net
|
1208 |
+
# categories: [general, web]
|
1209 |
+
# shortcut: ml
|
1210 |
+
|
1211 |
+
- name: odysee
|
1212 |
+
engine: odysee
|
1213 |
+
shortcut: od
|
1214 |
+
disabled: true
|
1215 |
+
|
1216 |
+
- name: openairedatasets
|
1217 |
+
engine: json_engine
|
1218 |
+
paging: true
|
1219 |
+
search_url: https://api.openaire.eu/search/datasets?format=json&page={pageno}&size=10&title={query}
|
1220 |
+
results_query: response/results/result
|
1221 |
+
url_query: metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
|
1222 |
+
title_query: metadata/oaf:entity/oaf:result/title/$
|
1223 |
+
content_query: metadata/oaf:entity/oaf:result/description/$
|
1224 |
+
content_html_to_text: true
|
1225 |
+
categories: "science"
|
1226 |
+
shortcut: oad
|
1227 |
+
timeout: 5.0
|
1228 |
+
about:
|
1229 |
+
website: https://www.openaire.eu/
|
1230 |
+
wikidata_id: Q25106053
|
1231 |
+
official_api_documentation: https://api.openaire.eu/
|
1232 |
+
use_official_api: false
|
1233 |
+
require_api_key: false
|
1234 |
+
results: JSON
|
1235 |
+
|
1236 |
+
- name: openairepublications
|
1237 |
+
engine: json_engine
|
1238 |
+
paging: true
|
1239 |
+
search_url: https://api.openaire.eu/search/publications?format=json&page={pageno}&size=10&title={query}
|
1240 |
+
results_query: response/results/result
|
1241 |
+
url_query: metadata/oaf:entity/oaf:result/children/instance/webresource/url/$
|
1242 |
+
title_query: metadata/oaf:entity/oaf:result/title/$
|
1243 |
+
content_query: metadata/oaf:entity/oaf:result/description/$
|
1244 |
+
content_html_to_text: true
|
1245 |
+
categories: science
|
1246 |
+
shortcut: oap
|
1247 |
+
timeout: 5.0
|
1248 |
+
about:
|
1249 |
+
website: https://www.openaire.eu/
|
1250 |
+
wikidata_id: Q25106053
|
1251 |
+
official_api_documentation: https://api.openaire.eu/
|
1252 |
+
use_official_api: false
|
1253 |
+
require_api_key: false
|
1254 |
+
results: JSON
|
1255 |
+
|
1256 |
+
- name: openmeteo
|
1257 |
+
engine: open_meteo
|
1258 |
+
shortcut: om
|
1259 |
+
disabled: true
|
1260 |
+
|
1261 |
+
# - name: opensemanticsearch
|
1262 |
+
# engine: opensemantic
|
1263 |
+
# shortcut: oss
|
1264 |
+
# base_url: 'http://localhost:8983/solr/opensemanticsearch/'
|
1265 |
+
|
1266 |
+
- name: openstreetmap
|
1267 |
+
engine: openstreetmap
|
1268 |
+
shortcut: osm
|
1269 |
+
|
1270 |
+
- name: openrepos
|
1271 |
+
engine: xpath
|
1272 |
+
paging: true
|
1273 |
+
search_url: https://openrepos.net/search/node/{query}?page={pageno}
|
1274 |
+
url_xpath: //li[@class="search-result"]//h3[@class="title"]/a/@href
|
1275 |
+
title_xpath: //li[@class="search-result"]//h3[@class="title"]/a
|
1276 |
+
content_xpath: //li[@class="search-result"]//div[@class="search-snippet-info"]//p[@class="search-snippet"]
|
1277 |
+
categories: files
|
1278 |
+
timeout: 4.0
|
1279 |
+
disabled: true
|
1280 |
+
shortcut: or
|
1281 |
+
about:
|
1282 |
+
website: https://openrepos.net/
|
1283 |
+
wikidata_id:
|
1284 |
+
official_api_documentation:
|
1285 |
+
use_official_api: false
|
1286 |
+
require_api_key: false
|
1287 |
+
results: HTML
|
1288 |
+
|
1289 |
+
- name: packagist
|
1290 |
+
engine: json_engine
|
1291 |
+
paging: true
|
1292 |
+
search_url: https://packagist.org/search.json?q={query}&page={pageno}
|
1293 |
+
results_query: results
|
1294 |
+
url_query: url
|
1295 |
+
title_query: name
|
1296 |
+
content_query: description
|
1297 |
+
categories: [it, packages]
|
1298 |
+
disabled: true
|
1299 |
+
timeout: 5.0
|
1300 |
+
shortcut: pack
|
1301 |
+
about:
|
1302 |
+
website: https://packagist.org
|
1303 |
+
wikidata_id: Q108311377
|
1304 |
+
official_api_documentation: https://packagist.org/apidoc
|
1305 |
+
use_official_api: true
|
1306 |
+
require_api_key: false
|
1307 |
+
results: JSON
|
1308 |
+
|
1309 |
+
- name: pdbe
|
1310 |
+
engine: pdbe
|
1311 |
+
shortcut: pdb
|
1312 |
+
# Hide obsolete PDB entries. Default is not to hide obsolete structures
|
1313 |
+
# hide_obsolete: false
|
1314 |
+
|
1315 |
+
- name: photon
|
1316 |
+
engine: photon
|
1317 |
+
shortcut: ph
|
1318 |
+
|
1319 |
+
- name: pinterest
|
1320 |
+
engine: pinterest
|
1321 |
+
shortcut: pin
|
1322 |
+
|
1323 |
+
- name: piped
|
1324 |
+
engine: piped
|
1325 |
+
shortcut: ppd
|
1326 |
+
categories: videos
|
1327 |
+
piped_filter: videos
|
1328 |
+
timeout: 3.0
|
1329 |
+
|
1330 |
+
# URL to use as link and for embeds
|
1331 |
+
frontend_url: https://srv.piped.video
|
1332 |
+
# Instance will be selected randomly, for more see https://piped-instances.kavin.rocks/
|
1333 |
+
backend_url:
|
1334 |
+
- https://pipedapi.kavin.rocks
|
1335 |
+
- https://pipedapi-libre.kavin.rocks
|
1336 |
+
- https://pipedapi.adminforge.de
|
1337 |
+
|
1338 |
+
- name: piped.music
|
1339 |
+
engine: piped
|
1340 |
+
network: piped
|
1341 |
+
shortcut: ppdm
|
1342 |
+
categories: music
|
1343 |
+
piped_filter: music_songs
|
1344 |
+
timeout: 3.0
|
1345 |
+
|
1346 |
+
- name: piratebay
|
1347 |
+
engine: piratebay
|
1348 |
+
shortcut: tpb
|
1349 |
+
# You may need to change this URL to a proxy if piratebay is blocked in your
|
1350 |
+
# country
|
1351 |
+
url: https://thepiratebay.org/
|
1352 |
+
timeout: 3.0
|
1353 |
+
|
1354 |
+
- name: pixiv
|
1355 |
+
shortcut: pv
|
1356 |
+
engine: pixiv
|
1357 |
+
disabled: true
|
1358 |
+
inactive: true
|
1359 |
+
pixiv_image_proxies:
|
1360 |
+
- https://pximg.example.org
|
1361 |
+
# A proxy is required to load the images. Hosting an image proxy server
|
1362 |
+
# for Pixiv:
|
1363 |
+
# --> https://pixivfe.pages.dev/hosting-image-proxy-server/
|
1364 |
+
# Proxies from public instances. Ask the public instances owners if they
|
1365 |
+
# agree to receive traffic from SearXNG!
|
1366 |
+
# --> https://codeberg.org/VnPower/PixivFE#instances
|
1367 |
+
# --> https://github.com/searxng/searxng/pull/3192#issuecomment-1941095047
|
1368 |
+
# image proxy of https://pixiv.cat
|
1369 |
+
# - https://i.pixiv.cat
|
1370 |
+
# image proxy of https://www.pixiv.pics
|
1371 |
+
# - https://pximg.cocomi.eu.org
|
1372 |
+
# image proxy of https://pixivfe.exozy.me
|
1373 |
+
# - https://pximg.exozy.me
|
1374 |
+
# image proxy of https://pixivfe.ducks.party
|
1375 |
+
# - https://pixiv.ducks.party
|
1376 |
+
# image proxy of https://pixiv.perennialte.ch
|
1377 |
+
# - https://pximg.perennialte.ch
|
1378 |
+
|
1379 |
+
- name: podcastindex
|
1380 |
+
engine: podcastindex
|
1381 |
+
shortcut: podcast
|
1382 |
+
|
1383 |
+
# Required dependency: psychopg2
|
1384 |
+
# - name: postgresql
|
1385 |
+
# engine: postgresql
|
1386 |
+
# database: postgres
|
1387 |
+
# username: postgres
|
1388 |
+
# password: postgres
|
1389 |
+
# limit: 10
|
1390 |
+
# query_str: 'SELECT * from my_table WHERE my_column = %(query)s'
|
1391 |
+
# shortcut : psql
|
1392 |
+
|
1393 |
+
- name: presearch
|
1394 |
+
engine: presearch
|
1395 |
+
search_type: search
|
1396 |
+
categories: [general, web]
|
1397 |
+
shortcut: ps
|
1398 |
+
timeout: 4.0
|
1399 |
+
disabled: true
|
1400 |
+
|
1401 |
+
- name: presearch images
|
1402 |
+
engine: presearch
|
1403 |
+
network: presearch
|
1404 |
+
search_type: images
|
1405 |
+
categories: [images, web]
|
1406 |
+
timeout: 4.0
|
1407 |
+
shortcut: psimg
|
1408 |
+
disabled: true
|
1409 |
+
|
1410 |
+
- name: presearch videos
|
1411 |
+
engine: presearch
|
1412 |
+
network: presearch
|
1413 |
+
search_type: videos
|
1414 |
+
categories: [general, web]
|
1415 |
+
timeout: 4.0
|
1416 |
+
shortcut: psvid
|
1417 |
+
disabled: true
|
1418 |
+
|
1419 |
+
- name: presearch news
|
1420 |
+
engine: presearch
|
1421 |
+
network: presearch
|
1422 |
+
search_type: news
|
1423 |
+
categories: [news, web]
|
1424 |
+
timeout: 4.0
|
1425 |
+
shortcut: psnews
|
1426 |
+
disabled: true
|
1427 |
+
|
1428 |
+
- name: pub.dev
|
1429 |
+
engine: xpath
|
1430 |
+
shortcut: pd
|
1431 |
+
search_url: https://pub.dev/packages?q={query}&page={pageno}
|
1432 |
+
paging: true
|
1433 |
+
results_xpath: //div[contains(@class,"packages-item")]
|
1434 |
+
url_xpath: ./div/h3/a/@href
|
1435 |
+
title_xpath: ./div/h3/a
|
1436 |
+
content_xpath: ./div/div/div[contains(@class,"packages-description")]/span
|
1437 |
+
categories: [packages, it]
|
1438 |
+
timeout: 3.0
|
1439 |
+
disabled: true
|
1440 |
+
first_page_num: 1
|
1441 |
+
about:
|
1442 |
+
website: https://pub.dev/
|
1443 |
+
official_api_documentation: https://pub.dev/help/api
|
1444 |
+
use_official_api: false
|
1445 |
+
require_api_key: false
|
1446 |
+
results: HTML
|
1447 |
+
|
1448 |
+
- name: pubmed
|
1449 |
+
engine: pubmed
|
1450 |
+
shortcut: pub
|
1451 |
+
timeout: 3.0
|
1452 |
+
|
1453 |
+
- name: pypi
|
1454 |
+
shortcut: pypi
|
1455 |
+
engine: pypi
|
1456 |
+
|
1457 |
+
- name: qwant
|
1458 |
+
qwant_categ: web
|
1459 |
+
engine: qwant
|
1460 |
+
shortcut: qw
|
1461 |
+
categories: [general, web]
|
1462 |
+
additional_tests:
|
1463 |
+
rosebud: *test_rosebud
|
1464 |
+
|
1465 |
+
- name: qwant news
|
1466 |
+
qwant_categ: news
|
1467 |
+
engine: qwant
|
1468 |
+
shortcut: qwn
|
1469 |
+
categories: news
|
1470 |
+
network: qwant
|
1471 |
+
|
1472 |
+
- name: qwant images
|
1473 |
+
qwant_categ: images
|
1474 |
+
engine: qwant
|
1475 |
+
shortcut: qwi
|
1476 |
+
categories: [images, web]
|
1477 |
+
network: qwant
|
1478 |
+
|
1479 |
+
- name: qwant videos
|
1480 |
+
qwant_categ: videos
|
1481 |
+
engine: qwant
|
1482 |
+
shortcut: qwv
|
1483 |
+
categories: [videos, web]
|
1484 |
+
network: qwant
|
1485 |
+
|
1486 |
+
# - name: library
|
1487 |
+
# engine: recoll
|
1488 |
+
# shortcut: lib
|
1489 |
+
# base_url: 'https://recoll.example.org/'
|
1490 |
+
# search_dir: ''
|
1491 |
+
# mount_prefix: /export
|
1492 |
+
# dl_prefix: 'https://download.example.org'
|
1493 |
+
# timeout: 30.0
|
1494 |
+
# categories: files
|
1495 |
+
# disabled: true
|
1496 |
+
|
1497 |
+
# - name: recoll library reference
|
1498 |
+
# engine: recoll
|
1499 |
+
# base_url: 'https://recoll.example.org/'
|
1500 |
+
# search_dir: reference
|
1501 |
+
# mount_prefix: /export
|
1502 |
+
# dl_prefix: 'https://download.example.org'
|
1503 |
+
# shortcut: libr
|
1504 |
+
# timeout: 30.0
|
1505 |
+
# categories: files
|
1506 |
+
# disabled: true
|
1507 |
+
|
1508 |
+
- name: radio browser
|
1509 |
+
engine: radio_browser
|
1510 |
+
shortcut: rb
|
1511 |
+
|
1512 |
+
- name: reddit
|
1513 |
+
engine: reddit
|
1514 |
+
shortcut: re
|
1515 |
+
page_size: 25
|
1516 |
+
|
1517 |
+
- name: rottentomatoes
|
1518 |
+
engine: rottentomatoes
|
1519 |
+
shortcut: rt
|
1520 |
+
disabled: true
|
1521 |
+
|
1522 |
+
# Required dependency: redis
|
1523 |
+
# - name: myredis
|
1524 |
+
# shortcut : rds
|
1525 |
+
# engine: redis_server
|
1526 |
+
# exact_match_only: false
|
1527 |
+
# host: '127.0.0.1'
|
1528 |
+
# port: 6379
|
1529 |
+
# enable_http: true
|
1530 |
+
# password: ''
|
1531 |
+
# db: 0
|
1532 |
+
|
1533 |
+
# tmp suspended: bad certificate
|
1534 |
+
# - name: scanr structures
|
1535 |
+
# shortcut: scs
|
1536 |
+
# engine: scanr_structures
|
1537 |
+
# disabled: true
|
1538 |
+
|
1539 |
+
- name: searchmysite
|
1540 |
+
engine: xpath
|
1541 |
+
shortcut: sms
|
1542 |
+
categories: general
|
1543 |
+
paging: true
|
1544 |
+
search_url: https://searchmysite.net/search/?q={query}&page={pageno}
|
1545 |
+
results_xpath: //div[contains(@class,'search-result')]
|
1546 |
+
url_xpath: .//a[contains(@class,'result-link')]/@href
|
1547 |
+
title_xpath: .//span[contains(@class,'result-title-txt')]/text()
|
1548 |
+
content_xpath: ./p[@id='result-hightlight']
|
1549 |
+
disabled: true
|
1550 |
+
about:
|
1551 |
+
website: https://searchmysite.net
|
1552 |
+
|
1553 |
+
- name: sepiasearch
|
1554 |
+
engine: sepiasearch
|
1555 |
+
shortcut: sep
|
1556 |
+
|
1557 |
+
- name: soundcloud
|
1558 |
+
engine: soundcloud
|
1559 |
+
shortcut: sc
|
1560 |
+
|
1561 |
+
- name: stackoverflow
|
1562 |
+
engine: stackexchange
|
1563 |
+
shortcut: st
|
1564 |
+
api_site: 'stackoverflow'
|
1565 |
+
categories: [it, q&a]
|
1566 |
+
|
1567 |
+
- name: askubuntu
|
1568 |
+
engine: stackexchange
|
1569 |
+
shortcut: ubuntu
|
1570 |
+
api_site: 'askubuntu'
|
1571 |
+
categories: [it, q&a]
|
1572 |
+
|
1573 |
+
- name: internetarchivescholar
|
1574 |
+
engine: internet_archive_scholar
|
1575 |
+
shortcut: ias
|
1576 |
+
timeout: 15.0
|
1577 |
+
|
1578 |
+
- name: superuser
|
1579 |
+
engine: stackexchange
|
1580 |
+
shortcut: su
|
1581 |
+
api_site: 'superuser'
|
1582 |
+
categories: [it, q&a]
|
1583 |
+
|
1584 |
+
- name: searchcode code
|
1585 |
+
engine: searchcode_code
|
1586 |
+
shortcut: scc
|
1587 |
+
disabled: true
|
1588 |
+
|
1589 |
+
# - name: searx
|
1590 |
+
# engine: searx_engine
|
1591 |
+
# shortcut: se
|
1592 |
+
# instance_urls :
|
1593 |
+
# - http://127.0.0.1:8888/
|
1594 |
+
# - ...
|
1595 |
+
# disabled: true
|
1596 |
+
|
1597 |
+
- name: semantic scholar
|
1598 |
+
engine: semantic_scholar
|
1599 |
+
disabled: true
|
1600 |
+
shortcut: se
|
1601 |
+
|
1602 |
+
# Spotify needs API credentials
|
1603 |
+
# - name: spotify
|
1604 |
+
# engine: spotify
|
1605 |
+
# shortcut: stf
|
1606 |
+
# api_client_id: *******
|
1607 |
+
# api_client_secret: *******
|
1608 |
+
|
1609 |
+
# - name: solr
|
1610 |
+
# engine: solr
|
1611 |
+
# shortcut: slr
|
1612 |
+
# base_url: http://localhost:8983
|
1613 |
+
# collection: collection_name
|
1614 |
+
# sort: '' # sorting: asc or desc
|
1615 |
+
# field_list: '' # comma separated list of field names to display on the UI
|
1616 |
+
# default_fields: '' # default field to query
|
1617 |
+
# query_fields: '' # query fields
|
1618 |
+
# enable_http: true
|
1619 |
+
|
1620 |
+
# - name: springer nature
|
1621 |
+
# engine: springer
|
1622 |
+
# # get your API key from: https://dev.springernature.com/signup
|
1623 |
+
# # working API key, for test & debug: "a69685087d07eca9f13db62f65b8f601"
|
1624 |
+
# api_key: 'unset'
|
1625 |
+
# shortcut: springer
|
1626 |
+
# timeout: 15.0
|
1627 |
+
|
1628 |
+
- name: startpage
|
1629 |
+
engine: startpage
|
1630 |
+
shortcut: sp
|
1631 |
+
timeout: 6.0
|
1632 |
+
disabled: true
|
1633 |
+
additional_tests:
|
1634 |
+
rosebud: *test_rosebud
|
1635 |
+
|
1636 |
+
- name: tokyotoshokan
|
1637 |
+
engine: tokyotoshokan
|
1638 |
+
shortcut: tt
|
1639 |
+
timeout: 6.0
|
1640 |
+
disabled: true
|
1641 |
+
|
1642 |
+
- name: solidtorrents
|
1643 |
+
engine: solidtorrents
|
1644 |
+
shortcut: solid
|
1645 |
+
timeout: 4.0
|
1646 |
+
base_url:
|
1647 |
+
- https://solidtorrents.to
|
1648 |
+
- https://bitsearch.to
|
1649 |
+
|
1650 |
+
# For this demo of the sqlite engine download:
|
1651 |
+
# https://liste.mediathekview.de/filmliste-v2.db.bz2
|
1652 |
+
# and unpack into searx/data/filmliste-v2.db
|
1653 |
+
# Query to test: "!demo concert"
|
1654 |
+
#
|
1655 |
+
# - name: demo
|
1656 |
+
# engine: sqlite
|
1657 |
+
# shortcut: demo
|
1658 |
+
# categories: general
|
1659 |
+
# result_template: default.html
|
1660 |
+
# database: searx/data/filmliste-v2.db
|
1661 |
+
# query_str: >-
|
1662 |
+
# SELECT title || ' (' || time(duration, 'unixepoch') || ')' AS title,
|
1663 |
+
# COALESCE( NULLIF(url_video_hd,''), NULLIF(url_video_sd,''), url_video) AS url,
|
1664 |
+
# description AS content
|
1665 |
+
# FROM film
|
1666 |
+
# WHERE title LIKE :wildcard OR description LIKE :wildcard
|
1667 |
+
# ORDER BY duration DESC
|
1668 |
+
|
1669 |
+
- name: tagesschau
|
1670 |
+
engine: tagesschau
|
1671 |
+
# when set to false, display URLs from Tagesschau, and not the actual source
|
1672 |
+
# (e.g. NDR, WDR, SWR, HR, ...)
|
1673 |
+
use_source_url: true
|
1674 |
+
shortcut: ts
|
1675 |
+
disabled: true
|
1676 |
+
|
1677 |
+
- name: tmdb
|
1678 |
+
engine: xpath
|
1679 |
+
paging: true
|
1680 |
+
categories: movies
|
1681 |
+
search_url: https://www.themoviedb.org/search?page={pageno}&query={query}
|
1682 |
+
results_xpath: //div[contains(@class,"movie") or contains(@class,"tv")]//div[contains(@class,"card")]
|
1683 |
+
url_xpath: .//div[contains(@class,"poster")]/a/@href
|
1684 |
+
thumbnail_xpath: .//img/@src
|
1685 |
+
title_xpath: .//div[contains(@class,"title")]//h2
|
1686 |
+
content_xpath: .//div[contains(@class,"overview")]
|
1687 |
+
shortcut: tm
|
1688 |
+
disabled: true
|
1689 |
+
|
1690 |
+
# Requires Tor
|
1691 |
+
- name: torch
|
1692 |
+
engine: xpath
|
1693 |
+
paging: true
|
1694 |
+
search_url:
|
1695 |
+
http://xmh57jrknzkhv6y3ls3ubitzfqnkrwxhopf5aygthi7d6rplyvk3noyd.onion/cgi-bin/omega/omega?P={query}&DEFAULTOP=and
|
1696 |
+
results_xpath: //table//tr
|
1697 |
+
url_xpath: ./td[2]/a
|
1698 |
+
title_xpath: ./td[2]/b
|
1699 |
+
content_xpath: ./td[2]/small
|
1700 |
+
categories: onions
|
1701 |
+
enable_http: true
|
1702 |
+
shortcut: tch
|
1703 |
+
|
1704 |
+
# torznab engine lets you query any torznab compatible indexer. Using this
|
1705 |
+
# engine in combination with Jackett opens the possibility to query a lot of
|
1706 |
+
# public and private indexers directly from SearXNG. More details at:
|
1707 |
+
# https://docs.searxng.org/dev/engines/online/torznab.html
|
1708 |
+
#
|
1709 |
+
# - name: Torznab EZTV
|
1710 |
+
# engine: torznab
|
1711 |
+
# shortcut: eztv
|
1712 |
+
# base_url: http://localhost:9117/api/v2.0/indexers/eztv/results/torznab
|
1713 |
+
# enable_http: true # if using localhost
|
1714 |
+
# api_key: xxxxxxxxxxxxxxx
|
1715 |
+
# show_magnet_links: true
|
1716 |
+
# show_torrent_files: false
|
1717 |
+
# # https://github.com/Jackett/Jackett/wiki/Jackett-Categories
|
1718 |
+
# torznab_categories: # optional
|
1719 |
+
# - 2000
|
1720 |
+
# - 5000
|
1721 |
+
|
1722 |
+
# tmp suspended - too slow, too many errors
|
1723 |
+
# - name: urbandictionary
|
1724 |
+
# engine : xpath
|
1725 |
+
# search_url : https://www.urbandictionary.com/define.php?term={query}
|
1726 |
+
# url_xpath : //*[@class="word"]/@href
|
1727 |
+
# title_xpath : //*[@class="def-header"]
|
1728 |
+
# content_xpath: //*[@class="meaning"]
|
1729 |
+
# shortcut: ud
|
1730 |
+
|
1731 |
+
- name: unsplash
|
1732 |
+
engine: unsplash
|
1733 |
+
shortcut: us
|
1734 |
+
|
1735 |
+
- name: yandex music
|
1736 |
+
engine: yandex_music
|
1737 |
+
shortcut: ydm
|
1738 |
+
disabled: true
|
1739 |
+
# https://yandex.com/support/music/access.html
|
1740 |
+
inactive: true
|
1741 |
+
|
1742 |
+
- name: yahoo
|
1743 |
+
engine: yahoo
|
1744 |
+
shortcut: yh
|
1745 |
+
disabled: true
|
1746 |
+
|
1747 |
+
- name: yahoo news
|
1748 |
+
engine: yahoo_news
|
1749 |
+
shortcut: yhn
|
1750 |
+
|
1751 |
+
- name: youtube
|
1752 |
+
shortcut: yt
|
1753 |
+
# You can use the engine using the official stable API, but you need an API
|
1754 |
+
# key See: https://console.developers.google.com/project
|
1755 |
+
#
|
1756 |
+
# engine: youtube_api
|
1757 |
+
# api_key: 'apikey' # required!
|
1758 |
+
#
|
1759 |
+
# Or you can use the html non-stable engine, activated by default
|
1760 |
+
engine: youtube_noapi
|
1761 |
+
|
1762 |
+
- name: dailymotion
|
1763 |
+
engine: dailymotion
|
1764 |
+
shortcut: dm
|
1765 |
+
|
1766 |
+
- name: vimeo
|
1767 |
+
engine: vimeo
|
1768 |
+
shortcut: vm
|
1769 |
+
|
1770 |
+
- name: wiby
|
1771 |
+
engine: json_engine
|
1772 |
+
paging: true
|
1773 |
+
search_url: https://wiby.me/json/?q={query}&p={pageno}
|
1774 |
+
url_query: URL
|
1775 |
+
title_query: Title
|
1776 |
+
content_query: Snippet
|
1777 |
+
categories: [general, web]
|
1778 |
+
shortcut: wib
|
1779 |
+
disabled: true
|
1780 |
+
about:
|
1781 |
+
website: https://wiby.me/
|
1782 |
+
|
1783 |
+
- name: alexandria
|
1784 |
+
engine: json_engine
|
1785 |
+
shortcut: alx
|
1786 |
+
categories: general
|
1787 |
+
paging: true
|
1788 |
+
search_url: https://api.alexandria.org/?a=1&q={query}&p={pageno}
|
1789 |
+
results_query: results
|
1790 |
+
title_query: title
|
1791 |
+
url_query: url
|
1792 |
+
content_query: snippet
|
1793 |
+
timeout: 1.5
|
1794 |
+
disabled: true
|
1795 |
+
about:
|
1796 |
+
website: https://alexandria.org/
|
1797 |
+
official_api_documentation: https://github.com/alexandria-org/alexandria-api/raw/master/README.md
|
1798 |
+
use_official_api: true
|
1799 |
+
require_api_key: false
|
1800 |
+
results: JSON
|
1801 |
+
|
1802 |
+
- name: wikibooks
|
1803 |
+
engine: mediawiki
|
1804 |
+
weight: 0.5
|
1805 |
+
shortcut: wb
|
1806 |
+
categories: [general, wikimedia]
|
1807 |
+
base_url: "https://{language}.wikibooks.org/"
|
1808 |
+
search_type: text
|
1809 |
+
disabled: true
|
1810 |
+
about:
|
1811 |
+
website: https://www.wikibooks.org/
|
1812 |
+
wikidata_id: Q367
|
1813 |
+
|
1814 |
+
- name: wikinews
|
1815 |
+
engine: mediawiki
|
1816 |
+
shortcut: wn
|
1817 |
+
categories: [news, wikimedia]
|
1818 |
+
base_url: "https://{language}.wikinews.org/"
|
1819 |
+
search_type: text
|
1820 |
+
srsort: create_timestamp_desc
|
1821 |
+
about:
|
1822 |
+
website: https://www.wikinews.org/
|
1823 |
+
wikidata_id: Q964
|
1824 |
+
|
1825 |
+
- name: wikiquote
|
1826 |
+
engine: mediawiki
|
1827 |
+
weight: 0.5
|
1828 |
+
shortcut: wq
|
1829 |
+
categories: [general, wikimedia]
|
1830 |
+
base_url: "https://{language}.wikiquote.org/"
|
1831 |
+
search_type: text
|
1832 |
+
disabled: true
|
1833 |
+
additional_tests:
|
1834 |
+
rosebud: *test_rosebud
|
1835 |
+
about:
|
1836 |
+
website: https://www.wikiquote.org/
|
1837 |
+
wikidata_id: Q369
|
1838 |
+
|
1839 |
+
- name: wikisource
|
1840 |
+
engine: mediawiki
|
1841 |
+
weight: 0.5
|
1842 |
+
shortcut: ws
|
1843 |
+
categories: [general, wikimedia]
|
1844 |
+
base_url: "https://{language}.wikisource.org/"
|
1845 |
+
search_type: text
|
1846 |
+
disabled: true
|
1847 |
+
about:
|
1848 |
+
website: https://www.wikisource.org/
|
1849 |
+
wikidata_id: Q263
|
1850 |
+
|
1851 |
+
- name: wikispecies
|
1852 |
+
engine: mediawiki
|
1853 |
+
shortcut: wsp
|
1854 |
+
categories: [general, science, wikimedia]
|
1855 |
+
base_url: "https://species.wikimedia.org/"
|
1856 |
+
search_type: text
|
1857 |
+
disabled: true
|
1858 |
+
about:
|
1859 |
+
website: https://species.wikimedia.org/
|
1860 |
+
wikidata_id: Q13679
|
1861 |
+
tests:
|
1862 |
+
wikispecies:
|
1863 |
+
matrix:
|
1864 |
+
query: "Campbell, L.I. et al. 2011: MicroRNAs"
|
1865 |
+
lang: en
|
1866 |
+
result_container:
|
1867 |
+
- not_empty
|
1868 |
+
- ['one_title_contains', 'Tardigrada']
|
1869 |
+
test:
|
1870 |
+
- unique_results
|
1871 |
+
|
1872 |
+
- name: wiktionary
|
1873 |
+
engine: mediawiki
|
1874 |
+
shortcut: wt
|
1875 |
+
categories: [dictionaries, wikimedia]
|
1876 |
+
base_url: "https://{language}.wiktionary.org/"
|
1877 |
+
search_type: text
|
1878 |
+
about:
|
1879 |
+
website: https://www.wiktionary.org/
|
1880 |
+
wikidata_id: Q151
|
1881 |
+
|
1882 |
+
- name: wikiversity
|
1883 |
+
engine: mediawiki
|
1884 |
+
weight: 0.5
|
1885 |
+
shortcut: wv
|
1886 |
+
categories: [general, wikimedia]
|
1887 |
+
base_url: "https://{language}.wikiversity.org/"
|
1888 |
+
search_type: text
|
1889 |
+
disabled: true
|
1890 |
+
about:
|
1891 |
+
website: https://www.wikiversity.org/
|
1892 |
+
wikidata_id: Q370
|
1893 |
+
|
1894 |
+
- name: wikivoyage
|
1895 |
+
engine: mediawiki
|
1896 |
+
weight: 0.5
|
1897 |
+
shortcut: wy
|
1898 |
+
categories: [general, wikimedia]
|
1899 |
+
base_url: "https://{language}.wikivoyage.org/"
|
1900 |
+
search_type: text
|
1901 |
+
disabled: true
|
1902 |
+
about:
|
1903 |
+
website: https://www.wikivoyage.org/
|
1904 |
+
wikidata_id: Q373
|
1905 |
+
|
1906 |
+
- name: wikicommons.images
|
1907 |
+
engine: wikicommons
|
1908 |
+
shortcut: wc
|
1909 |
+
categories: images
|
1910 |
+
search_type: images
|
1911 |
+
number_of_results: 10
|
1912 |
+
|
1913 |
+
- name: wikicommons.videos
|
1914 |
+
engine: wikicommons
|
1915 |
+
shortcut: wcv
|
1916 |
+
categories: videos
|
1917 |
+
search_type: videos
|
1918 |
+
number_of_results: 10
|
1919 |
+
|
1920 |
+
- name: wikicommons.audio
|
1921 |
+
engine: wikicommons
|
1922 |
+
shortcut: wca
|
1923 |
+
categories: music
|
1924 |
+
search_type: audio
|
1925 |
+
number_of_results: 10
|
1926 |
+
|
1927 |
+
- name: wikicommons.files
|
1928 |
+
engine: wikicommons
|
1929 |
+
shortcut: wcf
|
1930 |
+
categories: files
|
1931 |
+
search_type: files
|
1932 |
+
number_of_results: 10
|
1933 |
+
|
1934 |
+
- name: wolframalpha
|
1935 |
+
shortcut: wa
|
1936 |
+
# You can use the engine using the official stable API, but you need an API
|
1937 |
+
# key. See: https://products.wolframalpha.com/api/
|
1938 |
+
#
|
1939 |
+
# engine: wolframalpha_api
|
1940 |
+
# api_key: ''
|
1941 |
+
#
|
1942 |
+
# Or you can use the html non-stable engine, activated by default
|
1943 |
+
engine: wolframalpha_noapi
|
1944 |
+
timeout: 6.0
|
1945 |
+
categories: general
|
1946 |
+
disabled: true
|
1947 |
+
|
1948 |
+
- name: dictzone
|
1949 |
+
engine: dictzone
|
1950 |
+
shortcut: dc
|
1951 |
+
|
1952 |
+
- name: mymemory translated
|
1953 |
+
engine: translated
|
1954 |
+
shortcut: tl
|
1955 |
+
timeout: 5.0
|
1956 |
+
# You can use without an API key, but you are limited to 1000 words/day
|
1957 |
+
# See: https://mymemory.translated.net/doc/usagelimits.php
|
1958 |
+
# api_key: ''
|
1959 |
+
|
1960 |
+
# Required dependency: mysql-connector-python
|
1961 |
+
# - name: mysql
|
1962 |
+
# engine: mysql_server
|
1963 |
+
# database: mydatabase
|
1964 |
+
# username: user
|
1965 |
+
# password: pass
|
1966 |
+
# limit: 10
|
1967 |
+
# query_str: 'SELECT * from mytable WHERE fieldname=%(query)s'
|
1968 |
+
# shortcut: mysql
|
1969 |
+
|
1970 |
+
- name: 1337x
|
1971 |
+
engine: 1337x
|
1972 |
+
shortcut: 1337x
|
1973 |
+
disabled: true
|
1974 |
+
|
1975 |
+
- name: duden
|
1976 |
+
engine: duden
|
1977 |
+
shortcut: du
|
1978 |
+
disabled: true
|
1979 |
+
|
1980 |
+
- name: seznam
|
1981 |
+
shortcut: szn
|
1982 |
+
engine: seznam
|
1983 |
+
disabled: true
|
1984 |
+
|
1985 |
+
# - name: deepl
|
1986 |
+
# engine: deepl
|
1987 |
+
# shortcut: dpl
|
1988 |
+
# # You can use the engine using the official stable API, but you need an API key
|
1989 |
+
# # See: https://www.deepl.com/pro-api?cta=header-pro-api
|
1990 |
+
# api_key: '' # required!
|
1991 |
+
# timeout: 5.0
|
1992 |
+
# disabled: true
|
1993 |
+
|
1994 |
+
- name: mojeek
|
1995 |
+
shortcut: mjk
|
1996 |
+
engine: xpath
|
1997 |
+
paging: true
|
1998 |
+
categories: [general, web]
|
1999 |
+
search_url: https://www.mojeek.com/search?q={query}&s={pageno}&lang={lang}&lb={lang}
|
2000 |
+
results_xpath: //ul[@class="results-standard"]/li/a[@class="ob"]
|
2001 |
+
url_xpath: ./@href
|
2002 |
+
title_xpath: ../h2/a
|
2003 |
+
content_xpath: ..//p[@class="s"]
|
2004 |
+
suggestion_xpath: //div[@class="top-info"]/p[@class="top-info spell"]/em/a
|
2005 |
+
first_page_num: 0
|
2006 |
+
page_size: 10
|
2007 |
+
max_page: 100
|
2008 |
+
disabled: true
|
2009 |
+
about:
|
2010 |
+
website: https://www.mojeek.com/
|
2011 |
+
wikidata_id: Q60747299
|
2012 |
+
official_api_documentation: https://www.mojeek.com/services/api.html/
|
2013 |
+
use_official_api: false
|
2014 |
+
require_api_key: false
|
2015 |
+
results: HTML
|
2016 |
+
|
2017 |
+
- name: moviepilot
|
2018 |
+
engine: moviepilot
|
2019 |
+
shortcut: mp
|
2020 |
+
disabled: true
|
2021 |
+
|
2022 |
+
- name: naver
|
2023 |
+
shortcut: nvr
|
2024 |
+
categories: [general, web]
|
2025 |
+
engine: xpath
|
2026 |
+
paging: true
|
2027 |
+
search_url: https://search.naver.com/search.naver?where=webkr&sm=osp_hty&ie=UTF-8&query={query}&start={pageno}
|
2028 |
+
url_xpath: //a[@class="link_tit"]/@href
|
2029 |
+
title_xpath: //a[@class="link_tit"]
|
2030 |
+
content_xpath: //div[@class="total_dsc_wrap"]/a
|
2031 |
+
first_page_num: 1
|
2032 |
+
page_size: 10
|
2033 |
+
disabled: true
|
2034 |
+
about:
|
2035 |
+
website: https://www.naver.com/
|
2036 |
+
wikidata_id: Q485639
|
2037 |
+
official_api_documentation: https://developers.naver.com/docs/nmt/examples/
|
2038 |
+
use_official_api: false
|
2039 |
+
require_api_key: false
|
2040 |
+
results: HTML
|
2041 |
+
language: ko
|
2042 |
+
|
2043 |
+
- name: rubygems
|
2044 |
+
shortcut: rbg
|
2045 |
+
engine: xpath
|
2046 |
+
paging: true
|
2047 |
+
search_url: https://rubygems.org/search?page={pageno}&query={query}
|
2048 |
+
results_xpath: /html/body/main/div/a[@class="gems__gem"]
|
2049 |
+
url_xpath: ./@href
|
2050 |
+
title_xpath: ./span/h2
|
2051 |
+
content_xpath: ./span/p
|
2052 |
+
suggestion_xpath: /html/body/main/div/div[@class="search__suggestions"]/p/a
|
2053 |
+
first_page_num: 1
|
2054 |
+
categories: [it, packages]
|
2055 |
+
disabled: true
|
2056 |
+
about:
|
2057 |
+
website: https://rubygems.org/
|
2058 |
+
wikidata_id: Q1853420
|
2059 |
+
official_api_documentation: https://guides.rubygems.org/rubygems-org-api/
|
2060 |
+
use_official_api: false
|
2061 |
+
require_api_key: false
|
2062 |
+
results: HTML
|
2063 |
+
|
2064 |
+
- name: peertube
|
2065 |
+
engine: peertube
|
2066 |
+
shortcut: ptb
|
2067 |
+
paging: true
|
2068 |
+
# alternatives see: https://instances.joinpeertube.org/instances
|
2069 |
+
# base_url: https://tube.4aem.com
|
2070 |
+
categories: videos
|
2071 |
+
disabled: true
|
2072 |
+
timeout: 6.0
|
2073 |
+
|
2074 |
+
- name: mediathekviewweb
|
2075 |
+
engine: mediathekviewweb
|
2076 |
+
shortcut: mvw
|
2077 |
+
disabled: true
|
2078 |
+
|
2079 |
+
- name: yacy
|
2080 |
+
engine: yacy
|
2081 |
+
categories: general
|
2082 |
+
search_type: text
|
2083 |
+
base_url:
|
2084 |
+
- https://yacy.searchlab.eu
|
2085 |
+
- https://search.lomig.me
|
2086 |
+
- https://yacy.ecosys.eu
|
2087 |
+
- https://search.webproject.link
|
2088 |
+
shortcut: ya
|
2089 |
+
disabled: true
|
2090 |
+
# required if you aren't using HTTPS for your local yacy instance
|
2091 |
+
# https://docs.searxng.org/dev/engines/online/yacy.html
|
2092 |
+
# enable_http: true
|
2093 |
+
# timeout: 3.0
|
2094 |
+
# search_mode: 'global'
|
2095 |
+
|
2096 |
+
- name: yacy images
|
2097 |
+
engine: yacy
|
2098 |
+
categories: images
|
2099 |
+
search_type: image
|
2100 |
+
shortcut: yai
|
2101 |
+
disabled: true
|
2102 |
+
|
2103 |
+
- name: rumble
|
2104 |
+
engine: rumble
|
2105 |
+
shortcut: ru
|
2106 |
+
base_url: https://rumble.com/
|
2107 |
+
paging: true
|
2108 |
+
categories: videos
|
2109 |
+
disabled: true
|
2110 |
+
|
2111 |
+
- name: livespace
|
2112 |
+
engine: livespace
|
2113 |
+
shortcut: ls
|
2114 |
+
categories: videos
|
2115 |
+
disabled: true
|
2116 |
+
timeout: 5.0
|
2117 |
+
|
2118 |
+
- name: wordnik
|
2119 |
+
engine: wordnik
|
2120 |
+
shortcut: def
|
2121 |
+
base_url: https://www.wordnik.com/
|
2122 |
+
categories: [dictionaries]
|
2123 |
+
timeout: 5.0
|
2124 |
+
|
2125 |
+
- name: woxikon.de synonyme
|
2126 |
+
engine: xpath
|
2127 |
+
shortcut: woxi
|
2128 |
+
categories: [dictionaries]
|
2129 |
+
timeout: 5.0
|
2130 |
+
disabled: true
|
2131 |
+
search_url: https://synonyme.woxikon.de/synonyme/{query}.php
|
2132 |
+
url_xpath: //div[@class="upper-synonyms"]/a/@href
|
2133 |
+
content_xpath: //div[@class="synonyms-list-group"]
|
2134 |
+
title_xpath: //div[@class="upper-synonyms"]/a
|
2135 |
+
no_result_for_http_status: [404]
|
2136 |
+
about:
|
2137 |
+
website: https://www.woxikon.de/
|
2138 |
+
wikidata_id: # No Wikidata ID
|
2139 |
+
use_official_api: false
|
2140 |
+
require_api_key: false
|
2141 |
+
results: HTML
|
2142 |
+
language: de
|
2143 |
+
|
2144 |
+
- name: seekr news
|
2145 |
+
engine: seekr
|
2146 |
+
shortcut: senews
|
2147 |
+
categories: news
|
2148 |
+
seekr_category: news
|
2149 |
+
disabled: true
|
2150 |
+
|
2151 |
+
- name: seekr images
|
2152 |
+
engine: seekr
|
2153 |
+
network: seekr news
|
2154 |
+
shortcut: seimg
|
2155 |
+
categories: images
|
2156 |
+
seekr_category: images
|
2157 |
+
disabled: true
|
2158 |
+
|
2159 |
+
- name: seekr videos
|
2160 |
+
engine: seekr
|
2161 |
+
network: seekr news
|
2162 |
+
shortcut: sevid
|
2163 |
+
categories: videos
|
2164 |
+
seekr_category: videos
|
2165 |
+
disabled: true
|
2166 |
+
|
2167 |
+
- name: sjp.pwn
|
2168 |
+
engine: sjp
|
2169 |
+
shortcut: sjp
|
2170 |
+
base_url: https://sjp.pwn.pl/
|
2171 |
+
timeout: 5.0
|
2172 |
+
disabled: true
|
2173 |
+
|
2174 |
+
- name: stract
|
2175 |
+
engine: stract
|
2176 |
+
shortcut: str
|
2177 |
+
disabled: true
|
2178 |
+
|
2179 |
+
- name: svgrepo
|
2180 |
+
engine: svgrepo
|
2181 |
+
shortcut: svg
|
2182 |
+
timeout: 10.0
|
2183 |
+
disabled: true
|
2184 |
+
|
2185 |
+
- name: tootfinder
|
2186 |
+
engine: tootfinder
|
2187 |
+
shortcut: toot
|
2188 |
+
|
2189 |
+
- name: voidlinux
|
2190 |
+
engine: voidlinux
|
2191 |
+
shortcut: void
|
2192 |
+
disabled: true
|
2193 |
+
|
2194 |
+
- name: wallhaven
|
2195 |
+
engine: wallhaven
|
2196 |
+
# api_key: abcdefghijklmnopqrstuvwxyz
|
2197 |
+
shortcut: wh
|
2198 |
+
|
2199 |
+
# wikimini: online encyclopedia for children
|
2200 |
+
# The fulltext and title parameter is necessary for Wikimini because
|
2201 |
+
# sometimes it will not show the results and redirect instead
|
2202 |
+
- name: wikimini
|
2203 |
+
engine: xpath
|
2204 |
+
shortcut: wkmn
|
2205 |
+
search_url: https://fr.wikimini.org/w/index.php?search={query}&title=Sp%C3%A9cial%3ASearch&fulltext=Search
|
2206 |
+
url_xpath: //li/div[@class="mw-search-result-heading"]/a/@href
|
2207 |
+
title_xpath: //li//div[@class="mw-search-result-heading"]/a
|
2208 |
+
content_xpath: //li/div[@class="searchresult"]
|
2209 |
+
categories: general
|
2210 |
+
disabled: true
|
2211 |
+
about:
|
2212 |
+
website: https://wikimini.org/
|
2213 |
+
wikidata_id: Q3568032
|
2214 |
+
use_official_api: false
|
2215 |
+
require_api_key: false
|
2216 |
+
results: HTML
|
2217 |
+
language: fr
|
2218 |
+
|
2219 |
+
- name: wttr.in
|
2220 |
+
engine: wttr
|
2221 |
+
shortcut: wttr
|
2222 |
+
timeout: 9.0
|
2223 |
+
|
2224 |
+
- name: yummly
|
2225 |
+
engine: yummly
|
2226 |
+
shortcut: yum
|
2227 |
+
disabled: true
|
2228 |
+
|
2229 |
+
- name: brave
|
2230 |
+
engine: brave
|
2231 |
+
shortcut: br
|
2232 |
+
time_range_support: true
|
2233 |
+
paging: true
|
2234 |
+
categories: [general, web]
|
2235 |
+
brave_category: search
|
2236 |
+
# brave_spellcheck: true
|
2237 |
+
|
2238 |
+
- name: brave.images
|
2239 |
+
engine: brave
|
2240 |
+
network: brave
|
2241 |
+
shortcut: brimg
|
2242 |
+
categories: [images, web]
|
2243 |
+
brave_category: images
|
2244 |
+
|
2245 |
+
- name: brave.videos
|
2246 |
+
engine: brave
|
2247 |
+
network: brave
|
2248 |
+
shortcut: brvid
|
2249 |
+
categories: [videos, web]
|
2250 |
+
brave_category: videos
|
2251 |
+
|
2252 |
+
- name: brave.news
|
2253 |
+
engine: brave
|
2254 |
+
network: brave
|
2255 |
+
shortcut: brnews
|
2256 |
+
categories: news
|
2257 |
+
brave_category: news
|
2258 |
+
|
2259 |
+
# - name: brave.goggles
|
2260 |
+
# engine: brave
|
2261 |
+
# network: brave
|
2262 |
+
# shortcut: brgog
|
2263 |
+
# time_range_support: true
|
2264 |
+
# paging: true
|
2265 |
+
# categories: [general, web]
|
2266 |
+
# brave_category: goggles
|
2267 |
+
# Goggles: # required! This should be a URL ending in .goggle
|
2268 |
+
|
2269 |
+
- name: lib.rs
|
2270 |
+
shortcut: lrs
|
2271 |
+
engine: lib_rs
|
2272 |
+
disabled: true
|
2273 |
+
|
2274 |
+
- name: sourcehut
|
2275 |
+
shortcut: srht
|
2276 |
+
engine: xpath
|
2277 |
+
paging: true
|
2278 |
+
search_url: https://sr.ht/projects?page={pageno}&search={query}
|
2279 |
+
results_xpath: (//div[@class="event-list"])[1]/div[@class="event"]
|
2280 |
+
url_xpath: ./h4/a[2]/@href
|
2281 |
+
title_xpath: ./h4/a[2]
|
2282 |
+
content_xpath: ./p
|
2283 |
+
first_page_num: 1
|
2284 |
+
categories: [it, repos]
|
2285 |
+
disabled: true
|
2286 |
+
about:
|
2287 |
+
website: https://sr.ht
|
2288 |
+
wikidata_id: Q78514485
|
2289 |
+
official_api_documentation: https://man.sr.ht/
|
2290 |
+
use_official_api: false
|
2291 |
+
require_api_key: false
|
2292 |
+
results: HTML
|
2293 |
+
|
2294 |
+
- name: goo
|
2295 |
+
shortcut: goo
|
2296 |
+
engine: xpath
|
2297 |
+
paging: true
|
2298 |
+
search_url: https://search.goo.ne.jp/web.jsp?MT={query}&FR={pageno}0
|
2299 |
+
url_xpath: //div[@class="result"]/p[@class='title fsL1']/a/@href
|
2300 |
+
title_xpath: //div[@class="result"]/p[@class='title fsL1']/a
|
2301 |
+
content_xpath: //p[contains(@class,'url fsM')]/following-sibling::p
|
2302 |
+
first_page_num: 0
|
2303 |
+
categories: [general, web]
|
2304 |
+
disabled: true
|
2305 |
+
timeout: 4.0
|
2306 |
+
about:
|
2307 |
+
website: https://search.goo.ne.jp
|
2308 |
+
wikidata_id: Q249044
|
2309 |
+
use_official_api: false
|
2310 |
+
require_api_key: false
|
2311 |
+
results: HTML
|
2312 |
+
language: ja
|
2313 |
+
|
2314 |
+
- name: bt4g
|
2315 |
+
engine: bt4g
|
2316 |
+
shortcut: bt4g
|
2317 |
+
|
2318 |
+
- name: pkg.go.dev
|
2319 |
+
engine: pkg_go_dev
|
2320 |
+
shortcut: pgo
|
2321 |
+
disabled: true
|
2322 |
+
|
2323 |
+
# Doku engine lets you access to any Doku wiki instance:
|
2324 |
+
# A public one or a privete/corporate one.
|
2325 |
+
# - name: ubuntuwiki
|
2326 |
+
# engine: doku
|
2327 |
+
# shortcut: uw
|
2328 |
+
# base_url: 'https://doc.ubuntu-fr.org'
|
2329 |
+
|
2330 |
+
# Be careful when enabling this engine if you are
|
2331 |
+
# running a public instance. Do not expose any sensitive
|
2332 |
+
# information. You can restrict access by configuring a list
|
2333 |
+
# of access tokens under tokens.
|
2334 |
+
# - name: git grep
|
2335 |
+
# engine: command
|
2336 |
+
# command: ['git', 'grep', '{{QUERY}}']
|
2337 |
+
# shortcut: gg
|
2338 |
+
# tokens: []
|
2339 |
+
# disabled: true
|
2340 |
+
# delimiter:
|
2341 |
+
# chars: ':'
|
2342 |
+
# keys: ['filepath', 'code']
|
2343 |
+
|
2344 |
+
# Be careful when enabling this engine if you are
|
2345 |
+
# running a public instance. Do not expose any sensitive
|
2346 |
+
# information. You can restrict access by configuring a list
|
2347 |
+
# of access tokens under tokens.
|
2348 |
+
# - name: locate
|
2349 |
+
# engine: command
|
2350 |
+
# command: ['locate', '{{QUERY}}']
|
2351 |
+
# shortcut: loc
|
2352 |
+
# tokens: []
|
2353 |
+
# disabled: true
|
2354 |
+
# delimiter:
|
2355 |
+
# chars: ' '
|
2356 |
+
# keys: ['line']
|
2357 |
+
|
2358 |
+
# Be careful when enabling this engine if you are
|
2359 |
+
# running a public instance. Do not expose any sensitive
|
2360 |
+
# information. You can restrict access by configuring a list
|
2361 |
+
# of access tokens under tokens.
|
2362 |
+
# - name: find
|
2363 |
+
# engine: command
|
2364 |
+
# command: ['find', '.', '-name', '{{QUERY}}']
|
2365 |
+
# query_type: path
|
2366 |
+
# shortcut: fnd
|
2367 |
+
# tokens: []
|
2368 |
+
# disabled: true
|
2369 |
+
# delimiter:
|
2370 |
+
# chars: ' '
|
2371 |
+
# keys: ['line']
|
2372 |
+
|
2373 |
+
# Be careful when enabling this engine if you are
|
2374 |
+
# running a public instance. Do not expose any sensitive
|
2375 |
+
# information. You can restrict access by configuring a list
|
2376 |
+
# of access tokens under tokens.
|
2377 |
+
# - name: pattern search in files
|
2378 |
+
# engine: command
|
2379 |
+
# command: ['fgrep', '{{QUERY}}']
|
2380 |
+
# shortcut: fgr
|
2381 |
+
# tokens: []
|
2382 |
+
# disabled: true
|
2383 |
+
# delimiter:
|
2384 |
+
# chars: ' '
|
2385 |
+
# keys: ['line']
|
2386 |
+
|
2387 |
+
# Be careful when enabling this engine if you are
|
2388 |
+
# running a public instance. Do not expose any sensitive
|
2389 |
+
# information. You can restrict access by configuring a list
|
2390 |
+
# of access tokens under tokens.
|
2391 |
+
# - name: regex search in files
|
2392 |
+
# engine: command
|
2393 |
+
# command: ['grep', '{{QUERY}}']
|
2394 |
+
# shortcut: gr
|
2395 |
+
# tokens: []
|
2396 |
+
# disabled: true
|
2397 |
+
# delimiter:
|
2398 |
+
# chars: ' '
|
2399 |
+
# keys: ['line']
|
2400 |
+
|
2401 |
+
doi_resolvers:
|
2402 |
+
oadoi.org: 'https://oadoi.org/'
|
2403 |
+
doi.org: 'https://doi.org/'
|
2404 |
+
doai.io: 'https://dissem.in/'
|
2405 |
+
sci-hub.se: 'https://sci-hub.se/'
|
2406 |
+
sci-hub.st: 'https://sci-hub.st/'
|
2407 |
+
sci-hub.ru: 'https://sci-hub.ru/'
|
2408 |
+
|
2409 |
+
default_doi_resolver: 'oadoi.org'
|
searxng/uwsgi.ini
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[uwsgi]
|
2 |
+
# Who will run the code
|
3 |
+
uid = searxng
|
4 |
+
gid = searxng
|
5 |
+
|
6 |
+
# Number of workers (usually CPU count)
|
7 |
+
# default value: %k (= number of CPU core, see Dockerfile)
|
8 |
+
workers = %k
|
9 |
+
|
10 |
+
# Number of threads per worker
|
11 |
+
# default value: 4 (see Dockerfile)
|
12 |
+
threads = 4
|
13 |
+
|
14 |
+
# The right granted on the created socket
|
15 |
+
chmod-socket = 666
|
16 |
+
|
17 |
+
# Plugin to use and interpreter config
|
18 |
+
single-interpreter = true
|
19 |
+
master = true
|
20 |
+
plugin = python3
|
21 |
+
lazy-apps = true
|
22 |
+
enable-threads = 4
|
23 |
+
|
24 |
+
# Module to import
|
25 |
+
module = searx.webapp
|
26 |
+
|
27 |
+
# Virtualenv and python path
|
28 |
+
pythonpath = /usr/local/searxng/
|
29 |
+
chdir = /usr/local/searxng/searx/
|
30 |
+
|
31 |
+
# automatically set processes name to something meaningful
|
32 |
+
auto-procname = true
|
33 |
+
|
34 |
+
# Disable request logging for privacy
|
35 |
+
disable-logging = true
|
36 |
+
log-5xx = true
|
37 |
+
|
38 |
+
# Set the max size of a request (request-body excluded)
|
39 |
+
buffer-size = 8192
|
40 |
+
|
41 |
+
# No keep alive
|
42 |
+
# See https://github.com/searx/searx-docker/issues/24
|
43 |
+
add-header = Connection: close
|
44 |
+
|
45 |
+
# uwsgi serves the static files
|
46 |
+
static-map = /static=/usr/local/searxng/searx/static
|
47 |
+
# expires set to one day
|
48 |
+
static-expires = /* 86400
|
49 |
+
static-gzip-all = True
|
50 |
+
offload-threads = 4
|
searxng/uwsgi.ini.new
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[uwsgi]
|
2 |
+
# Who will run the code
|
3 |
+
uid = searxng
|
4 |
+
gid = searxng
|
5 |
+
|
6 |
+
# Number of workers (usually CPU count)
|
7 |
+
# default value: %k (= number of CPU core, see Dockerfile)
|
8 |
+
workers = %k
|
9 |
+
|
10 |
+
# Number of threads per worker
|
11 |
+
# default value: 4 (see Dockerfile)
|
12 |
+
threads = 4
|
13 |
+
|
14 |
+
# The right granted on the created socket
|
15 |
+
chmod-socket = 666
|
16 |
+
|
17 |
+
# Plugin to use and interpreter config
|
18 |
+
single-interpreter = true
|
19 |
+
master = true
|
20 |
+
plugin = python3
|
21 |
+
lazy-apps = true
|
22 |
+
enable-threads = 4
|
23 |
+
|
24 |
+
# Module to import
|
25 |
+
module = searx.webapp
|
26 |
+
|
27 |
+
# Virtualenv and python path
|
28 |
+
pythonpath = /usr/local/searxng/
|
29 |
+
chdir = /usr/local/searxng/searx/
|
30 |
+
|
31 |
+
# automatically set processes name to something meaningful
|
32 |
+
auto-procname = true
|
33 |
+
|
34 |
+
# Disable request logging for privacy
|
35 |
+
disable-logging = true
|
36 |
+
log-5xx = true
|
37 |
+
|
38 |
+
# Set the max size of a request (request-body excluded)
|
39 |
+
buffer-size = 8192
|
40 |
+
|
41 |
+
# No keep alive
|
42 |
+
# See https://github.com/searx/searx-docker/issues/24
|
43 |
+
add-header = Connection: close
|
44 |
+
|
45 |
+
# Follow SIGTERM convention
|
46 |
+
# See https://github.com/searxng/searxng/issues/3427
|
47 |
+
die-on-term
|
48 |
+
|
49 |
+
# uwsgi serves the static files
|
50 |
+
static-map = /static=/usr/local/searxng/searx/static
|
51 |
+
# expires set to one day
|
52 |
+
static-expires = /* 86400
|
53 |
+
static-gzip-all = True
|
54 |
+
offload-threads = 4
|
tsconfig.json
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"compilerOptions": {
|
3 |
+
"target": "ES2019",
|
4 |
+
"module": "CommonJS",
|
5 |
+
"experimentalDecorators": true,
|
6 |
+
"emitDecoratorMetadata": true,
|
7 |
+
"inlineSourceMap":true,
|
8 |
+
"noImplicitThis": true,
|
9 |
+
"noUnusedLocals": true,
|
10 |
+
"stripInternal": true,
|
11 |
+
"skipLibCheck": true,
|
12 |
+
"pretty": true,
|
13 |
+
"declaration": true,
|
14 |
+
"forceConsistentCasingInFileNames": true,
|
15 |
+
"outDir": "./dist",
|
16 |
+
"rootDir": "backend",
|
17 |
+
"strict": true,
|
18 |
+
"esModuleInterop": true,
|
19 |
+
"strictPropertyInitialization": false
|
20 |
+
},
|
21 |
+
"include": [
|
22 |
+
"backend/**/*"
|
23 |
+
],
|
24 |
+
"exclude": [
|
25 |
+
"node_modules",
|
26 |
+
"dist",
|
27 |
+
"test"
|
28 |
+
]
|
29 |
+
}
|
web/.eslintrc.json
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"root": true,
|
3 |
+
"env": {
|
4 |
+
"browser": true,
|
5 |
+
"node": true,
|
6 |
+
"es2021": true
|
7 |
+
},
|
8 |
+
"extends": [
|
9 |
+
"eslint:recommended",
|
10 |
+
"plugin:@typescript-eslint/recommended",
|
11 |
+
"plugin:vue/vue3-recommended",
|
12 |
+
"plugin:vue/essential",
|
13 |
+
"plugin:tailwindcss/recommended",
|
14 |
+
"prettier"
|
15 |
+
],
|
16 |
+
"overrides": [
|
17 |
+
{
|
18 |
+
"files": ["*.ts", "*.tsx", "*.vue"],
|
19 |
+
"rules": {
|
20 |
+
"@typescript-eslint/no-explicit-any": "off",
|
21 |
+
"semi": "warn",
|
22 |
+
"no-unused-vars": "off"
|
23 |
+
}
|
24 |
+
}
|
25 |
+
],
|
26 |
+
"parserOptions": {
|
27 |
+
"parser": "@typescript-eslint/parser",
|
28 |
+
"ecmaVersion": "latest",
|
29 |
+
"sourceType": "module"
|
30 |
+
},
|
31 |
+
"plugins": ["vue", "@typescript-eslint", "tailwindcss"]
|
32 |
+
}
|
web/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Logs
|
2 |
+
logs
|
3 |
+
*.log
|
4 |
+
npm-debug.log*
|
5 |
+
yarn-debug.log*
|
6 |
+
yarn-error.log*
|
7 |
+
pnpm-debug.log*
|
8 |
+
lerna-debug.log*
|
9 |
+
|
10 |
+
node_modules
|
11 |
+
build
|
12 |
+
dist
|
13 |
+
dist-ssr
|
14 |
+
*.local
|
15 |
+
|
16 |
+
# Editor directories and files
|
17 |
+
.vscode/*
|
18 |
+
!.vscode/extensions.json
|
19 |
+
.idea
|
20 |
+
.DS_Store
|
21 |
+
*.suo
|
22 |
+
*.ntvs*
|
23 |
+
*.njsproj
|
24 |
+
*.sln
|
25 |
+
*.sw?
|