zhzabcd commited on
Commit
755dd12
·
verified ·
1 Parent(s): 25b8335

Upload 101 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
.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?