diff --git a/.env b/.env index 922973d..2c9dc3c 100644 --- a/.env +++ b/.env @@ -11,4 +11,7 @@ PROXY_HOST=127.0.0.1 PROXY_PORT=3211 # 日志级别(可选):error, warn, info, debug, verbose -LOG_LEVEL=info \ No newline at end of file +LOG_LEVEL=info + +# OpenAI API Key (用于 AI 推荐) +ARK_API_KEY=a63d58b6-cf56-434b-8a42-5c781ba0822a \ No newline at end of file diff --git a/.env.example b/.env.example index 8116932..2f36d00 100644 --- a/.env.example +++ b/.env.example @@ -13,4 +13,7 @@ PROXY_PORT=6000 # PROXY_PASSWORD= # 日志级别(可选):error, warn, info, debug, verbose -LOG_LEVEL=info \ No newline at end of file +LOG_LEVEL=info + +# OpenAI API Key (用于 AI 推荐) +ARK_API_KEY=your_openai_api_key_here \ No newline at end of file diff --git a/frontend/.env b/frontend/.env new file mode 100644 index 0000000..40e3e3c --- /dev/null +++ b/frontend/.env @@ -0,0 +1,2 @@ +# ARK API Key (用于 AI 推荐) +VITE_ARK_API_KEY=a63d58b6-cf56-434b-8a42-5c781ba0822a diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 0000000..56dd77d --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1,2 @@ +# OpenAI API Key (用于 AI 推荐) +VITE_OPENAI_API_KEY=your_openai_api_key_here diff --git a/frontend/package.json b/frontend/package.json index 4f6271b..ad98159 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,7 @@ "@element-plus/icons-vue": "^2.3.2", "axios": "^1.13.2", "element-plus": "^2.13.1", + "openai": "^6.16.0", "vue": "^3.5.24" }, "devDependencies": { diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 96de7ce..019aa92 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -15,10 +15,14 @@ Dashboard + + Dashboard AI + + Bids - + Keywords @@ -41,9 +45,14 @@ @refresh="fetchData" /> - + + import { ref, onMounted } from 'vue' import axios from 'axios' -import { DataBoard, Document, Setting } from '@element-plus/icons-vue' +import { DataBoard, Document, Setting, MagicStick } from '@element-plus/icons-vue' import Dashboard from './components/Dashboard.vue' +import DashboardAI from './components/Dashboard-AI.vue' import Bids from './components/Bids.vue' import Keywords from './components/Keywords.vue' diff --git a/frontend/src/components/Dashboard-AI.vue b/frontend/src/components/Dashboard-AI.vue new file mode 100644 index 0000000..b47bf30 --- /dev/null +++ b/frontend/src/components/Dashboard-AI.vue @@ -0,0 +1,294 @@ + + + + + diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json index 8d16e42..abc1598 100644 --- a/frontend/tsconfig.app.json +++ b/frontend/tsconfig.app.json @@ -12,5 +12,5 @@ "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "../src/ai/Prompt.ts"] } diff --git a/package.json b/package.json index 84186aa..e7bd0ee 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "test:e2e": "jest --config ./test/jest-e2e.json", "crawl": "ts-node -r tsconfig-paths/register src/scripts/crawl.ts", "update-source": "ts-node -r tsconfig-paths/register src/scripts/update-source.ts", - "web":"npm --prefix frontend run build" + "web": "npm --prefix frontend run build" }, "dependencies": { "@nestjs/common": "^11.0.1", @@ -35,6 +35,7 @@ "class-validator": "^0.14.3", "dotenv": "^16.4.7", "mysql2": "^3.16.0", + "openai": "^6.16.0", "puppeteer": "^24.34.0", "puppeteer-extra": "^3.3.6", "puppeteer-extra-plugin-stealth": "^2.11.2", diff --git a/src/ai/ai.controller.ts b/src/ai/ai.controller.ts new file mode 100644 index 0000000..df38c61 --- /dev/null +++ b/src/ai/ai.controller.ts @@ -0,0 +1,23 @@ +import { Controller, Post, Body } from '@nestjs/common'; +import { AiService } from './ai.service'; + +export class BidDataDto { + title: string; + url: string; + source: string; + publishDate: string; +} + +export class BidsRequestDto { + bids: BidDataDto[]; +} + +@Controller('api/ai') +export class AiController { + constructor(private readonly aiService: AiService) {} + + @Post('recommendations') + async getRecommendations(@Body() request: BidsRequestDto) { + return this.aiService.getRecommendations(request.bids); + } +} diff --git a/src/ai/ai.module.ts b/src/ai/ai.module.ts new file mode 100644 index 0000000..8cd91f4 --- /dev/null +++ b/src/ai/ai.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { AiController } from './ai.controller'; +import { AiService } from './ai.service'; + +@Module({ + imports: [ConfigModule], + controllers: [AiController], + providers: [AiService], + exports: [AiService], +}) +export class AiModule {} diff --git a/src/app.module.ts b/src/app.module.ts index a5cb2de..85840be 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -9,6 +9,7 @@ import { KeywordsModule } from './keywords/keywords.module'; import { CrawlerModule } from './crawler/crawler.module'; import { TasksModule } from './schedule/schedule.module'; import { LoggerModule } from './common/logger/logger.module'; +import { AiModule } from './ai/ai.module'; @Module({ imports: [ @@ -16,7 +17,7 @@ import { LoggerModule } from './common/logger/logger.module'; ScheduleModule.forRoot(), ServeStaticModule.forRoot({ rootPath: join(__dirname, '..', 'frontend', 'dist'), - exclude: ['/api*'], + exclude: ['/api/(.*)'], }), LoggerModule, DatabaseModule, @@ -24,6 +25,7 @@ import { LoggerModule } from './common/logger/logger.module'; KeywordsModule, CrawlerModule, TasksModule, + AiModule, ], }) export class AppModule {} \ No newline at end of file