python+ollama自己寫(xiě)代碼調(diào)用本地deepseek模型
目的:本地部署ollama后,下載了一堆模型,沒(méi)有合適的界面使用,干脆自己寫(xiě)一個(gè)簡(jiǎn)單的。
1、本地下載并安裝ollama,Ollama。
2、在平臺(tái)上找到deepseek模型,Ollama,選哪個(gè)模型都行,看自己的機(jī)器能不能扛得住,可以先1.5b的試試再玩其他的。
3、本地cmd執(zhí)行模型下載,舉例:ollama pull deepseek-r1:1.5b
4、隨便什么ide編寫(xiě)以下代碼。
目錄結(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 || '無(wú)內(nèi)容'}</div>
<div class="history-time">${new Date(chat.timestamp).toLocaleString()}</div>
</li>
`).join('');
}
// 回車(chē)處理
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; /* 更圓潤(rùn)的邊框 */
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": "無(wú)法連接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庫(kù) (pip install requests)
- Ollama ,至少PULL一個(gè)模型
5、運(yùn)行:python app.py
6、打開(kāi) http://127.0.0.1:5000 開(kāi)始使用。
簡(jiǎn)單實(shí)現(xiàn),界面如下,自己看著改:

到此這篇關(guān)于python+ollama自己寫(xiě)代碼調(diào)用本地deepseek模型的文章就介紹到這了,更多相關(guān)python+ollama調(diào)用本地deepseek模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
理解深度學(xué)習(xí)之深度學(xué)習(xí)簡(jiǎn)介
這篇文章主要是關(guān)于深度學(xué)習(xí)的簡(jiǎn)介,對(duì)大家學(xué)習(xí)了解機(jī)器深度學(xué)習(xí)有一定的幫助,以后會(huì)持續(xù)更新本系列,希望能為大家?guī)?lái)一些收貨,讓我們一起來(lái)看看下面的文章吧2021-04-04
Python實(shí)現(xiàn)讀取.nc數(shù)據(jù)并提取指定時(shí)間與經(jīng)緯度維度對(duì)應(yīng)的變量數(shù)值
這篇文章主要為大家詳細(xì)介紹了如何使用Python語(yǔ)言的netCDF4庫(kù)實(shí)現(xiàn)讀取.nc格式的數(shù)據(jù)文件,并提取指定維(時(shí)間、經(jīng)度與緯度)下的變量數(shù)據(jù),需要的可以了解下2024-02-02
Django中celery執(zhí)行任務(wù)結(jié)果的保存方法
今天小編就為大家分享一篇Django中celery執(zhí)行任務(wù)結(jié)果的保存方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07
python根據(jù)京東商品url獲取產(chǎn)品價(jià)格
閑著沒(méi)事嘗試抓一下京東的數(shù)據(jù),需要使用到的庫(kù)有:BeautifulSoup,urllib2,在Python2下測(cè)試通過(guò)2015-08-08
DataFrame.to_excel多次寫(xiě)入不同Sheet的實(shí)例
今天小編就為大家分享一篇DataFrame.to_excel多次寫(xiě)入不同Sheet的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12
Python2比較當(dāng)前圖片跟圖庫(kù)哪個(gè)圖片相似的方法示例
這篇文章主要介紹了Python2比較當(dāng)前圖片跟圖庫(kù)哪個(gè)圖片相似的方法,結(jié)合實(shí)例形式分析了Python文件目錄操作及圖形運(yùn)算相關(guān)使用技巧,需要的朋友可以參考下2019-09-09
python中字典dict排序sorted的實(shí)現(xiàn)
本文主要介紹了python中字典dict排序sorted的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05

