python+ollama自己写代码调用本地deepseek模型

 更新时间:2025年03月21日 10:00:45   作者:杨正同学  
本文主要介绍了python+ollama自己写代码调用本地deepseek模型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

目的:本地部署ollama后,下载了一堆模型,没有合适的界面使用,干脆自己写一个简单的。

1、本地下载并安装ollama,Ollama

2、在平台上找到deepseek模型,Ollama,选哪个模型都行,看自己的机器能不能扛得住,可以先1.5b的试试再玩其他的。

3、本地cmd执行模型下载,举例:ollama pull deepseek-r1:1.5b

4、随便什么ide编写以下代码。

目录结构:

index.html:

<!DOCTYPE html>
<html>
<head>
    <title>本地模型聊天</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="external nofollow" >
    <link rel="stylesheet" href="/static/style.css" rel="external nofollow" >
</head>
<body>
    <div class="container">
        <div class="sidebar">
            <div class="history-header">
                <h3>聊天话题</h3>
                <div>
                    <button onclick="createNewChat()" title="新话题"><i class="fas fa-plus"></i></button>
                    <button onclick="clearHistory()" title="清空记录"><i class="fas fa-trash"></i></button>
                </div>
            </div>
            <ul id="historyList"></ul>
            <div class="model-select">
                <select id="modelSelect">
                    <option value="">选择模型...</option>
                </select>
            </div>
        </div>
        <div class="chat-container">
            <div id="chatHistory" class="chat-history"></div>
            <div class="input-area">
                <input type="text" id="messageInput" placeholder="输入消息 (Enter发送,Shift+Enter换行)" 
                       onkeydown="handleKeyPress(event)">
                <button onclick="sendMessage()"><i class="fas fa-paper-plane"></i></button>
            </div>
        </div>
    </div>

    <script>
        // 新增历史记录功能
        let currentChatId = null;
        
        // 初始化时加载历史记录
        window.onload = async () => {
            loadHistory();
            const response = await fetch('/get_models');
            const models = await response.json();
            const select = document.getElementById('modelSelect');
            models.forEach(model => {
                const option = document.createElement('option');
                option.value = model;
                option.textContent = model;
                select.appendChild(option);
            });
        };

        // 保存聊天记录
        function saveToHistory(chatData) {
            const history = JSON.parse(localStorage.getItem('chatHistory') || '[]');
            const existingIndex = history.findIndex(item => item.id === chatData.id);
            
            if (existingIndex > -1) {
                // 更新现有记录
                history[existingIndex] = chatData;
            } else {
                // 添加新记录
                history.unshift(chatData);
            }
            
            localStorage.setItem('chatHistory', JSON.stringify(history));
            loadHistory();
        }

        // 加载历史记录
        function loadHistory() {
            const history = JSON.parse(localStorage.getItem('chatHistory') || '[]');
            const list = document.getElementById('historyList');
            
            list.innerHTML = history.map(chat => `
                <li class="history-item" onclick="loadChat('${chat.id}')">
                    <div class="history-header">
                        <div class="history-model">${chat.model || '未指定模型'}</div>
                        <button class="delete-btn" onclick="deleteChat('${chat.id}', event)">
                            <i class="fas fa-times"></i>
                        </button>
                    </div>
                    <div class="history-preview">${chat.messages.slice(-1)[0]?.content || '无内容'}</div>
                    <div class="history-time">${new Date(chat.timestamp).toLocaleString()}</div>
                </li>
            `).join('');
        }

        // 回车处理
        function handleKeyPress(e) {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                sendMessage();
            }
        }

        // 处理消息发送
        async function sendMessage() {
            const input = document.getElementById('messageInput');
            const message = input.value;
            const model = document.getElementById('modelSelect').value;
            
            if (!message || !model) return;

            const chatHistory = document.getElementById('chatHistory');
            
            // 添加用户消息(带图标)
            chatHistory.innerHTML += `
                <div class="message user-message">
                    <div class="avatar"><i class="fas fa-user"></i></div>
                    <div class="content">${message}</div>
                </div>
            `;

            // 创建AI消息容器(带图标)
            const aiMessageDiv = document.createElement('div');
            aiMessageDiv.className = 'message ai-message';
            aiMessageDiv.innerHTML = `
                <div class="avatar"><i class="fas fa-robot"></i></div>
                <div class="content"></div>
            `;
            chatHistory.appendChild(aiMessageDiv);

            // 清空输入框
            input.value = '';
            
            // 滚动到底部
            chatHistory.scrollTop = chatHistory.scrollHeight;

            // 发起请求
            const response = await fetch('/chat', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    model: model,
                    messages: [{content: message}]
                })
            });

            const reader = response.body.getReader();
            const decoder = new TextDecoder();
            
            let responseText = '';

            while(true) {
                const { done, value } = await reader.read();
                if (done) break;
                const chunk = decoder.decode(value);
                const lines = chunk.split('\n');
                
                lines.forEach(line => {
                    if (line.startsWith('data: ')) {
                        try {
                            const data = JSON.parse(line.slice(6));
                            responseText += data.response;
                            aiMessageDiv.querySelector('.content').textContent = responseText;
                            chatHistory.scrollTop = chatHistory.scrollHeight;
                        } catch(e) {
                            console.error('解析错误:', e);
                        }
                    }
                });
            }

            // 初始化或更新聊天记录
            if (!currentChatId) {
                currentChatId = Date.now().toString();
            }
            
            // 保存到历史记录
            const chatData = {
                id: currentChatId,
                model: model,
                timestamp: Date.now(),
                messages: [...existingMessages, 
                          {role: 'user', content: message},
                          {role: 'assistant', content: responseText}]
            };
            
            saveToHistory(chatData);
        }

        function createNewChat() {
            currentChatId = Date.now().toString();
            document.getElementById('chatHistory').innerHTML = '';
            document.getElementById('messageInput').value = '';
        }

        function deleteChat(chatId, event) {
            event.stopPropagation();
            const history = JSON.parse(localStorage.getItem('chatHistory') || '[]');
            const newHistory = history.filter(item => item.id !== chatId);
            localStorage.setItem('chatHistory', JSON.stringify(newHistory));
            loadHistory();
            
            if (chatId === currentChatId) {
                createNewChat();
            }
        }
    </script>
</body>
</html> 

style.css:

body {
    margin: 0;
    font-family: Arial, sans-serif;
    background: #f0f0f0;
}

.container {
    display: flex;
    height: 100vh;
}

.sidebar {
    width: 250px;
    background: #2c3e50;
    padding: 20px;
    color: white;
}

.chat-container {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.chat-history {
    flex: 1;
    padding: 20px;
    overflow-y: auto;
    background: white;
}

.message {
    display: flex;
    align-items: start;
    gap: 10px;
    padding: 12px;
    margin: 10px 0;
}

.user-message {
    flex-direction: row-reverse;
}

.message .avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    flex-shrink: 0;
}

.user-message .avatar {
    background: #3498db;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ai-message .avatar {
    background: #2ecc71;
    display: flex;
    align-items: center;
    justify-content: center;
}

.message .content {
    max-width: calc(100% - 50px);
    padding: 10px 15px;
    border-radius: 15px;
    white-space: pre-wrap;
    word-break: break-word;
    line-height: 1.5;
}

.input-area {
    display: flex;
    gap: 10px;
    padding: 15px;
    background: white;
    box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
}

input[type="text"] {
    flex: 1;
    min-width: 300px;  /* 最小宽度 */
    padding: 12px 15px;
    border: 1px solid #ddd;
    border-radius: 25px;  /* 更圆润的边框 */
    margin-right: 0;
    font-size: 16px;
}

button {
    padding: 10px 20px;
    background: #007bff;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

button:hover {
    background: #0056b3;
}

/* 新增历史记录样式 */
.history-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
}

.history-item {
    padding: 12px;
    border-bottom: 1px solid #34495e;
    cursor: pointer;
    transition: background 0.3s;
}

.history-item:hover {
    background: #34495e;
}

.history-preview {
    color: #bdc3c7;
    font-size: 0.9em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.history-time {
    color: #7f8c8d;
    font-size: 0.8em;
    margin-top: 5px;
}

/* 新增代码块样式 */
.message .content pre {
    background: rgba(0,0,0,0.05);
    padding: 10px;
    border-radius: 5px;
    overflow-x: auto;
    white-space: pre-wrap;
}

.message .content code {
    font-family: 'Courier New', monospace;
    font-size: 0.9em;
}

/* 历史记录删除按钮 */
.delete-btn {
    background: none;
    border: none;
    color: #e74c3c;
    padding: 2px 5px;
    cursor: pointer;
}

.delete-btn:hover {
    color: #c0392b;
} 

app.py:

from flask import Flask, render_template, request, jsonify, Response
import requests
import subprocess
import time

app = Flask(__name__)
OLLAMA_HOST = "http://localhost:11434"

def start_ollama():
    try:
        # 尝试启动Ollama服务
        subprocess.Popen(["ollama", "serve"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        time.sleep(2)  # 等待服务启动
    except Exception as e:
        print(f"启动Ollama时出错: {e}")

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/get_models')
def get_models():
    try:
        response = requests.get(f"{OLLAMA_HOST}/api/tags")
        models = [model['name'] for model in response.json()['models']]
        return jsonify(models)
    except requests.ConnectionError:
        return jsonify({"error": "无法连接Ollama服务,请确保已安装并运行Ollama"}), 500

@app.route('/chat', methods=['POST'])
def chat():
    data = request.json
    model = data['model']
    messages = data['messages']
    
    def generate():
        try:
            response = requests.post(
                f"{OLLAMA_HOST}/api/generate",
                json={
                    "model": model,
                    "prompt": messages[-1]['content'],
                    "stream": True
                },
                stream=True
            )
            for line in response.iter_lines():
                if line:
                    yield f"data: {line.decode()}\n\n"
        except Exception as e:
            yield f"data: {str(e)}\n\n"
    
    return Response(generate(), mimetype='text/event-stream')

if __name__ == '__main__':
    start_ollama()
    app.run(debug=True, port=5000) 

运行环境:

  • Python 3.7+
  • Flask (pip install flask)
  • requests库 (pip install requests)
  • Ollama ,至少PULL一个模型

5、运行:python app.py

6、打开 http://127.0.0.1:5000 开始使用。

简单实现,界面如下,自己看着改:

到此这篇关于python+ollama自己写代码调用本地deepseek模型的文章就介绍到这了,更多相关python+ollama调用本地deepseek模型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 理解深度学习之深度学习简介

    理解深度学习之深度学习简介

    这篇文章主要是关于深度学习的简介,对大家学习了解机器深度学习有一定的帮助,以后会持续更新本系列,希望能为大家带来一些收货,让我们一起来看看下面的文章吧
    2021-04-04
  • Python实现读取.nc数据并提取指定时间与经纬度维度对应的变量数值

    Python实现读取.nc数据并提取指定时间与经纬度维度对应的变量数值

    这篇文章主要为大家详细介绍了如何使用Python语言的netCDF4库实现读取.nc格式的数据文件,并提取指定维(时间、经度与纬度)下的变量数据,需要的可以了解下
    2024-02-02
  • Django中celery执行任务结果的保存方法

    Django中celery执行任务结果的保存方法

    今天小编就为大家分享一篇Django中celery执行任务结果的保存方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • Python边遍历边删除列表元素的几种方法

    Python边遍历边删除列表元素的几种方法

    在 Python 中,边遍历边删除列表元素通常是一个不推荐的操作,因为它会改变列表的大小,可能会导致一些意料之外的行为,例如,元素被删除后,列表的索引会发生变化,可能导致漏掉某些元素或者遍历到错误的位置,所以本文介绍了Python边遍历边删除列表元素的几种方法
    2024-12-12
  • python根据京东商品url获取产品价格

    python根据京东商品url获取产品价格

    闲着没事尝试抓一下京东的数据,需要使用到的库有:BeautifulSoup,urllib2,在Python2下测试通过
    2015-08-08
  • DataFrame.to_excel多次写入不同Sheet的实例

    DataFrame.to_excel多次写入不同Sheet的实例

    今天小编就为大家分享一篇DataFrame.to_excel多次写入不同Sheet的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-12-12
  • Python2比较当前图片跟图库哪个图片相似的方法示例

    Python2比较当前图片跟图库哪个图片相似的方法示例

    这篇文章主要介绍了Python2比较当前图片跟图库哪个图片相似的方法,结合实例形式分析了Python文件目录操作及图形运算相关使用技巧,需要的朋友可以参考下
    2019-09-09
  • Python绘制组合图的示例

    Python绘制组合图的示例

    这篇文章主要介绍了Python如何绘制组合图,帮助大家更好的利用python绘制图像,进行数据可视化分析,感兴趣的朋友可以了解下
    2020-09-09
  • python中字典dict排序sorted的实现

    python中字典dict排序sorted的实现

    本文主要介绍了python中字典dict排序sorted的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Python多进程机制实例详解

    Python多进程机制实例详解

    这篇文章主要介绍了Python多进程机制,以实例形式详细分析了Python多进程机制的原理与实现技巧,需要的朋友可以参考下
    2015-07-07

最新评论