本文圖文並茂,記錄安裝 Ollama過程,下載大模型,啓動ollama大模型服務,然後通過nginx代理外部請求訪問,實現一個前端問答效果
準備工作
- 一台服務器,操作系統 Ubuntu,版本大於等於 20.04,筆者的是 Ubuntu 22.04 64 bit
- 當然了 有域名最好
- 一個圖形可視化化鏈接服務器軟件,筆者推薦 winscp
- 一架梯子,筆者用的是,clash小貓
效果圖
效果演示地址
請點擊一下:https://ashuai.site/reactExamples/ollama
第一步,試試ollama官方提供的命令
ollama官方:https://ollama.com/download/linux
第二步,網絡不行,ollama下載不下來
文件太大了,有一個G多
第三步,到github上找對應ollama安裝包資源,下載,再上傳到烏班圖服務器上
地址如下:https://github.com/ollama/ollama/releases/tag/v0.12.0
然後,在瀏覽器中下載
下載完畢以後,在用winscp將其移動到服務器上
ollama安裝包上傳完畢
第四步,解壓對應的這個文件
1. 解壓 .tgz 壓縮包並統一路徑管理
當前我們是已在 /var/selfDownload 目錄(通過 ls 能看到 ollama-linux-amd64.tgz),直接執行解壓命令即可。.tgz 是 .tar.gz 的簡寫,需用 tar 命令解壓:
tar -zxvf ollama-linux-amd64.tgz
-
命令説明:
z:處理 gzip 壓縮格式(對應.gz/.tgz);x:執行 “解壓” 操作;v:顯示解壓過程(可選,方便查看文件是否正常解壓);f:指定要解壓的文件名(必須放在命令最後,這裏是ollama-linux-amd64.tgz)。
解壓成功 得到兩個新的文件夾
在winscp中也能直觀看到
把對應的文件移動走到對應位置,統一管理,注意下圖的路徑
然後跑起來服務
2. 安裝大模型,使用curl命令進行對話
ollama服務 默認運行的端口是11434端口
然後,使用curl命令,在服務器內部的命令行中,發送給ollama發請求,調用通義千文大模型試試
curl http://localhost:11434/api/generate -d '{
"model": "qwen2.5:0.5b",
"prompt": "你是什麼模型",
"stream": false
}'
- 我們發現跑通了,至此,烏班圖服務器上,安裝Ollama就全部完成了
- 但是,單單隻有Ollama的上安裝的模型服務還不太夠,效果不明顯
- 接下,我們要讓服務器上的大模型服務能夠在外部調用
3. nginx代理外部請求到ollama
- 筆者服務器上安裝nginx,以便於代理外部的請求,而後把外部請求轉發到服務器上的ollama的大模型服務
- 以/ollama開頭的請求,轉到ollama這裏使用11434端口上
# ollama服務
location /ollama/ {
# 允許所有來源訪問
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Max-Age' 1728000 always;
# 代理到 Ollama
proxy_pass http://localhost:11434/;
# 完全清理所有頭,只保留必要的
proxy_pass_request_headers off;
# 手動設置最基本的頭信息 ollama的響應頭過於複雜可能導致403報錯
proxy_set_header Host localhost;
proxy_set_header Content-Type application/json;
proxy_set_header Content-Length $content_length;
proxy_set_header Connection close;
}
第五步,在外部訪問請求服務器上的ollama大模型接口
寫一個react頁面,直接發請求即可
效果圖
交互效果
接口請求返回
react代碼
即分為對話區和輸入區,前端代碼倒是很簡單
import { useState } from 'react'
import axios from 'axios'
import { Input } from 'antd'
import styles from './Ollama.module.css'
export default function Ollama() {
const [messages, setMessages] = useState([]) // 存儲對話數據
const [inputValue, setInputValue] = useState('') // 輸入框內容
const [isLoading, setIsLoading] = useState(false) // 加載狀態
// 發請求
const sendApiRequest = () => {
if (!inputValue.trim()) return // 如果輸入為空,不發送請求
const userMessage = inputValue.trim()
setIsLoading(true)
// 添加用户消息到對話數據
setMessages(prev => [...prev, { type: 'user', content: userMessage }])
setInputValue('') // 清空輸入框
axios.post('/ollama/api/generate', {
model: "qwen2.5:0.5b",
prompt: userMessage,
stream: false
}).then((response) => {
const { response: aiResponse } = response.data
// 添加AI回覆到對話數據
setMessages(prev => [...prev, { type: 'ai', content: aiResponse }])
setIsLoading(false)
}).catch((error) => {
setMessages(prev => [...prev, { type: 'error', content: JSON.stringify(error) }])
setIsLoading(false)
})
}
// 處理輸入框按鍵事件
const handleKeyPress = (e) => {
if (e.key === 'Enter' && !isLoading) {
sendApiRequest()
}
}
return (
<div>
<h3>Ollama調用大模型</h3>
{/* 對話區 */}
<div className={styles.chatContainer}>
<div className={styles.messages}>
{messages.length === 0 ? (
<div className={styles.emptyMessage}>
暫無數據,請開始與AI對話吧!🤔🤔🤔
</div>
) : (
messages.map((message, index) => (
<div
key={index}
className={`${styles.message} ${styles[message.type]}`}
>
<div className={styles.messageContent}>
{message.content}
</div>
</div>
))
)}
</div>
</div>
{/* 輸入區 */}
<Input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onPressEnter={handleKeyPress}
placeholder="輸入問題,回車發送"
disabled={isLoading}
/>
</div>
)
}
樣式css代碼
.chatContainer {
border: 1px solid #dee2e6;
border-radius: 8px;
height: 400px;
margin-bottom: 20px;
overflow-y: auto;
background-color: #fafafa;
}
.messages {
padding: 15px;
}
.message {
margin-bottom: 15px;
display: flex;
}
/* 用户輸入的在右側,ai回覆的在左側,報錯居中 */
.user { justify-content: flex-end; }
.ai { justify-content: flex-start; }
.error { justify-content: center; }
.messageContent {
max-width: 70%;
padding: 10px 15px;
word-wrap: break-word;
}
.user .messageContent {
background-color: #1890ff;
color: white;
border-radius: 18px 18px 4px 18px;
}
.ai .messageContent {
background-color: #f0f0f0;
color: #333;
border-radius: 18px 18px 18px 4px;
}
.error .messageContent {
background-color: #fff2f0;
color: #ff4d4f;
border: 1px solid #ffccc7;
border-radius: 8px;
}
.emptyMessage {
text-align: center;
color: #999;
font-style: italic;
padding: 40px;
}
完整github代碼地址
請點擊 https://github.com/shuirongshuifu/react-examples
創造不易,感謝關注、點贊、評論支持 🙏🙏🙏
A good memory is better than a bad pen. Record it down...