python+ollama自己寫代碼調(diào)用本地deepseek模型
目的:本地部署ollama后,下載了一堆模型,沒有合適的界面使用,干脆自己寫一個(gè)簡單的。
1、本地下載并安裝ollama,Ollama。
2、在平臺(tái)上找到deepseek模型,Ollama,選哪個(gè)模型都行,看自己的機(jī)器能不能扛得住,可以先1.5b的試試再玩其他的。
3、本地cmd執(zhí)行模型下載,舉例:ollama pull deepseek-r1:1.5b
4、隨便什么ide編寫以下代碼。
目錄結(jié)構(gòu):
index.html:
<!DOCTYPE html> <html> <head> <title>本地模型聊天</title> <link rel="stylesheet" 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發(fā)送,Shift+Enter換行)" onkeydown="handleKeyPress(event)"> <button onclick="sendMessage()"><i class="fas fa-paper-plane"></i></button> </div> </div> </div> <script> // 新增歷史記錄功能 let currentChatId = null; // 初始化時(shí)加載歷史記錄 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) { // 更新現(xiàn)有記錄 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 || '無內(nèi)容'}</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(); } } // 處理消息發(fā)送 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'); // 添加用戶消息(帶圖標(biāo)) chatHistory.innerHTML += ` <div class="message user-message"> <div class="avatar"><i class="fas fa-user"></i></div> <div class="content">${message}</div> </div> `; // 創(chuàng)建AI消息容器(帶圖標(biāo)) 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 = ''; // 滾動(dòng)到底部 chatHistory.scrollTop = chatHistory.scrollHeight; // 發(fā)起請(qǐng)求 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('解析錯(cuò)誤:', 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: # 嘗試啟動(dòng)Ollama服務(wù) subprocess.Popen(["ollama", "serve"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) time.sleep(2) # 等待服務(wù)啟動(dòng) except Exception as e: print(f"啟動(dòng)Ollama時(shí)出錯(cuò): {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服務(wù),請(qǐng)確保已安裝并運(yùn)行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)
運(yùn)行環(huán)境:
- Python 3.7+
- Flask (pip install flask)
- requests庫 (pip install requests)
- Ollama ,至少PULL一個(gè)模型
5、運(yùn)行:python app.py
6、打開 http://127.0.0.1:5000 開始使用。
簡單實(shí)現(xiàn),界面如下,自己看著改:
到此這篇關(guān)于python+ollama自己寫代碼調(diào)用本地deepseek模型的文章就介紹到這了,更多相關(guān)python+ollama調(diào)用本地deepseek模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
理解深度學(xué)習(xí)之深度學(xué)習(xí)簡介
這篇文章主要是關(guān)于深度學(xué)習(xí)的簡介,對(duì)大家學(xué)習(xí)了解機(jī)器深度學(xué)習(xí)有一定的幫助,以后會(huì)持續(xù)更新本系列,希望能為大家?guī)硪恍┦肇?,讓我們一起來看看下面的文章?/div> 2021-04-04Python實(shí)現(xiàn)讀取.nc數(shù)據(jù)并提取指定時(shí)間與經(jīng)緯度維度對(duì)應(yīng)的變量數(shù)值
這篇文章主要為大家詳細(xì)介紹了如何使用Python語言的netCDF4庫實(shí)現(xiàn)讀取.nc格式的數(shù)據(jù)文件,并提取指定維(時(shí)間、經(jīng)度與緯度)下的變量數(shù)據(jù),需要的可以了解下2024-02-02Django中celery執(zhí)行任務(wù)結(jié)果的保存方法
今天小編就為大家分享一篇Django中celery執(zhí)行任務(wù)結(jié)果的保存方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07python根據(jù)京東商品url獲取產(chǎn)品價(jià)格
閑著沒事嘗試抓一下京東的數(shù)據(jù),需要使用到的庫有:BeautifulSoup,urllib2,在Python2下測試通過2015-08-08DataFrame.to_excel多次寫入不同Sheet的實(shí)例
今天小編就為大家分享一篇DataFrame.to_excel多次寫入不同Sheet的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-12-12Python2比較當(dāng)前圖片跟圖庫哪個(gè)圖片相似的方法示例
這篇文章主要介紹了Python2比較當(dāng)前圖片跟圖庫哪個(gè)圖片相似的方法,結(jié)合實(shí)例形式分析了Python文件目錄操作及圖形運(yùn)算相關(guān)使用技巧,需要的朋友可以參考下2019-09-09python中字典dict排序sorted的實(shí)現(xiàn)
本文主要介紹了python中字典dict排序sorted的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05最新評(píng)論