0%

本地部署deepseek+百度搜索

完成本地部署deepseek、联网搜索,以及页面交互功能

具体分为以下三步:
使用Ollama部署本地deepseek
使用requests和beautifulsoup实现爬取网络检索内容
使用streamlit创建交互界面

Ollama部署本地deepseek

  1. 下载Ollama
    • 建议不要下载到C盘,在CMD窗口输入:OllamaSetup.exe /DIR=你自己的路径
    • 在高级系统设置的环境变量,新建一个环境变量 OLLAMA_MODELS :刚刚ollama的路径/models
    • 在用户变量中新建变量名为OLLAMA_MODELS,变量值为:刚刚ollama的路径/models
    • 然后打开Ollama官网搜索deepseek,选择你想要的模型版本对应的的指令,在cmd中输入然后等待安装即可
      (运行之前要将ollama打开)

requests和beautifulsoup实现爬取网络检索内容

requests发送请求,beautifulsoup解析网页结构,最后保存输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import requests
from bs4 import BeautifulSoup
import time
import os
import random
import json # 新增JSON模块导入

def baidu_search(keyword, page_num=3): # 默认爬取 3 页
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
]

headers = {
"User-Agent": random.choice(user_agents),
"Accept-Language": "zh-CN,zh;q=0.9",
}

results = []
added_links = set() # 用于存储已添加结果的链接

for page in range(page_num):
pn = page * 10 # 计算 pn 参数的值
search_url = f"https://www.baidu.com/s?wd={requests.utils.quote(keyword)}&pn={pn}"
print(search_url)

try:
response = requests.get(search_url, headers=headers, timeout=10)
response.raise_for_status()
print(f"第 {page+1} 页请求成功,状态码:{response.status_code}")
response.encoding = response.apparent_encoding

soup = BeautifulSoup(response.text, 'html.parser')

# 定位搜索结果容器
containers = soup.find_all('div', class_='c-container')

for container in containers:
# 提取标题和链接
title_tag = container.find('h3', class_='t')
if not title_tag or not title_tag.a:
continue

title = title_tag.get_text(strip=True)
link = title_tag.a['href']

# 检查链接是否已存在
if link in added_links:
continue

# 提取摘要(兼容新旧版页面结构)
abstract = ""
abstract_tag = container.find('div', class_='c-abstract') or \
container.find('div', class_='content-right_8Zs40') or \
container.find('span', class_='c-font-normal') or \
container.find('span', class_='content-right_2s-H4') or \
container.find('div', class_='c-span-last') or \
container.find('span', class_='content-right_1THTn') or \
container.find('div', class_='right-link_NlGkt')

if abstract_tag:
abstract = abstract_tag.get_text(strip=True).replace('\n', ' ')

results.append({
'title': title,
#'link': link,
'abstract': abstract if abstract else "暂无摘要信息"
})
added_links.add(link) # 将链接添加到已添加集合中

if len(results) >= 10 * page_num: # 限制结果数量防止触发反爬
break
time.sleep(random.uniform(1, 3)) # 每次请求后延迟 2 秒

except Exception as e:
print(f"第 {page + 1} 页请求异常:{str(e)}")

return results

def save_results_to_file(results, keyword): # 函数名可保留,功能改为保存JSON
filename = os.path.join(os.getcwd(), f"{keyword}_search_results.json") # 改为JSON扩展名

with open(filename, 'w', encoding='utf-8') as f:
# 使用json.dump保存数据,设置ensure_ascii=False保证中文正常显示,indent=2增加可读性
json.dump({
"keyword": keyword,
"total": len(results),
"results": results
}, f, ensure_ascii=False, indent=2)

print(f"√ 搜索结果已保存至 {filename}") # 提示信息同步修改

# 测试功能
if __name__ == "__main__":
keyword = "李白"
search_results = baidu_search(keyword, page_num=10) # 爬取 10 页

if search_results:
print("search success")
save_results_to_file(search_results, keyword)
else:
print("× 搜索结果获取失败,请检查网络或重试")

streamlit创建交互界面

感觉streamlit创建的页面最好看,网上教程很多,我直接把我的放在下面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import streamlit as st
from ollama import chat
from search import baidu_search
import re

# 页面配置
st.set_page_config(
page_title="DeepSeek Chat",
page_icon="🤖",
layout="wide",
)

# 自定义 CSS 美化
st.markdown(
"""
<style>
/* 背景、字体 */
body {
/* 这里可以设置背景渐变色,例如 */
background: linear-gradient(to bottom right, #f7f7f7, #e6e6e6);
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.stApp {
color: #333333;
}
/* 聊天气泡 */
.user-bubble,.assistant-bubble {
padding: 12px 16px;
border-radius: 16px;
margin: 8px 0;
max-width: 70%;
line-height: 1.4;
/* 添加阴影效果 */
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.user-bubble {
background-color: #FFEBE8;
color: #C0392B;
margin-left: auto;
/* 调整用户气泡文字样式 */
font-size: 16px;
font-weight: 500;
}
.assistant-bubble {
background-color: #E8F6FF;
color: #2471A3;
margin-right: auto;
/* 调整助手气泡文字样式 */
font-size: 16px;
font-weight: 500;
}
/* 输入区 */
.stTextInput>div>div>input {
border: 2px solid #F39C12!important;
border-radius: 8px;
}
.stButton>button {
background-color: #F39C12;
color: white;
border-radius: 8px;
}
/* 侧边栏 */
.css-1d391kg {
background-color: #FFF7E6;
}
.sidebar.stText {
font-size: 16px;
}
</style>
""",
unsafe_allow_html=True
)

# 侧边栏
with st.sidebar:
st.title("🎈 设置")
model = st.selectbox(
"选择模型:",
options=["deepseek-r1:1.5b","deepseek-r1:7b"],
help="选择你想使用的模型版本"
)
st.markdown("---")
st.markdown("**说明:** 这是一个可爱的聊天界面,用于与 DeepSeek 进行对话。")

# 主界面标题
st.title("🤗 欢迎来到 DeepSeek 聊天机器人")

# 初始化消息历史
if 'messages' not in st.session_state:
st.session_state.messages = [
{"role": "assistant", "content": "Hello! 我是 DeepSeek 聊天机器人,有什么可以帮您?"}
]

def clean_response(raw_resp):
# 1. 先拿到纯文本
if hasattr(raw_resp, "message") and hasattr(raw_resp.message, "content"):
# Ollama/其他 SDK 风格
text = raw_resp.message.content
elif hasattr(raw_resp, "content"):
# 万一又是 .content
text = raw_resp.content
else:
# 兜底
text = str(raw_resp)

# 2. 去掉 <think>…</think> 块
text = re.sub(r"<think>.*?</think>\s*", "", text, flags=re.S)
# 3. 去掉开头自我介绍段落
text = re.sub(r"^(你好!.*?提供更好的服务!\s*)", "", text, flags=re.S)
return text.strip()

for msg in st.session_state.messages:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])

# 用户输入
if prompt := st.chat_input("有什么需要我帮助的吗?"):
# 1. 展示并存储用户输入
with st.chat_message("user"):
st.markdown(prompt)
st.session_state.messages.append({"role": "user", "content": prompt})

# 2. 在百度上检索
print(prompt)
search_results = baidu_search(prompt, page_num=3)
search_context = "根据检索到的信息:\n"
for idx, item in enumerate(search_results, start=1):
search_context += (
f"{idx}. 标题:{item['标题']}\n"
f" 摘要:{item['摘要']}\n"
)

# 3. 把检索结果作为 system 消息插入到 user prompt 之前
insert_idx = len(st.session_state.messages) - 1
st.session_state.messages.insert(
insert_idx,
{"role": "system", "content": search_context}
)

# 4. 准备防“think”和自我介绍”的 system 指令
system_msg = {
"role": "system",
"content": (
"你是一个直接回答问题的助手:\n"
"- 不要输出任何 `<think>` 标签或内部思考。\n"
"- 不要做自我介绍或额外寒暄。\n"
"只需给出简洁、准确的回答。"
)
}

# 5. 调用大模型,并清洗、展示结果
with st.chat_message("assistant"):
raw_response = chat(
model,
messages=[system_msg] + st.session_state.messages
)
cleaned = clean_response(raw_response)
st.markdown(cleaned)

# 6. 把清洗后的回复存入历史
st.session_state.messages.append({
"role": "assistant",
"content": cleaned
})


欢迎打赏