refactor:删除未使用的文件,添加文章总结功能及相关处理逻辑
This commit is contained in:
54
src/controller/summarizeHandler.ts
Normal file
54
src/controller/summarizeHandler.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import type { Context } from "elysia";
|
||||
import { JSDOM } from "jsdom";
|
||||
import callGeminiAPI from "../llm/gemini";
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export async function summarizeHandler({ body }: Context) {
|
||||
try {
|
||||
const { articleUrl } = body as { articleUrl: string };
|
||||
const urls = articleUrl.split('\n').filter(url => url.trim() !== '');
|
||||
|
||||
async function fetchArticle(url: string): Promise<string> {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch article: Status Code ${response.status}`);
|
||||
}
|
||||
return await response.text();
|
||||
}
|
||||
|
||||
let articleTexts = [];
|
||||
for (const url of urls) {
|
||||
try {
|
||||
const articleHTML = await fetchArticle(url);
|
||||
const dom = new JSDOM(articleHTML);
|
||||
const jsContent = dom.window.document.querySelector("#js_content");
|
||||
const content = jsContent ? jsContent.textContent : "";
|
||||
articleTexts.push(content);
|
||||
} catch (error) {
|
||||
console.error(`Failed to process article from ${url}:`, error);
|
||||
// Optionally, you might want to handle the error more gracefully,
|
||||
// such as skipping the article or returning a default value.
|
||||
}
|
||||
}
|
||||
|
||||
const geminiResponse = await callGeminiAPI(articleTexts);
|
||||
const today = new Date();
|
||||
const fileName = `history/${today.getFullYear()}/${today.getMonth() + 1}/${today.getDate()}.md`;
|
||||
const dir = path.dirname(fileName);
|
||||
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
fs.writeFileSync(fileName, geminiResponse);
|
||||
return new Response(geminiResponse, {
|
||||
headers: {
|
||||
"Content-Type": "text/markdown; charset=utf-8",
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error("Error:", error);
|
||||
return { error: error.message };
|
||||
}
|
||||
}
|
||||
20
src/index.ts
Normal file
20
src/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Elysia } from "elysia";
|
||||
import { html } from '@elysiajs/html'
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { summarizeHandler } from "./controller/summarizeHandler";
|
||||
|
||||
const app = new Elysia()
|
||||
.use(html())
|
||||
.get("/", () => {
|
||||
// 读取 HTML 文件
|
||||
const filePath = path.join(process.cwd(), 'index.html');
|
||||
const htmlContent = fs.readFileSync(filePath, 'utf8');
|
||||
return htmlContent;
|
||||
})
|
||||
.post("/summarize", summarizeHandler)
|
||||
.listen({ port: 3000 });
|
||||
|
||||
console.log(
|
||||
`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
|
||||
);
|
||||
50
src/llm/gemini.ts
Normal file
50
src/llm/gemini.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
async function callGeminiAPI(articleContent: string[]): Promise<any> {
|
||||
// articleContent = `You are a helpful assistant that summarizes WeChat articles.use Chinese: ${articleContent}`;
|
||||
// const response = (await model.generateContent(articleContent)).response;
|
||||
// return response.text();
|
||||
|
||||
|
||||
const {
|
||||
GoogleGenerativeAI,
|
||||
HarmCategory,
|
||||
HarmBlockThreshold,
|
||||
} = require("@google/generative-ai");
|
||||
|
||||
const genAI = new GoogleGenerativeAI(process.env.API_KEY || "");
|
||||
console.log(process.env.API_KEY);
|
||||
|
||||
const model = genAI.getGenerativeModel({
|
||||
model: "gemini-2.0-flash-lite-preview-02-05"
|
||||
});
|
||||
|
||||
const generationConfig = {
|
||||
temperature: 1,
|
||||
topP: 0.95,
|
||||
topK: 40,
|
||||
maxOutputTokens: 8192,
|
||||
responseMimeType: "text/plain",
|
||||
};
|
||||
|
||||
async function run(articleContent: string[]) {
|
||||
const chatSession = model.startChat({
|
||||
generationConfig,
|
||||
history: [
|
||||
{
|
||||
role: "user",
|
||||
parts: [
|
||||
{ text: "这里有几篇文章,用 --- 分割,帮我简要汇总一下,控制在 300 字以内。" },
|
||||
{ text: "如果你认为是投资主题,我希望你能额外帮我总结和设计出一个短中长线的投资策略,要求详略得当,短线权重大一些,长线一笔带过就好" }
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const result = await chatSession.sendMessage(articleContent.join("\n---\n"));
|
||||
console.log(result.response.text());
|
||||
return result.response.text();
|
||||
}
|
||||
|
||||
return run(articleContent);
|
||||
}
|
||||
|
||||
export default callGeminiAPI;
|
||||
17
src/view/form.html
Normal file
17
src/view/form.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>文章总结</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>输入微信文章链接</h1>
|
||||
<form action="/summarize" method="post">
|
||||
<label for="articleUrl">文章链接:</label><br>
|
||||
<textarea id="articleUrl" name="articleUrl" rows="4" cols="50"></textarea><br><br>
|
||||
<input type="submit" value="提交">
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user