快速原型开发使用Python Flask构建BERT文本分割演示Web应用想快速把AI模型的能力包装成一个能看能用的网页应用吗今天我们就来动手用最轻量级的Python Web框架Flask为BERT文本分割模型搭建一个演示应用。整个过程就像搭积木即使你是刚接触Web开发的新手也能跟着一步步做出来。这个应用很简单用户在前端输入一段长文本点击按钮后端调用BERT模型把文本分割成逻辑连贯的段落最后前端用不同颜色把各个段落高亮展示出来。通过这个项目你不仅能学会如何将AI模型API与Web应用结合还能掌握一个快速验证AI想法、制作演示Demo的完整流程。1. 项目准备与环境搭建在开始敲代码之前我们需要先把“舞台”搭好。这包括安装必要的工具和创建项目的“骨架”。1.1 安装必要的工具首先确保你的电脑上已经安装了Python建议使用Python 3.8或更高版本。然后我们通过一个命令来安装这个项目唯一的核心依赖——Flask。打开你的终端Windows上是命令提示符或PowerShellMac/Linux上是Terminal输入以下命令pip install flask如果安装速度慢可以考虑使用国内的镜像源比如加上-i https://pypi.tuna.tsinghua.edu.cn/simple。安装成功后你可以通过flask --version来验证一下。1.2 创建项目结构接下来为我们的项目创建一个专属的文件夹并规划好里面的文件。一个好的结构能让代码更清晰后期维护也方便。在你的电脑上找个合适的位置新建一个文件夹例如叫做bert_segmentation_demo。然后在里面创建以下几个文件和文件夹bert_segmentation_demo/ ├── app.py # 后端Flask主程序 ├── static/ # 存放静态文件CSS, JS │ └── style.css # 网页样式 ├── templates/ # 存放HTML模板 │ └── index.html # 主页面 └── requirements.txt # 项目依赖列表可选你可以手动创建也可以用终端命令mkdir和touch在Mac/Linux上来快速创建。requirements.txt文件可以先留空或者简单写上一行flask方便以后别人部署你的项目时知道需要安装什么。2. 编写后端Flask应用核心后端就像是餐厅的后厨负责接收前台的订单用户请求加工处理调用模型然后把做好的菜处理结果送回前台。我们的“后厨”代码就写在app.py里。2.1 初始化Flask应用打开app.py文件我们开始编写后端的第一个部分初始化应用和定义主页路由。from flask import Flask, render_template, request, jsonify import requests import json app Flask(__name__) # 假设你的BERT文本分割模型API地址 # 这里我们用一个大模型平台的文本分割API作为示例你需要替换成你自己的API地址和密钥 MODEL_API_URL https://api.example.com/v1/chat/completions # 示例地址需替换 API_KEY your_api_key_here # 你的API密钥 app.route(/) def index(): 渲染主页面 return render_template(index.html)这段代码做了几件事导入必要的模块Flask用来创建应用render_template用来渲染HTML页面request用来获取前端发来的数据jsonify用来把Python数据转换成JSON格式返回给前端。创建了一个Flask应用实例名字叫app。定义了一个路由/。当用户访问网站根目录比如http://localhost:5000/时Flask就会执行index()这个函数它返回渲染好的index.html页面。2.2 构建模型调用函数现在我们来编写最关键的部分一个函数它能够把我们收到的用户文本发送给远端的BERT模型API并取回分割好的结果。这里我们模拟调用一个提供文本分割功能的模型API。def call_bert_segmentation_api(text): 调用BERT文本分割API示例。 注意你需要根据实际使用的API文档调整请求格式。 headers { Authorization: fBearer {API_KEY}, Content-Type: application/json } # 构建符合特定API要求的请求数据 # 这里的prompt和格式是示例请务必替换为你所用API的实际格式 payload { model: text-segmentation-model, # 模型名称需替换 messages: [ { role: user, content: f请将以下文本分割成意义完整的段落并直接输出段落列表不要额外解释\n\n{text} } ], temperature: 0.1 # 低温度使输出更确定适合分割任务 } try: response requests.post(MODEL_API_URL, headersheaders, jsonpayload, timeout30) response.raise_for_status() # 如果请求失败4xx或5xx抛出异常 result response.json() # 解析API返回结果这里需要根据实际API响应结构来调整 # 假设返回的文本在 choices[0].message.content 中并且是以换行或特定符号分隔的段落 segmented_text result.get(choices, [{}])[0].get(message, {}).get(content, ) # 简单处理按换行符分割过滤空行 paragraphs [p.strip() for p in segmented_text.split(\n) if p.strip()] # 如果解析失败或为空返回原始文本作为一个段落 if not paragraphs: paragraphs [text] return paragraphs except requests.exceptions.RequestException as e: print(f调用API时出错: {e}) # 出错时返回原始文本作为一个段落保证前端有显示 return [text]重要提示上面的MODEL_API_URL、API_KEY以及payload的构造方式都是示例。在实际操作中你需要将其替换为你自己部署的BERT文本分割模型的真实API地址、密钥以及符合该API文档要求的请求格式。你可以使用任何提供类似功能的模型服务平台。2.3 创建处理请求的API路由有了调用函数我们需要创建一个“窗口”来接收前端的请求。这个窗口在Web开发里就叫API接口。app.route(/segment, methods[POST]) def segment_text(): 处理文本分割请求的API接口 # 从前端发送的JSON数据中获取用户输入的文本 data request.get_json() input_text data.get(text, ).strip() if not input_text: return jsonify({error: 输入文本不能为空, paragraphs: []}) # 调用上面定义的函数获取分割后的段落列表 paragraphs call_bert_segmentation_api(input_text) # 将结果以JSON格式返回给前端 return jsonify({ success: True, paragraphs: paragraphs, original_length: len(input_text), segment_count: len(paragraphs) }) if __name__ __main__: # 启动Flask开发服务器debugTrue便于调试 app.run(debugTrue, port5000)这个/segment路由只接受POST请求。它从前端拿到文本调用模型然后把分割好的段落列表、原始文本长度和段落数量打包成一个JSON对象返回给前端。最后两行代码是标准写法意思是当直接运行这个app.py脚本时就启动Flask自带的开发服务器。3. 设计前端用户交互界面前端就是用户看到的“店面”。我们用HTML搭建骨架用CSS美化用JavaScript让它动起来。3.1 构建HTML页面骨架打开templates/index.html文件编写基本的页面结构。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleBERT文本分割演示/title link relstylesheet href{{ url_for(static, filenamestyle.css) }} link relstylesheet hrefhttps://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css /head body div classcontainer header h1i classfas fa-code-branch/i BERT文本分割演示工具/h1 p classsubtitle输入一段长文本体验BERT模型如何智能地将其分割为逻辑段落。/p /header main section classinput-section h2## 1. 输入文本/h2 textarea idinputText placeholder请在这里粘贴或输入您想要分割的长文本...例如一篇技术文章、一段故事或任何连贯的文字。/textarea div classaction-bar button idsegmentBtn classbtn-primary i classfas fa-cut/i 开始分割文本 /button button idclearBtn classbtn-secondary i classfas fa-broom/i 清空 /button span classchar-count字符数: span idcharCount0/span/span /div /section section classoutput-section h2## 2. 分割结果/h2 div classresult-header h3高亮段落展示/h3 div classstats idstats等待处理.../div /div div classresult-container idresultContainer p classplaceholder分割后的段落将在这里显示每个段落会有不同的背景色。/p /div /section /main footer p本演示使用 Flask 后端调用BERT模型API实现。模型分割结果仅供参考。/p /footer /div script src{{ url_for(static, filenamescript.js) }}/script /body /html这个页面结构清晰包含了一个标题区、一个输入区带文本框和按钮、一个输出区用于展示结果和一个页脚。3.2 添加CSS样式美化光有骨架不够我们还需要“装修”。打开static/style.css文件添加一些样式让页面看起来更舒服。/* 基础重置与字体 */ * { margin: 0; padding: 0; box-sizing: border-box; font-family: Segoe UI, Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f5f7fa; color: #333; line-height: 1.6; padding: 20px; min-height: 100vh; } .container { max-width: 1000px; margin: 0 auto; background-color: white; border-radius: 12px; box-shadow: 0 5px 25px rgba(0, 0, 0, 0.08); overflow: hidden; padding: 30px; } /* 标题区域 */ header { text-align: center; margin-bottom: 40px; padding-bottom: 20px; border-bottom: 1px solid #eaeaea; } header h1 { color: #2c3e50; margin-bottom: 10px; font-size: 2.2em; } header .subtitle { color: #7f8c8d; font-size: 1.1em; } /* 主内容区 */ main section { margin-bottom: 40px; } h2 { color: #3498db; margin-bottom: 20px; padding-bottom: 10px; border-bottom: 2px solid #f0f0f0; font-size: 1.5em; } /* 输入区域 */ .input-section textarea { width: 100%; min-height: 200px; padding: 20px; border: 2px solid #ddd; border-radius: 8px; font-size: 16px; resize: vertical; transition: border-color 0.3s; line-height: 1.5; } .input-section textarea:focus { outline: none; border-color: #3498db; } .action-bar { display: flex; align-items: center; gap: 15px; margin-top: 20px; flex-wrap: wrap; } button { padding: 12px 25px; border: none; border-radius: 6px; cursor: pointer; font-size: 16px; font-weight: 600; transition: all 0.2s ease; display: flex; align-items: center; gap: 8px; } .btn-primary { background-color: #3498db; color: white; } .btn-primary:hover { background-color: #2980b9; } .btn-secondary { background-color: #95a5a6; color: white; } .btn-secondary:hover { background-color: #7f8c8d; } .char-count { margin-left: auto; color: #7f8c8d; font-size: 14px; } /* 输出区域 */ .result-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .result-header h3 { color: #2c3e50; } .stats { background-color: #ecf0f1; padding: 8px 15px; border-radius: 20px; font-size: 14px; color: #2c3e50; } .result-container { background-color: #f8f9fa; border-radius: 8px; padding: 25px; min-height: 150px; border: 1px dashed #ddd; } .paragraph { padding: 15px 20px; margin-bottom: 15px; border-radius: 6px; border-left: 4px solid #3498db; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.05); line-height: 1.7; } .placeholder { text-align: center; color: #bdc3c7; font-style: italic; } /* 页脚 */ footer { text-align: center; margin-top: 40px; padding-top: 20px; border-top: 1px solid #eaeaea; color: #95a5a6; font-size: 0.9em; } /* 预定义一组颜色用于循环给段落上色 */ .para-color-0 { border-left-color: #3498db; background-color: #ebf5fb; } .para-color-1 { border-left-color: #2ecc71; background-color: #eafaf1; } .para-color-2 { border-left-color: #e74c3c; background-color: #fdedec; } .para-color-3 { border-left-color: #f39c12; background-color: #fef5e7; } .para-color-4 { border-left-color: #9b59b6; background-color: #f4ecf7; } .para-color-5 { border-left-color: #1abc9c; background-color: #e8f6f3; }3.3 实现JavaScript交互逻辑最后我们让页面“活”起来。创建static/script.js文件编写处理用户交互和与后端通信的代码。document.addEventListener(DOMContentLoaded, function() { // 获取页面元素 const inputTextArea document.getElementById(inputText); const segmentBtn document.getElementById(segmentBtn); const clearBtn document.getElementById(clearBtn); const charCountSpan document.getElementById(charCount); const resultContainer document.getElementById(resultContainer); const statsDiv document.getElementById(stats); // 颜色类名数组用于循环给段落上色 const colorClasses [para-color-0, para-color-1, para-color-2, para-color-3, para-color-4, para-color-5]; // 实时更新字符数 inputTextArea.addEventListener(input, function() { charCountSpan.textContent this.value.length; }); // 清空按钮事件 clearBtn.addEventListener(click, function() { inputTextArea.value ; charCountSpan.textContent 0; resultContainer.innerHTML p classplaceholder分割后的段落将在这里显示每个段落会有不同的背景色。/p; statsDiv.textContent 等待处理...; }); // 分割按钮事件 - 核心交互 segmentBtn.addEventListener(click, async function() { const text inputTextArea.value.trim(); if (!text) { alert(请输入一些文本内容。); return; } // 禁用按钮显示加载状态 const originalBtnText segmentBtn.innerHTML; segmentBtn.innerHTML i classfas fa-spinner fa-spin/i 处理中...; segmentBtn.disabled true; // 清空之前的结果显示加载提示 resultContainer.innerHTML pi classfas fa-spinner fa-spin/i 正在调用模型进行分割请稍候.../p; statsDiv.textContent 处理中...; try { // 发送POST请求到我们的后端API const response await fetch(/segment, { method: POST, headers: { Content-Type: application/json, }, body: JSON.stringify({ text: text }) }); const data await response.json(); // 恢复按钮状态 segmentBtn.innerHTML originalBtnText; segmentBtn.disabled false; if (data.success) { // 更新统计信息 statsDiv.textContent 原文共 ${data.original_length} 字符被分割为 ${data.segment_count} 个段落。; // 清空结果容器并展示新段落 resultContainer.innerHTML ; if (data.paragraphs data.paragraphs.length 0) { data.paragraphs.forEach((paragraph, index) { const paraElement document.createElement(div); paraElement.className paragraph ${colorClasses[index % colorClasses.length]}; // 添加段落编号 const paraHeader document.createElement(div); paraHeader.className para-header; paraHeader.innerHTML strong段落 ${index 1}/strong; // 添加段落内容 const paraContent document.createElement(div); paraContent.className para-content; paraContent.textContent paragraph; paraElement.appendChild(paraHeader); paraElement.appendChild(paraContent); resultContainer.appendChild(paraElement); }); } else { resultContainer.innerHTML p classplaceholder模型返回了空结果请尝试其他文本。/p; } } else { // 处理后端返回的错误 alert(处理失败: ${data.error || 未知错误}); resultContainer.innerHTML p classplaceholder处理过程出现错误。/p; statsDiv.textContent 处理失败; } } catch (error) { // 处理网络或请求错误 console.error(请求出错:, error); alert(网络请求失败请检查后端服务是否正常运行。); // 恢复按钮状态 segmentBtn.innerHTML originalBtnText; segmentBtn.disabled false; resultContainer.innerHTML p classplaceholder请求失败请重试。/p; statsDiv.textContent 请求失败; } }); });这段JavaScript代码负责监听文本输入实时显示字数。处理“清空”按钮的点击事件。处理“开始分割”按钮的点击事件禁用按钮、显示加载状态、通过fetchAPI向后端发送请求、接收JSON响应、动态生成带颜色高亮的段落并更新页面。4. 运行与测试你的应用所有代码都写好了现在让我们把它跑起来看看效果。启动后端服务器打开终端进入你的项目目录bert_segmentation_demo运行以下命令python app.py如果一切正常你会看到类似这样的输出* Serving Flask app app * Debug mode: on * Running on http://127.0.0.1:5000 (Press CTRLC to quit)访问应用打开你的浏览器Chrome, Firefox等在地址栏输入http://127.0.0.1:5000并访问。测试功能在文本框中输入或粘贴一段长文本比如一篇新闻、技术文档或小说片段。点击“开始分割文本”按钮。你会看到按钮变成“处理中...”并且结果区域显示加载提示。稍等片刻取决于你的模型API速度和网络分割后的段落就会以不同颜色背景块的形式展示出来上方还会显示统计信息。你可以尝试点击“清空”按钮重新开始。5. 总结与后续改进思路跟着走完这一趟一个完整的、前后端分离的BERT文本分割演示应用就搭建起来了。整个过程其实并不复杂核心就是Flask接收请求、调用AI API、返回结果然后前端用JavaScript把结果漂亮地展示出来。这种模式非常通用你可以很容易地把这里的文本分割模型换成其他任何模型比如情感分析、文本摘要、翻译等等快速做出新的演示应用。实际用下来这个基础版本跑通肯定没问题但真要拿来演示或者做点小工具还有不少可以打磨的地方。比如可以加个“加载动画”让用户等待时更清楚程序在运行或者让用户能手动调整一下分割的“粒度”再比如把每次分割的结果保存下来甚至加个分享链接的功能。前端样式也可以根据你的喜好调得更精美一些。最重要的是你需要把代码里app.py中call_bert_segmentation_api函数里的API地址和请求格式换成你自己实际使用的模型服务。这才是让整个应用“活”起来的关键一步。动手试试吧把这个架子搭好你就能快速验证各种AI模型在Web端的表现了。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。