Upload 8 files
Browse files- Dockerfile +2 -0
- app.ts +82 -0
- constant.ts +95 -0
- home.vue +0 -1
- toolbar.vue +32 -0
Dockerfile
CHANGED
@@ -8,6 +8,8 @@ RUN git clone https://github.com/yokingma/search_with_ai.git /app
|
|
8 |
COPY ./logo.png /app/web/src/assets/logo.png
|
9 |
COPY ./logo.png /app/web/src/public/favicon.ico
|
10 |
COPY ./home.vue /app/web/src/pages/home.vue
|
|
|
|
|
11 |
|
12 |
WORKDIR /app
|
13 |
RUN yarn install && yarn run build
|
|
|
8 |
COPY ./logo.png /app/web/src/assets/logo.png
|
9 |
COPY ./logo.png /app/web/src/public/favicon.ico
|
10 |
COPY ./home.vue /app/web/src/pages/home.vue
|
11 |
+
COPY ./toolbar.vue /app/web/src/components/toolbar.vue
|
12 |
+
COPY ./constant.ts /app/backend/constant.ts
|
13 |
|
14 |
WORKDIR /app
|
15 |
RUN yarn install && yarn run build
|
app.ts
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 './middlewares';
|
8 |
+
import history from 'koa2-connect-history-api-fallback';
|
9 |
+
import { chatStreamController, localChatStreamController, localModelsController, modelsController, searchController, sogouSearchController } from './controllers';
|
10 |
+
import { initializeModels } from './constant'; // 请确保路径正确
|
11 |
+
|
12 |
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
13 |
+
// @ts-ignore
|
14 |
+
import dotenvx from '@dotenvx/dotenvx';
|
15 |
+
dotenvx.config();
|
16 |
+
|
17 |
+
const app = new Koa();
|
18 |
+
const router = new Router();
|
19 |
+
|
20 |
+
const port = process.env.PORT || 3000;
|
21 |
+
|
22 |
+
app.use(history({
|
23 |
+
index: '/index.html',
|
24 |
+
whiteList: ['/api']
|
25 |
+
}));
|
26 |
+
|
27 |
+
// static path
|
28 |
+
const staticPath = path.join(__dirname, '../web/build');
|
29 |
+
app.use(serve(staticPath, {
|
30 |
+
gzip: true,
|
31 |
+
index: 'index.html'
|
32 |
+
}));
|
33 |
+
|
34 |
+
app.use(cors({
|
35 |
+
origin: '*'
|
36 |
+
}));
|
37 |
+
|
38 |
+
app.use(bodyParser());
|
39 |
+
|
40 |
+
// Error handler
|
41 |
+
app.use(async (ctx, next) => {
|
42 |
+
try {
|
43 |
+
await next();
|
44 |
+
} catch(err) {
|
45 |
+
console.error('[server error]', err);
|
46 |
+
ctx.res.statusCode = 422;
|
47 |
+
ctx.body = err;
|
48 |
+
}
|
49 |
+
});
|
50 |
+
|
51 |
+
// router
|
52 |
+
app.use(router.routes()).use(router.allowedMethods());
|
53 |
+
|
54 |
+
// controller
|
55 |
+
router.post('/api/search', whiteListMiddleware(), searchController);
|
56 |
+
router.post('/api/sogou/search', sogouSearchController);
|
57 |
+
router.post('/api/chat', chatStreamController);
|
58 |
+
router.get('/api/models', modelsController);
|
59 |
+
|
60 |
+
// local llm
|
61 |
+
router.get('/api/local/models', localModelsController);
|
62 |
+
router.post('/api/local/chat', localChatStreamController);
|
63 |
+
|
64 |
+
// 创建异步启动函数
|
65 |
+
async function startApp() {
|
66 |
+
try {
|
67 |
+
// 初始化模型
|
68 |
+
await initializeModels();
|
69 |
+
console.log('Models initialized successfully');
|
70 |
+
|
71 |
+
// 启动服务器
|
72 |
+
app.listen(port, () => {
|
73 |
+
console.log(`Server is running on port ${port}`);
|
74 |
+
});
|
75 |
+
} catch (error) {
|
76 |
+
console.error('Failed to start the application:', error);
|
77 |
+
process.exit(1);
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
// 调用启动函数
|
82 |
+
startApp();
|
constant.ts
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { IModelInfo } from './interface';
|
2 |
+
import axios from 'axios';
|
3 |
+
|
4 |
+
// Search engine related. You don't really need to change this.
|
5 |
+
export const EndPoint = {
|
6 |
+
BING_SEARCH_V7_ENDPOINT: 'https://api.bing.microsoft.com/v7.0/search',
|
7 |
+
GOOGLE_SEARCH_ENDPOINT: 'https://www.googleapis.com/customsearch/v1'
|
8 |
+
};
|
9 |
+
|
10 |
+
export const BING_MKT = 'en-US';
|
11 |
+
|
12 |
+
// default timeout ms
|
13 |
+
export const DEFAULT_SEARCH_ENGINE_TIMEOUT = 20000;
|
14 |
+
|
15 |
+
// default search keywords
|
16 |
+
export const DefaultQuery = 'Who said \'live long and prosper';
|
17 |
+
export const DefaultSystem = 'You are a helpful assistant.';
|
18 |
+
|
19 |
+
// 创建一个异步函数来获取模型列表
|
20 |
+
async function fetchOpenAIModels(): Promise<string[]> {
|
21 |
+
try {
|
22 |
+
const response = await axios.get('https://api.deem.love/v1/models');
|
23 |
+
const data = response.data;
|
24 |
+
return data.data.map((model: { id: string }) => model.id);
|
25 |
+
} catch (error) {
|
26 |
+
console.error('获取模型列表失败:', error);
|
27 |
+
return [];
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
// 修改 Models 数组,将 'openai' 平台的模型设置为动态获取
|
32 |
+
export const Models: IModelInfo[] = [
|
33 |
+
{
|
34 |
+
platform: 'aliyun',
|
35 |
+
type: '',
|
36 |
+
models: ['qwen-max', 'qwen-max-1201', 'qwen-turbo', 'qwen-plus']
|
37 |
+
},
|
38 |
+
{
|
39 |
+
platform: 'openai',
|
40 |
+
type: 'openai',
|
41 |
+
//models: ['gpt-3.5-turbo', 'gpt-4-0125-preview', 'gpt-4-turbo-preview', 'gpt-4o']
|
42 |
+
models: [] // 初始为空数组,稍后动态填充
|
43 |
+
},
|
44 |
+
{
|
45 |
+
platform: 'baidu',
|
46 |
+
type: 'baidu',
|
47 |
+
models: ['eb-instant', 'completions_pro', 'ernie_bot_8k']
|
48 |
+
},
|
49 |
+
{
|
50 |
+
platform: 'google',
|
51 |
+
type: 'gemini',
|
52 |
+
models: ['gemini-pro', 'gemini-1.5-pro-latest']
|
53 |
+
},
|
54 |
+
{
|
55 |
+
platform: 'yi',
|
56 |
+
type: 'openai',
|
57 |
+
models: ['yi-34b-chat-0205', 'yi-34b-chat-200k']
|
58 |
+
},
|
59 |
+
{
|
60 |
+
platform: 'moonshot',
|
61 |
+
type: 'openai',
|
62 |
+
models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k']
|
63 |
+
},
|
64 |
+
{
|
65 |
+
platform: 'lepton',
|
66 |
+
type: 'openai',
|
67 |
+
models: ['llama2-7b', 'llama2-13b', 'llama2-70b', 'mixtral-8*7b', 'mixtral-8*22b']
|
68 |
+
},
|
69 |
+
{
|
70 |
+
platform: 'deepseek',
|
71 |
+
type: 'openai',
|
72 |
+
models: ['deepseek-chat', 'deepseek-coder']
|
73 |
+
},
|
74 |
+
{
|
75 |
+
platform: 'chatglm',
|
76 |
+
type: 'openai',
|
77 |
+
models: ['glm-4', 'glm-4v', 'glm-3-turbo']
|
78 |
+
},
|
79 |
+
{
|
80 |
+
platform: 'tencent',
|
81 |
+
type: 'tencent',
|
82 |
+
models: ['std', 'pro']
|
83 |
+
}
|
84 |
+
];
|
85 |
+
|
86 |
+
// 创建一个初始化函数来更新 Models 数组
|
87 |
+
export async function initializeModels() {
|
88 |
+
const openAIModels = await fetchOpenAIModels();
|
89 |
+
Models = Models.map(platform => {
|
90 |
+
if (platform.platform === 'openai') {
|
91 |
+
return { ...platform, models: openAIModels };
|
92 |
+
}
|
93 |
+
return platform;
|
94 |
+
});
|
95 |
+
}
|
home.vue
CHANGED
@@ -4,7 +4,6 @@
|
|
4 |
<div class="flex items-center justify-center gap-2">
|
5 |
<img :src="logoUrl" class="w-10" />
|
6 |
<span class="text-3xl font-bold dark:text-gray-100">AI Search</span>
|
7 |
-
<t-tag variant="light" class="text-xs text-gray-500"></t-tag>
|
8 |
</div>
|
9 |
<SearchInputBar :autofocus="true" :loading="false" @search="search" />
|
10 |
<div class="my-2 flex flex-wrap items-center justify-center gap-4">
|
|
|
4 |
<div class="flex items-center justify-center gap-2">
|
5 |
<img :src="logoUrl" class="w-10" />
|
6 |
<span class="text-3xl font-bold dark:text-gray-100">AI Search</span>
|
|
|
7 |
</div>
|
8 |
<SearchInputBar :autofocus="true" :loading="false" @search="search" />
|
9 |
<div class="my-2 flex flex-wrap items-center justify-center gap-4">
|
toolbar.vue
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script setup lang="ts">
|
2 |
+
import { RiSettingsLine, RiGithubLine } from '@remixicon/vue';
|
3 |
+
|
4 |
+
type Emit = {
|
5 |
+
(e: 'show'): void;
|
6 |
+
}
|
7 |
+
|
8 |
+
const emits = defineEmits<Emit>();
|
9 |
+
|
10 |
+
|
11 |
+
</script>
|
12 |
+
|
13 |
+
<script lang="ts">
|
14 |
+
export default {
|
15 |
+
name: 'ToolBar'
|
16 |
+
};
|
17 |
+
</script>
|
18 |
+
|
19 |
+
<template>
|
20 |
+
<div class="fixed bottom-1/3 right-4 z-50 flex flex-col items-center justify-center gap-4">
|
21 |
+
<div class="flex w-9 justify-center gap-2 rounded-xl bg-gray-200 p-1 shadow-lg dark:bg-gray-600">
|
22 |
+
<t-button href="https://deem.love" target="_blank" shape="circle" theme="default">
|
23 |
+
<template #icon> <RiGithubLine /></template>
|
24 |
+
</t-button>
|
25 |
+
</div>
|
26 |
+
<div class="flex w-9 justify-center gap-2 rounded-xl bg-gray-200 p-1 shadow-lg dark:bg-gray-600">
|
27 |
+
<t-button shape="circle" theme="default" @click="emits('show')">
|
28 |
+
<template #icon> <RiSettingsLine /></template>
|
29 |
+
</t-button>
|
30 |
+
</div>
|
31 |
+
</div>
|
32 |
+
</template>
|