当前位置: 首页 > wzjs >正文

诸暨市建设局官方网站陕西省水利厅网站建设与管理处

诸暨市建设局官方网站,陕西省水利厅网站建设与管理处,芜湖炎黄做的网站,wordpress 远程代码从零开始部署DeepSeek:基于OllamaFlask的本地化AI对话系统 一、部署背景与工具选型 在AI大模型遍地开花的2025年,DeepSeek R1凭借其出色的推理能力和开源特性成为开发者首选。本文将以零基础视角,通过以下工具链实现本地化部署: …

从零开始部署DeepSeek:基于Ollama+Flask的本地化AI对话系统


一、部署背景与工具选型

在AI大模型遍地开花的2025年,DeepSeek R1凭借其出色的推理能力和开源特性成为开发者首选。本文将以零基础视角,通过以下工具链实现本地化部署:

1.Ollama:轻量级模型管理工具,支持一键拉取、运行模型

Ollama 是一个功能强大的大语言模型管理端,专为下载、运行和调用大型语言模型(如DeepSeek)而设计。它提供了以下几个核心功能:

  • 模型下载:支持从官方仓库下载不同规模的模型。
  • 模型运行:通过API提供服务,让用户与模型进行交互。
  • 实时对话模拟:以流式方式展示模型回复。
2.DeepSeek : 平衡性能与资源消耗的中等规模模型

DeepSeek 是目标语言模型,可以根据您的硬件配置选择不同的模型规模(如7B、13B等)。它具有以下特点:

  • 可扩展性:根据内存和计算资源调整模型大小。
  • 高效训练:支持并行训练以加速模型收敛。
3.Python+Flask:构建Web交互界面,支持流式响应

Flask 是一个轻量级的Web框架,广泛应用于快速开发Web应用。结合Python,它为构建动态Web界面提供了灵活性:

  • API集成:通过Flask API调用Ollama服务。
  • 前端动态:使用JavaScript和HTML创建交互式对话框。
4.HTML+JavaScript:实现类ChatGPT的对话交互体验

HTML 是构建Web界面的基础语言,用于设计用户友好的对话框,并将其嵌入到Flask应用中。您可以通过以下方式集成:

  • 响应式布局:使用CSS样式表确保界面在不同设备上适配。
  • 动态内容展示:通过JavaScript更新页面内容,模拟模型回复,需要模拟打字机方式。

**备注说明**: 不想自己编程的话,可使用chatbox直接接入ollama

二、环境准备与模型部署

1. 安装Ollama

Windows/Mac用户
访问Ollama官网下载安装包,双击完成安装。 (github下载很慢,需要使用加速或从其他地方下载)

Linux用户

curl -fsSL https://ollama.com/install.sh | sh
sudo systemctl start ollama
2. 下载DeepSeek模型

根据硬件配置选择模型(显存要求参考):

  • 基础版(1.5B):适合笔记本(8GB内存)
  • 标准版(7B):推荐配置(16GB内存+8GB显存)
  • 加强版(70B):需专业显卡(如RTX 5090)
# 拉取7B模型
ollama run deepseek-r1:7b

上述指令会完成下载和运行两个步骤(ollama支持断线续传功能,而且我发现速度慢下来的时候,手动停止然后再启动接着下载模型的话,速度会恢复上来),成功运行后可通过命令行直接向deepseek提问,如下:

另外,也可以在命令行手动执行ollama相关指令:

  • 无参数启动
C:\Users\arbboter\Desktop>ollama
Usage:ollama [flags]ollama [command]Available Commands:serve       Start ollamacreate      Create a model from a Modelfileshow        Show information for a modelrun         Run a modelpull        Pull a model from a registrypush        Push a model to a registrylist        List modelsps          List running modelscp          Copy a modelrm          Remove a modelhelp        Help about any commandFlags:-h, --help      help for ollama-v, --version   Show version informationUse "ollama [command] --help" for more information about a command.
命令功能示例
ollama serve启动模型ollama serve
ollama pull下载模型ollama pull deepseek-r1:7b
ollama list查看本地模型ollama list
ollama rm删除模型ollama rm deepseek-r1:1.5b
ollama cp复制模型ollama cp deepseek-r1:7b my-backup

3.配置ollama

# 限制本地访问(默认配置)
export OLLAMA_HOST=127.0.0.1# 允许局域网访问
export OLLAMA_HOST=0.0.0.0# 启用调试
export OLLAMA_DEBUG=1# 自定义模型路径(可能需重启机器生效)
export OLLAMA_MODELS=~\ollama\models

三、构建Web对话系统

备注说明:选型flask及代码编写基本是由deepseek完成,本人只负责提问和修缮
1. 项目结构
deepseek-web/
├── app.py          # Flask主程序
├── templates/
│   └── index.html  # 聊天界面
2. Flask后端实现(app.py)
# app.py
from flask import Flask, render_template, request, Response
import ollama
import logging
from datetime import datetimeapp = Flask(__name__)# 配置日志
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s',handlers=[logging.FileHandler('chat.log'),logging.StreamHandler()]
)def chat_ollama(user_message, stream):host = 'http://192.168.1.10:11434'cli = ollama.Client(host=host)response = cli.chat(model='deepseek-r1:7b',messages=[{'role': 'user', 'content': user_message}],stream=stream,# options={'temperature': 0.7})return response@app.route('/')
def index():return render_template('index.html')@app.route('/api/chat', methods=['POST'])
def chat():"""流式聊天接口"""def generate(user_message):try:app.logger.info(f"流式处理开始: {user_message[:50]}...")stream = chat_ollama(user_message, True)for chunk in stream:content = chunk['message']['content']if content.startswith('<think>'):content = content.replace('<think>', '', 1)elif content.startswith('</think>'):content = content.replace('</think>', '\n', 1)app.logger.debug(f"发送数据块: {content}")yield f"{content}"app.logger.info("流式处理完成")except Exception as e:app.logger.error(f"流式错误: {str(e)}")yield f"[ERROR] {str(e)}\n\n"return Response(generate(request.json['message']), mimetype='text/event-stream')if __name__ == '__main__':app.run(host='0.0.0.0', port=5001, debug=True)
3. 前端实现(index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>AI 对话助手</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css"><script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script><style>:root {--primary-color: #10a37f;--bg-color: #f0f2f5;}body {margin: 0;padding: 20px;font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;background-color: var(--bg-color);max-width: 800px;margin: 0 auto;}#chat-container {height: 70vh;overflow-y: auto;border: 1px solid #e0e0e0;border-radius: 8px;padding: 15px;background: white;margin-bottom: 20px;}.message {margin: 12px 0;display: flex;gap: 15px;}.user-message {justify-content: flex-end;}.message-content {max-width: 80%;padding: 12px 16px;border-radius: 8px;}.assistant-message .message-content {background: #f8f9fa;border: 1px solid #e0e0e0;}.user-message .message-content {background: var(--primary-color);color: white;}#input-container {display: flex;gap: 10px;}#user-input {flex: 1;padding: 12px;border: 1px solid #e0e0e0;border-radius: 8px;resize: none;min-height: 44px;}button {background: var(--primary-color);color: white;border: none;padding: 0 20px;border-radius: 8px;cursor: pointer;transition: opacity 0.2s;}button:disabled {opacity: 0.6;cursor: not-allowed;}.typing-indicator {display: inline-block;padding: 8px 12px;background: #f8f9fa;border-radius: 8px;border: 1px solid #e0e0e0;}.dot {display: inline-block;width: 6px;height: 6px;margin-right: 3px;background: #ccc;border-radius: 50%;animation: bounce 1.4s infinite;}@keyframes bounce {0%, 80%, 100% { transform: translateY(0) }40% { transform: translateY(-6px) }}/* markdown基础样式 */.markdown-content {line-height: 1.6;transition: opacity 0.3s;}.markdown-content:not(.markdown-rendered) {opacity: 0.5;}.markdown-content h1 { font-size: 2em; margin: 0.67em 0; }.markdown-content h2 { font-size: 1.5em; margin: 0.83em 0; }.markdown-content pre { background: #f5f5f5;padding: 1em;border-radius: 4px;overflow-x: auto;}</style>
</head>
<body><div id="chat-container"></div><div id="input-container"><textarea id="user-input" placeholder="输入消息..." rows="1"></textarea><button id="send-btn" onclick="sendMessage()">发送</button></div><script>const chatContainer = document.getElementById('chat-container');const userInput = document.getElementById('user-input');const sendBtn = document.getElementById('send-btn');// 滚动到底部function scrollToBottom() {}function renderMarkdown(options = {}) {// 合并配置参数const config = {selector: options.selector || '.markdown-content',breaks: options.breaks ?? true,gfm: options.gfm ?? true,highlight: options.highlight || null};// 配置Markedmarked.setOptions({breaks: config.breaks,gfm: config.gfm,highlight: config.highlight});// 渲染处理器const render = () => {document.querySelectorAll(config.selector).forEach(container => {if (container.dataset.rendered) return;// 创建虚拟容器避免内容闪烁const virtualDiv = document.createElement('div');virtualDiv.style.display = 'none';virtualDiv.innerHTML = container.innerHTML.trim();// 执行Markdown转换container.innerHTML = marked.parse(virtualDiv.innerHTML);container.dataset.rendered = true;// 添加加载动画container.classList.add('markdown-rendered');});};// 自动执行渲染if (document.readyState === 'complete') {render();} else {document.addEventListener('DOMContentLoaded', render);}}// 添加用户消息function addUserMessage(content) {const messageDiv = document.createElement('div');messageDiv.className = 'message user-message';messageDiv.innerHTML = `<div class="message-content">${content}</div>`;chatContainer.appendChild(messageDiv);}// 添加AI消息(流式)async function addAssistantMessageStream() {const messageDiv = document.createElement('div');messageDiv.className = 'message assistant-message';messageDiv.innerHTML = `<div class="message-content markdown-content"><div class="typing-indicator"><span class="dot"></span><span class="dot" style="animation-delay: 0.2s"></span><span class="dot" style="animation-delay: 0.4s"></span></div></div>`;chatContainer.appendChild(messageDiv);return messageDiv.querySelector('.message-content');}// 发送消息async function sendMessage() {const content = userInput.value.trim();if (!content) return;sendBtn.disabled = true;userInput.disabled = true;userInput.value = '';addUserMessage(content);const responseContainer = await addAssistantMessageStream();try {const response = await fetch('/api/chat', {method: 'POST',headers: {'Content-Type': 'application/json',// 如果需要认证// 'Authorization': 'Bearer YOUR_TOKEN'},body: JSON.stringify({ message: content })});if (!response.ok) throw new Error('请求失败');await this.createStreamTypewriter(response, responseContainer, {});this.scrollToBottom();} catch (error) {responseContainer.innerHTML = '❌ 请求出错: ' + error.message;} finally {sendBtn.disabled = false;userInput.disabled = false;userInput.focus();}}// 输入框事件处理userInput.addEventListener('keydown', (e) => {if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey) {e.preventDefault();sendMessage();} else if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {userInput.value += '\n';}});async function createStreamTypewriter(stream, container, options = {}) {const config = {baseSpeed: 50,maxSpeedup: 3,retryCount: 3,...options};this.reader = null;// 状态控制let isDestroyed = false;let cursorVisible = true;let renderQueue = [];let retryCounter = 0;// DOM元素初始化const cursor = document.createElement('span');cursor.className = 'typewriter-cursor';cursor.textContent = '▌';container.append(cursor);// 光标动画const cursorInterval = setInterval(() => {cursor.style.opacity = cursorVisible ? 1 : 0;cursorVisible = !cursorVisible;}, 600);// 核心渲染逻辑const renderEngine = () => {if (renderQueue.length === 0 || isDestroyed) return;// 动态调速算法const speed = Math.max(config.baseSpeed / config.maxSpeedup,config.baseSpeed - renderQueue.length * 2);const fragment = document.createDocumentFragment();while (renderQueue.length > 0) {const char = renderQueue.shift();fragment.append(document.createTextNode(char));}container.insertBefore(fragment, cursor);setTimeout(() => requestAnimationFrame(renderEngine), speed);};// 流数据处理const processStream = async () => {try {this.reader = stream.body.getReader();// Fetch模式处理while (!isDestroyed) {const { done, value } = await this.reader.read();if (done) break;renderQueue.push(...new TextDecoder().decode(value).split(''));if (!renderQueue.length) continue;requestAnimationFrame(renderEngine);}} catch (err) {if (retryCounter++ < config.retryCount && !isDestroyed) {processStream();} else {destroy();throw new Error('Stream connection failed');}} finally {container.innerHTML = marked.parse(container.textContent.replace('▌', ''));destroy();}};// 资源清理const destroy = () => {if (isDestroyed) return;isDestroyed = true;clearInterval(cursorInterval);cursor.remove();if (stream.cancel) stream.cancel();if (stream.close) stream.close();};// 启动引擎processStream();return { destroy };};</script>
</body>
</html>

四、启动与优化

1. 运行系统
flask run --port 5001

访问 http://localhost:5001 即可开始对话 ,如下:
主页面

2. 性能优化技巧
  • 量化加速:使用ollama run deepseek-r1:7b --quantize q4_0 减少显存占用
  • GPU加速:在Ollama配置中启用CUDA支持

五、安全注意事项

  1. 端口防护
export OLLAMA_HOST=127.0.0.1  # 禁止外部访问
netstat -an | grep 11434      # 验证监听地址
  1. 防火墙规则
sudo ufw deny 11434/tcp      # 禁用Ollama外部端口

六、扩展应用场景

  1. 私有知识库:接入LangChain处理本地文档
  2. 自动化脚本:通过API实现代码生成/自动Debug
  3. 硬件控制:结合HomeAssistant实现语音智能家居

完整代码已开源(其实没有):GitHub仓库地址
通过本教程,您已掌握从模型部署到应用开发的全流程。本地化AI部署不仅降低成本,更保障了数据隐私,为开发者提供了真正的「AI自由」!


文章转载自:

http://d7zsZvn4.dhchL.cn
http://kB3mDhSO.dhchL.cn
http://vsgv35hy.dhchL.cn
http://Cio8YWG6.dhchL.cn
http://6VCOjeSp.dhchL.cn
http://FvrM0ncY.dhchL.cn
http://wkfOiBFh.dhchL.cn
http://6R8kM8yT.dhchL.cn
http://lCUrUZVE.dhchL.cn
http://5RWbd3ny.dhchL.cn
http://Dcsco6eg.dhchL.cn
http://u9DGmehr.dhchL.cn
http://9oxqba89.dhchL.cn
http://ClJZCDoj.dhchL.cn
http://OVDXKdSU.dhchL.cn
http://tIFdRPf6.dhchL.cn
http://YCUngYnj.dhchL.cn
http://RPY1R8N9.dhchL.cn
http://E3X5nFRV.dhchL.cn
http://m0JHbIIa.dhchL.cn
http://2N31dpRL.dhchL.cn
http://5NT0szu6.dhchL.cn
http://nsjmnUp7.dhchL.cn
http://MeexYCtC.dhchL.cn
http://shHFMfok.dhchL.cn
http://UDFxXhZl.dhchL.cn
http://EFpPPh1q.dhchL.cn
http://xsMf3FrL.dhchL.cn
http://7rqkq4Iw.dhchL.cn
http://KA2f63p8.dhchL.cn
http://www.dtcms.com/wzjs/652395.html

相关文章:

  • drupal网站建设网址查询网站
  • 公司网站开发报价网页端二维码在哪里
  • 香河住房和建设局网站网址转换二维码
  • 运营最好的网站哈尔滨网站制作招聘
  • 有没有做淘宝首页特效的网站聊天系统源码
  • 荆州 网站建设宁波外贸seo网站建设
  • 网站建设发专业人才培养方案手机版网站如何制作
  • 哪些网站用echarts做的国外贸易网站
  • wordpress显示一个类目长沙优化网站技术厂家
  • 重庆做网站最好的网站怎么上传到空间
  • 做网站基础教程推广网站的方式
  • 成都便宜做网站的前端学什么
  • 公司注册网站方法移动端app是什么意思
  • 艺术培训网站模板wordpress彩色美化
  • 深圳住房建设部网站建设网站增城
  • 西安网站建设缑阳建与做网站的人怎么谈判
  • 重庆荣昌网站建设公司wordpress koncept 下载
  • 网站建设怎么选择MySQL数据库大小京伦科技做的网站如何
  • 旅游网站策划书河南网站建设设计
  • 如何利用php开源系统建立php网站重庆网站seo搜索引擎优化
  • 城市建设模拟游戏官方网站男人和女人做羞羞的免费网站
  • 网站上传图片尺寸最新获取网站访客qq接口
  • 电子商务网站建设成都网络营销师培训课程
  • 城乡建设举报网站重庆网站自己推广
  • 织梦网站动态网站搜索框用ps怎么做
  • pop布局的网站123邢台招聘信息网
  • 网站建设国外拂去其网站鼠标移上去显示层
  • 给企业做网站 内容需要对方提供喀什百度做网站多少钱
  • 定安免费建站公司北京工程建设监理协会网站
  • 做网站公司 郑州自媒体app推广是做什么的