LangChain.js 和 Next.js LLM 后端应用于协助博客撰写和总结领域是一个非常实用的方向!这涉及到理解和处理文本内容,并生成新的、有结构的信息。
在这里插入图片描述

根据您之前提供的代码和需求,我们可以在此基础上进行更具针对性的功能规划和技术实现。

博客撰写和总结助手的核心功能设想

基于您的需求,我们可以将功能分为以下几大类:

  1. 文章内容理解与分析
    • 摘要生成: 快速理解文章核心内容。
    • 关键词提取: 识别文章主题和关键概念。
    • 实体识别: 识别文章中提及的人物、地点、组织等。
    • 情感分析: (可选) 判断文章的整体情绪倾向。
  2. 内容创作辅助
    • 标题/副标题生成: 根据文章内容提供吸引人的标题建议。
    • 段落扩展/改写: 针对某个主题或草稿段落进行内容扩充或重新表达。
    • 引言/结论撰写: 辅助生成文章的开头和结尾。
    • 润色和校对: 检查语法、拼写,并提供表达优化建议。
    • 内容大纲生成: 根据主题或初步想法生成文章结构。
  3. 多模态支持
    • 图片描述生成: 如果有图片,可以生成图片的文字描述或配文。
    • 图片摘要/解读: (可选) 对图片内容进行简要说明。
  4. 用户交互与管理
    • 历史记录与管理: 保存用户生成的内容和对话历史。
    • 自定义提示词: 允许用户创建和保存自己的提示词模板。

技术实现方案调整与优化

我们将重点关注如何将 LangChain.js 的强大能力与 Next.js 的后端特性结合,以实现上述功能。

1. 后端架构调整 (pages/api/lib/)

由于功能的多样性,建议为每个主要功能创建独立的 API 路由,或者在现有 API 中通过 actiontype 参数进行区分。

推荐的 API 路由结构:

pages/
├── api/
│   ├── blog/
│   │   ├── summarize.ts        # 摘要生成
│   │   ├── keywords.ts         # 关键词提取
│   │   ├── outline.ts          # 大纲生成
│   │   ├── expand-rewrite.ts   # 段落扩展/改写
│   │   ├── title-suggest.ts    # 标题建议
│   │   └── proofread.ts        # 润色校对
│   └── chat.ts                 # 通用聊天辅助 (如果保留)
├── lib/
│   ├── langchain/
│   │   ├── models.ts           # LLM 模型实例化 (getChatLLM, getEmbeddings)
│   │   ├── chains.ts           # 各种 LangChain 链的封装 (摘要链, 关键词链等)
│   │   ├── tools.ts            # 如果需要 Agent 工具
│   │   └── memory.ts           # 内存管理 (如果通用聊天需要记忆)
│   └── utils.ts                # 通用工具函数 (如错误处理帮助函数)

lib/langchain/models.ts (基础模型配置):

// lib/langchain/models.ts
import { ChatOpenAI } from "@langchain/openai";
import { OpenAIEmbeddings } from "@langchain/openai";
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { GoogleGenerativeAIEmbeddings } from "@langchain/google-genai";// 根据需要选择 OpenAI 或 Google Gemini
const USE_OPENAI = process.env.LLM_PROVIDER === 'openai';export const getChatLLM = () => {if (USE_OPENAI) {if (!process.env.OPENAI_API_KEY) {throw new Error("OPENAI_API_KEY is not set in .env.local");}return new ChatOpenAI({openAIApiKey: process.env.OPENAI_API_KEY,temperature: 0.7,modelName: "gpt-3.5-turbo", // 或 "gpt-4", "gpt-4o"});} else {if (!process.env.GOOGLE_API_KEY) {throw new Error("GOOGLE_API_KEY is not set in .env.local");}return new ChatGoogleGenerativeAI({apiKey: process.env.GOOGLE_API_KEY,modelName: "gemini-pro",temperature: 0.7,});}
};export const getEmbeddings = () => {if (USE_OPENAI) {if (!process.env.OPENAI_API_KEY) {throw new Error("OPENAI_API_KEY is not set in .env.local");}return new OpenAIEmbeddings({openAIApiKey: process.env.OPENAI_API_KEY,modelName: "text-embedding-ada-002",});} else {if (!process.env.GOOGLE_API_KEY) {throw new Error("GOOGLE_API_KEY is not set in .env.local");}return new GoogleGenerativeAIEmbeddings({apiKey: process.env.GOOGLE_API_KEY,modelName: "embedding-001",});}
};

.env.local 增加配置:

LLM_PROVIDER=openai # 或 google
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
GOOGLE_API_KEY=YOUR_GOOGLE_API_KEY
LLM_API_SECRET_KEY=your_super_secret_api_key_12345
2. 实现具体的 LangChain.js 功能链

以下是几个核心功能的示例实现,都放在 lib/langchain/chains.ts 中。

lib/langchain/chains.ts (示例):

// lib/langchain/chains.ts
import { ChatOpenAI } from "@langchain/openai"; // 或 ChatGoogleGenerativeAI
import { ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser, JsonOutputParser } from "@langchain/core/output_parsers";
import { getChatLLM, getEmbeddings } from "./models"; // 从 models 导入
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { Document } from "@langchain/core/documents";
import { RunnableSequence } from "@langchain/core/runnables";// --- 1. 摘要生成 ---
export async function generateSummary(text: string): Promise<string> {const chatModel = getChatLLM();const prompt = ChatPromptTemplate.fromMessages([SystemMessagePromptTemplate.fromTemplate("你是一个专业的编辑助理,擅长提炼文章要点。"),HumanMessagePromptTemplate.fromTemplate("请为以下文章生成一份简洁的摘要,字数控制在100字以内,并确保包含核心观点和主要发现。\n\n文章内容:\n{text}"),]);const outputParser = new StringOutputParser();const chain = prompt.pipe(chatModel).pipe(outputParser);return chain.invoke({ text });
}// --- 2. 关键词提取 ---
// 假设我们需要一个包含关键词数组的 JSON 输出
interface KeywordsOutput {keywords: string[];
}export async function extractKeywords(text: string): Promise<string[]> {const chatModel = getChatLLM();const prompt = ChatPromptTemplate.fromMessages([SystemMessagePromptTemplate.fromTemplate(`你是一个专业的SEO分析师。请从提供的文章中提取5-10个最相关的关键词,以英文逗号分隔的字符串形式返回。`),HumanMessagePromptTemplate.fromTemplate("文章内容:\n{text}\n\n提取的关键词:"),]);const outputParser = new StringOutputParser(); // 我们可以让LLM直接返回逗号分隔的字符串const chain = prompt.pipe(chatModel).pipe(outputParser);const result = await chain.invoke({ text });return result.split(',').map(keyword => keyword.trim()).filter(Boolean); // 分割并清理
}// --- 3. 标题建议 ---
export async function suggestTitles(content: string): Promise<string[]> {const chatModel = getChatLLM();const prompt = ChatPromptTemplate.fromMessages([SystemMessagePromptTemplate.fromTemplate("你是一个创意内容策划师,擅长为博客文章生成吸引人的标题。"),HumanMessagePromptTemplate.fromTemplate("请根据以下文章内容,提供3-5个不同的、有吸引力的博客文章标题建议。每个标题一行。不包含其他任何额外内容。\n\n文章内容:\n{content}"),]);const outputParser = new StringOutputParser();const chain = prompt.pipe(chatModel).pipe(outputParser);const result = await chain.invoke({ content });return result.split('\n').map(s => s.trim()).filter(Boolean);
}// --- 4. 段落扩展/改写 (RAG 辅助) ---
// 这里的 RAG 并非从外部知识库检索,而是辅助理解用户意图和原始段落。
// 如果需要真正的外部知识 RAG,则需要集成向量数据库。
export async function expandOrRewriteParagraph(originalParagraph: string,instruction: string // 例如 "扩展细节", "用更正式的语言改写", "简化"
): Promise<string> {const chatModel = getChatLLM();const prompt = ChatPromptTemplate.fromMessages([SystemMessagePromptTemplate.fromTemplate(`你是一个专业的文章编辑。你的任务是根据用户的指令对提供的段落进行扩展或改写。请严格按照指令操作,如果指令是扩展,则在原有基础上增加更多细节;如果指令是改写,则保持原意但使用不同的表达方式。指令: ${instruction}`),HumanMessagePromptTemplate.fromTemplate("原始段落:\n{paragraph}\n\n{instruction}后的段落:"),]);const outputParser = new StringOutputParser();const chain = prompt.pipe(chatModel).pipe(outputParser);return chain.invoke({ paragraph: originalParagraph, instruction });
}// --- 5. 内容大纲生成 (基于主题或初步想法) ---
export async function generateOutline(topic: string, requirements?: string): Promise<string> {const chatModel = getChatLLM();const prompt = ChatPromptTemplate.fromMessages([SystemMessagePromptTemplate.fromTemplate(`你是一个结构化思考的AI助手,擅长为博客文章生成清晰的大纲。`),HumanMessagePromptTemplate.fromTemplate(`请为主题“${topic}”生成一份详细的博客文章大纲。
${requirements ? `请注意以下要求:${requirements}` : ''}大纲结构示例:
# 主标题
## 一级标题
### 二级标题
- 要点1
- 要点2
...
`),]);const outputParser = new StringOutputParser();const chain = prompt.pipe(chatModel).pipe(outputParser);return chain.invoke({ topic });
}// --- 6. 润色和校对 ---
export async function proofreadAndRefine(text: string): Promise<string> {const chatModel = getChatLLM();const prompt = ChatPromptTemplate.fromMessages([SystemMessagePromptTemplate.fromTemplate(`你是一个专业的文章校对和润色专家。请检查以下文本的语法、拼写、标点错误,并提供表达更流畅、更专业的修改建议。
请直接给出修改后的完整文本,并用markdown加粗显示所有改动的地方。
`),HumanMessagePromptTemplate.fromTemplate("待润色文本:\n{text}"),]);const outputParser = new StringOutputParser();const chain = prompt.pipe(chatModel).pipe(outputParser);return chain.invoke({ text });
}// --- 7. 多模态支持 (图片描述) ---
// 针对 Google Gemini Pro Vision 模型
// 注意:ChatGoogleGenerativeAI 的 invoke 接受 BaseMessage[] 作为输入
// 图像数据需要是 Base64 编码
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { HumanMessage, AIMessage } from "@langchain/core/messages";export async function generateImageDescription(base64Image: string, promptText: string): Promise<string> {// 确保使用支持多模态的 LLM,例如 "gemini-pro-vision"const chatModel = new ChatGoogleGenerativeAI({apiKey: process.env.GOOGLE_API_KEY,modelName: "gemini-pro-vision",temperature: 0.3,});const message = new HumanMessage({content: [{type: "text",text: promptText, // 用户对图片的问题或描述要求},{type: "image_url",image_url: `data:image/jpeg;base64,${base64Image}`, // 或 image/png 等},],});const res = await chatModel.invoke([message]);return String(res.content);
}// --- RAG (基于文档检索) 基础结构 ---
// 如果您需要真正的 RAG 来回答关于您博客数据的问题
let blogVectorStore: MemoryVectorStore | null = null; // 实际应为外部数据库export async function initializeBlogVectorStore(docs: Document[]) {if (blogVectorStore) return blogVectorStore;const embeddings = getEmbeddings();const splitter = new RecursiveCharacterTextSplitter({chunkSize: 1000,chunkOverlap: 200,});// 假设 `docs` 是从文件加载的博客文章 Document[]const splitDocs = await splitter.splitDocuments(docs);blogVectorStore = await MemoryVectorStore.fromDocuments(splitDocs, embeddings);console.log("Blog vector store initialized.");return blogVectorStore;
}export async function queryBlogContentRAG(question: string): Promise<string> {if (!blogVectorStore) {throw new Error("Blog vector store not initialized. Call initializeBlogVectorStore first.");}const chatModel = getChatLLM();const retriever = blogVectorStore.asRetriever();const prompt = ChatPromptTemplate.fromMessages([SystemMessagePromptTemplate.fromTemplate(`你是一个博客内容专家,擅长从提供的博客文章片段中找到答案。请根据以下上下文信息回答用户的问题。如果信息不足,请礼貌地告知。上下文: {context}`),HumanMessagePromptTemplate.fromTemplate("{question}"),]);const chain = RunnableSequence.from([{context: retriever,question: (input: string) => input,},prompt,chatModel,new StringOutputParser(),]);return chain.invoke(question);
}
3. 后端 API 路由 (pages/api/blog/*.ts)

为每个功能创建独立的 API 路由,以提供清晰的接口。

pages/api/blog/summarize.ts 示例:

// pages/api/blog/summarize.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { generateSummary } from '../../../lib/langchain/chains';
import { authenticateRequest } from '../../../lib/utils/auth'; // 导入认证函数interface RequestBody {content: string;
}interface ResponseData {summary?: string;error?: string;
}export default async function handler(req: NextApiRequest,res: NextApiResponse<ResponseData>
) {const timestamp = new Date().toISOString();// 认证检查const authError = authenticateRequest(req);if (authError) {console.warn(`[${timestamp}] Unauthorized access to /api/blog/summarize: ${authError}`);return res.status(401).json({ error: authError });}if (req.method !== 'POST') {res.setHeader('Allow', ['POST']);console.warn(`[${timestamp}] Method Not Allowed: ${req.method} for ${req.url}`);return res.status(405).json({ error: 'Method Not Allowed' });}const { content }: RequestBody = req.body;if (!content || typeof content !== 'string' || content.trim().length === 0) {console.error(`[${timestamp}] Bad Request: Missing or invalid 'content'. IP: ${req.socket.remoteAddress}`);return res.status(400).json({ error: 'Missing or invalid blog content for summarization.' });}try {console.log(`[${timestamp}] Generating summary for content length: ${content.length}`);const summary = await generateSummary(content);console.log(`[${timestamp}] Summary generated successfully.`);res.status(200).json({ summary });} catch (error: any) {console.error(`[${timestamp}] Error generating summary:`, error.message, error.stack);res.status(500).json({ error: error.message || 'Failed to generate summary.' });}
}

其他功能 API 路由 (pages/api/blog/*.ts) 结构类似,只需替换核心的 LangChain 链调用。

pages/api/blog/image-description.ts (多模态处理):

// pages/api/blog/image-description.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { generateImageDescription } from '../../../lib/langchain/chains';
import { authenticateRequest } from '../../../lib/utils/auth';interface RequestBody {base64Image: string; // 图像的 Base64 编码字符串promptText?: string; // 辅助性提示,如“描述这张图片中的主要内容”
}interface ResponseData {description?: string;error?: string;
}export default async function handler(req: NextApiRequest,res: NextApiResponse<ResponseData>
) {const timestamp = new Date().toISOString();const authError = authenticateRequest(req);if (authError) {console.warn(`[${timestamp}] Unauthorized access to /api/blog/image-description: ${authError}`);return res.status(401).json({ error: authError });}if (req.method !== 'POST') {res.setHeader('Allow', ['POST']);console.warn(`[${timestamp}] Method Not Allowed: ${req.method} for ${req.url}`);return res.status(405).json({ error: 'Method Not Allowed' });}const { base64Image, promptText = "请描述这张图片的内容。" }: RequestBody = req.body;if (!base64Image || typeof base64Image !== 'string' || !base64Image.startsWith('data:image')) {console.error(`[${timestamp}] Bad Request: Missing or invalid 'base64Image'. IP: ${req.socket.remoteAddress}`);return res.status(400).json({ error: 'Missing or invalid base64 image data.' });}try {// 提取纯 Base64 数据部分const base64Data = base64Image.split(',')[1];if (!base64Data) {return res.status(400).json({ error: 'Invalid Base64 image format.' });}console.log(`[${timestamp}] Generating image description for image data length: ${base64Data.length}`);const description = await generateImageDescription(base64Data, promptText);console.log(`[${timestamp}] Image description generated successfully.`);res.status(200).json({ description });} catch (error: any) {console.error(`[${timestamp}] Error generating image description:`, error.message, error.stack);res.status(500).json({ error: error.message || 'Failed to generate image description.' });}
}
4. 辅助函数 (lib/utils/)

lib/utils/auth.ts (认证帮助函数):

// lib/utils/auth.ts
import { NextApiRequest } from 'next';export function authenticateRequest(req: NextApiRequest): string | null {const providedApiKey = req.headers['x-api-key'];const expectedApiKey = process.env.LLM_API_SECRET_KEY;if (!expectedApiKey) {// 这是开发环境的警报,生产环境不应发生console.warn("LLM_API_SECRET_KEY is not set in environment variables. API will be unprotected.");return null; // 或者在生产环境抛出错误}if (!providedApiKey || providedApiKey !== expectedApiKey) {return 'Unauthorized: Invalid or missing API Key';}return null; // 认证成功
}
5. 前端集成 (UI/UX)

前端(例如您的博客编辑页面)需要调用这些新的 API 路由,并将结果展示给用户。

前端示例 (简化版,展示如何调用新 API):

假设您有一个博客编辑器页面,其中包含一个文本区域和一些按钮。

// pages/blog/edit.tsx (示例片段)
import React, { useState } from 'react';
import { Button, Input, message, Upload, Spin } from 'antd'; // 假设使用 Ant Design// ... (导入其他必要的组件和类型) ...export default function BlogEditor() {const [blogContent, setBlogContent] = useState('');const [summary, setSummary] = useState('');const [keywords, setKeywords] = useState<string[]>([]);const [titles, setTitles] = useState<string[]>([]);const [imageDescription, setImageDescription] = useState('');const [loading, setLoading] = useState(false);const callApi = async (endpoint: string, data: any) => {setLoading(true);try {const response = await fetch(`/api/blog/${endpoint}`, {method: 'POST',headers: {'Content-Type': 'application/json','X-API-KEY': process.env.NEXT_PUBLIC_LLM_API_SECRET_KEY || '', // 确保在 next.config.js 中暴露},body: JSON.stringify(data),});if (!response.ok) {const errorData = await response.json();throw new Error(errorData.error || `Failed to call ${endpoint} API.`);}return await response.json();} catch (err: any) {message.error(`操作失败: ${err.message}`);return null;} finally {setLoading(false);}};const handleSummarize = async () => {const result = await callApi('summarize', { content: blogContent });if (result) {setSummary(result.summary);message.success('摘要生成成功!');}};const handleExtractKeywords = async () => {const result = await callApi('keywords', { content: blogContent });if (result) {setKeywords(result.keywords);message.success('关键词提取成功!');}};const handleSuggestTitles = async () => {const result = await callApi('title-suggest', { content: blogContent });if (result) {setTitles(result.titles);message.success('标题建议生成成功!');}};const handleImageUpload = async (file: File) => {if (!file.type.startsWith('image/')) {message.error('只能上传图片文件!');return false;}const reader = new FileReader();reader.readAsDataURL(file);reader.onload = async () => {const base64Image = reader.result as string; // 'data:image/jpeg;base64,...'const result = await callApi('image-description', { base64Image });if (result) {setImageDescription(result.description);message.success('图片描述生成成功!');}};reader.onerror = (error) => {message.error('文件读取失败。');console.error(error);};return false; // 阻止 Upload 组件自动上传};return (<div style={{ padding: '20px' }}><h1>博客内容助手</h1><Input.TextArearows={10}placeholder="在此输入您的博客文章内容..."value={blogContent}onChange={(e) => setBlogContent(e.target.value)}style={{ marginBottom: '20px' }}/><div style={{ marginBottom: '20px' }}><Button onClick={handleSummarize} loading={loading}>生成摘要</Button><Button onClick={handleExtractKeywords} loading={loading} style={{ marginLeft: '10px' }}>提取关键词</Button><Button onClick={handleSuggestTitles} loading={loading} style={{ marginLeft: '10px' }}>建议标题</Button></div>{summary && (<Card title="文章摘要" style={{ marginBottom: '20px' }}><p>{summary}</p></Card>)}{keywords.length > 0 && (<Card title="提取关键词" style={{ marginBottom: '20px' }}>{keywords.map(kw => <Tag key={kw}>{kw}</Tag>)}</Card>)}{titles.length > 0 && (<Card title="建议标题" style={{ marginBottom: '20px' }}><ul>{titles.map((title, index) => <li key={index}>{title}</li>)}</ul></Card>)}{/* 图片描述功能 */}<Card title="图片描述生成" style={{ marginBottom: '20px' }}><Uploadaccept="image/*"beforeUpload={handleImageUpload}showUploadList={false}disabled={loading}><Button loading={loading}>上传图片并生成描述</Button></Upload>{imageDescription && <p style={{ marginTop: '10px' }}>{imageDescription}</p>}</Card>{/* 其他功能按钮和展示区... */}</div>);
}

next.config.js 配置环境变量以暴露给前端:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {reactStrictMode: true,env: {// 暴露给前端的环境变量需要以 NEXT_PUBLIC_ 开头NEXT_PUBLIC_LLM_API_SECRET_KEY: process.env.LLM_API_SECRET_KEY,// 如果您需要在前端根据 LLM_PROVIDER 选择不同的 UI 提示,也可以暴露// NEXT_PUBLIC_LLM_PROVIDER: process.env.LLM_PROVIDER,},
};module.exports = nextConfig;
6. 部署考虑
  • Serverless Function 限制: 注意 Vercel/Netlify 等平台的 Serverless Function 的内存和超时限制。复杂的 Agent 或 RAG 操作可能需要更长的执行时间或更多的内存。如果遇到超时,可能需要优化 LLM 调用逻辑,或考虑使用专用的服务器部署。
  • 成本: LLM 调用是按 Token 计费的。确保前端有适当的输入限制和提示,避免用户无意中生成过长的内容导致高额费用。
  • 安全性: 再次强调 API Key 的安全管理。生产环境中,客户端不应直接拥有 LLM_API_SECRET_KEY,而应通过用户认证系统(如 NextAuth.js)来授权前端请求后端 API。

总结

通过上述规划和代码示例,您可以构建一个功能丰富的博客撰写和总结助手。核心思路是:

  • 模块化: 将 LangChain 链和 API 路由解耦,方便管理和扩展。
  • 通用化: 封装 LLM 模型实例化,方便切换 LLM 提供商。
  • 用户体验: 考虑加载状态、错误提示、流式传输(如果需要)以提升用户体验。
  • 安全性: 实现基本的 API 密钥验证,并在生产环境中升级为更强大的认证方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84932.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84932.shtml
英文地址,请注明出处:http://en.pswp.cn/web/84932.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用 GitHub Issues 做任务管理和任务 List,简单好用!

说实话&#xff0c;我平时也是一个人写代码&#xff0c;每次开完会整理任务最麻烦&#xff1a; 一堆事项堆在聊天里、文档里&#xff0c;或者散落在邮件里…… 为了理清这些&#xff0c;我通常会做一份 List&#xff0c;标好优先级&#xff0c;再安排到每日的工作里 虽然这个…

每日算法刷题Day35 6.22:leetcode枚举技巧枚举中间2道题,用时1h

枚举中间 对于三个或者四个变量的问题&#xff0c;枚举中间的变量往往更好算。 为什么&#xff1f;比如问题有三个下标&#xff0c;需要满足 0≤i<j<k<n&#xff0c;对比一下&#xff1a; 枚举 i&#xff0c;后续计算中还需保证 j<k。 枚举 j&#xff0c;那么 i 和…

【教学类-18-06】20250623蒙德里安黑白七款合并WORD(500张、无学号)

背景需要 客户买了蒙德里安黑白格子7种尺寸,但是不需要学号方块,并指定要WORD 设计思路 【教学类-18-05】20241118正方形手工纸(蒙德里安-风格派-红黄蓝黑白)-CSDN博客文章浏览阅读1.3k次,点赞29次,收藏18次。【教学类-18-05】20241118正方形手工纸(蒙德里安-风格派-红…

langchain--(4)

7 Embedding文本向量化 Embedding文本向量化是一种将非结构化文本转化为低维、连续数值向量的技术,旨在通过数学方式捕捉文本的语义、语法或特征信息,从而让机器更高效地处理语言任务。其核心思想源于流形假设(Manifold Hypothesis),即认为高维原始数据(如文本)实际隐含…

DMDRS部署实施手册(ORACLE=》DM)

DMDRS部署实施手册&#xff08;ORACLE》DM&#xff09; 1 同步说明2 DMDRS安装3 数据库准备3.1 源端准备3.1.1 开启归档日志和附加日志3.1.2 关闭回收站3.1.3 创建同步用户 3.2 目标准备3.2.1 创建同步用户 4 DMDRS配置4.1 源端配置4.2 目标配置 5 DMDRS启动5.1 启动源端服务5.…

十(1)作业:sqli-labs重点关卡

参考文章&#xff1a;详细sqli-labs&#xff08;1-65&#xff09;通关讲解-CSDN博客 第1关&#xff1a; 输入 &#xff1a; ?id3 输入 &#xff1a; ?id2 当输入的数字不同&#xff0c;页面的响应也不同&#xff0c;说明&#xff0c;输入的内容被带入到数据库里查询了 输…

Python 爬虫入门 Day 7 - 复盘 + 实战挑战日

Python 第二阶段 - 爬虫入门 &#x1f3af; 本周知识回顾 网络请求与网页结构基础 HTML解析入门&#xff08;使用 BeautifulSoup&#xff09; 实现爬虫多页抓取与翻页逻辑 模拟登录爬虫与 Session 维持 使用 XPath 进行网页解析&#xff08;lxml XPath&#xff09; 反爬虫应对…

WebRTC(七):媒体能力协商

目的 在 WebRTC 中&#xff0c;每个浏览器或终端支持的音视频编解码器、分辨率、码率、帧率等可能不同。媒体能力协商的目的就是&#xff1a; 确保双方能“听得懂”对方发的媒体流&#xff1b;明确谁发送、谁接收、怎么发送&#xff1b;保障连接的互操作性和兼容性。 P2P的基…

可信启动方案设计

安全之安全(security)博客目录导读 目录 一、引言 二、关键数据(Critical Data) 三、度量槽(Measurement Slot) 四、可信启动后端 1、事件日志(Event Log) 2、离散型 TPM(Discrete TPM) 3、RSE(运行时安全引擎) 五、平台接口 平台接口的职责: 1、函数:b…

✨通义万相2.1深度解析:AI视频生成引擎FLF2V-14B全流程指南(命令行参数+模型架构+数据流)

&#x1f31f; 从零详解&#xff1a;如何用AI模型生成视频&#xff1f;命令行、模型结构、数据流全解析&#xff01; 本文通过一个实际案例&#xff0c;详细解析使用AI模型生成视频的整个流程。从命令行参数解读到模型结构&#xff0c;再到数据在模型间的流动&#xff0c;一步步…

在 TypeScript 前端中使用 Umi-Request 调用 Java 接口的完整指南

下面我将详细介绍如何在基于 TypeScript 的前端项目中使用 umi-request 调用 IntelliJ IDEA 中开发的 Java 接口&#xff0c;包括完整的实现方案和代码示例。 整体方案设计 一、Java 后端接口准备 1. 创建 Spring Boot 控制器 // src/main/java/com/example/demo/controller…

GO Gin Web框架面试题及参考答案

目录 Gin 与 net/http 有哪些主要区别?为什么选择 Gin? 如何使用 Gin 启动一个 HTTP 服务并设置默认路由? Gin 的默认路由和自定义路由器组是如何工作的? 如何在 Gin 中绑定请求参数(Query、Form、JSON、XML)? 如何在 Gin 中使用中间件?中间件执行顺序是怎样的? …

asp.net core Razor动态语言编程代替asp.net .aspx更高级吗?

For Each item In products<tr><td>item.Id</td><td>item.Name</td><td>item.Price.ToString("C")</td></tr>Next为什么要用<tr> ? 在Blazor的Razor语法中&#xff0c;使用<tr>是为了在VB.NET代码块中…

css语法中的选择器与属性详解:嵌套声明、集体声明、全局声明、混合选择器

嵌套声明 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>嵌套声明</title> <!-- 这里p span 的含义是p标签下面的span标签 所以有嵌套关系--><style>p span {font-weight:…

Linux 系统中,/usr/bin/ 和/bin/的区别?

在 Linux 系统中&#xff0c;/bin/ 和 /usr/bin/ 都是存放可执行程序&#xff08;命令&#xff09;的目录&#xff0c;但它们在历史定位、用途、挂载策略和系统设计上有一定区别。 ✅ 快速对比总结 项目/bin//usr/bin/全称含义binary&#xff08;核心二进制&#xff09;user b…

苍穹外卖--WebSocket、来单提醒、客户催单

WebSocket 1.介绍 WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并进行双向数据传送。 HTTP协议和WebSocket协议对比&#xff1a; ①Http是短连接 ②W…

Linux 信号(Signal)与信号量(Semaphore)区别

特性信号 (Signal)信号量 (Semaphore)本质软件中断进程间同步机制用途通知进程发生了某个事件控制对共享资源的访问通信方向单向 (内核→进程 或 进程→进程)多进程共享数据类型整数信号编号内核维护的计数器持久性瞬时,不排队持久,直到显式释放实现层次内核实现内核或用户空…

华为OD机考-观看文艺汇演问题-区间问题(JAVA 2025B卷)

import java.util.*; /*** version Ver 1.0* date 2025/6/20* description 观看文艺汇演*/ public class WatchMovie {public static void main(String[] args) {Scanner sc new Scanner(System.in);int num Integer.parseInt(sc.nextLine());List<Movie> movies new …

DeepSeek今天喝什么随机奶茶推荐器

用DeepSeek生成了一个随机奶茶推荐器-今天喝什么&#xff0c;效果非常棒&#xff01;UI界面美观。 提示词prompt如下 用html5帮我生成一个今天喝什么的网页 点击按钮随机生成奶茶品牌等&#xff0c;要包括中国常见的知名的奶茶品牌 如果不满意还可以随机再次生成 ui界面要好看 …

【国产AI服务器】全国产PCIE5.0交换板,替代博通89104/89144,支持海光、龙芯等平台

实物图 核心硬件配置 1、控制器芯片‌ 采用国产TL63104控制芯片‌&#xff0c;支持2.5GT/s、5GT/s、8GT/s、16GT/s、32GT/s的PCIe传输速率&#xff0c;支持968Lanes。支持6个x16的group和1个x8的group&#xff0c;每个group支持1至8个端口。x16group支持x16、x8、x4、x2端口…