网站首页 > 文章精选 正文
这个AI编程全自动网站建设与应用开发平台确实牛逼https://bolt.new/
文章作者使用这个平台《https://bolt.new/》来包装自己的手机聊天桌面非常方便,把代码给AI让包装成手机应用2分钟就能做好APP。
以下是文章作者开发的手机桌面聊天应用APP、请扫码使用。
手机应用桌面开源代码↓
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DeepSeek</title>
<!-- 引入 Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;700&display=swap" rel="stylesheet">
<!-- MathJax 配置与脚本 -->
<script>
window.MathJax = {
tex: {
inlineMath: [['#39;, '#39;], ['\#39;, '\#39;]],
displayMath: [['$', '$'], ['\\[', '\\]']]
}
};
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
<style>
/* 全局样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Noto Sans SC', sans-serif;
}
body {
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
background: #ffffff; /* 初始桌面背景颜色:白色 */
color: #333;
}
/* 顶栏 */
.header {
flex: 0 0 auto;
height: 60px;
background-color: #ffffff;
border-bottom: 1px solid #e0e0e0;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.app-title {
font-size: 24px;
color: #333;
font-weight: 700;
display: flex;
align-items: center;
gap: 8px;
}
/* 可选:添加图标 */
.app-title::before {
content: "";
font-size: 28px;
}
/* 顶栏右侧图标分组 */
.header-icons {
display: flex;
align-items: center;
gap: 15px;
}
/* 按钮通用样式 */
.header-icons button,
.toolbox-body button,
.icon-btn,
.chat-input button {
cursor: pointer;
border: none;
outline: none;
border-radius: 5px;
transition: background-color 0.3s, color 0.3s;
}
/* 全屏按钮 */
.fullscreen-btn {
font-size: 22px;
color: #555;
background: #f0f0f0;
padding: 8px;
}
.fullscreen-btn:hover {
background: #e0e0e0;
color: #000;
}
/* 工具箱按钮 */
.toolbox-btn {
font-size: 22px;
color: #555;
background: #f0f0f0;
padding: 8px;
}
.toolbox-btn:hover {
background: #e0e0e0;
color: #000;
}
/* 工具箱(右侧浮层) */
.toolbox-container {
position: fixed;
top: 60px;
right: 0;
width: 320px;
height: calc(100% - 60px);
background: #ffffff;
border-left: 1px solid #e0e0e0;
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
transform: translateX(100%);
transition: transform 0.3s ease;
z-index: 999;
}
.toolbox-container.show {
transform: translateX(0);
}
.toolbox-header {
font-size: 20px;
font-weight: 700;
padding: 20px;
border-bottom: 1px solid #e0e0e0;
background-color: #fafafa;
}
.toolbox-body {
flex: 1;
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 15px;
}
.toolbox-body label {
font-size: 14px;
color: #555;
margin-bottom: 5px;
}
.toolbox-body input[type="text"],
.toolbox-body input[type="number"],
.toolbox-body input[type="color"] {
width: 100%;
height: 40px;
font-size: 14px;
padding: 0 10px;
border: 1px solid #dcdcdc;
border-radius: 5px;
transition: border-color 0.3s;
}
.toolbox-body input[type="text"]:focus,
.toolbox-body input[type="number"]:focus,
.toolbox-body input[type="color"]:focus {
border-color: #3367d6;
}
/* 按钮样式 */
.toolbox-body button {
height: 42px;
font-size: 16px;
background: #3367d6;
color: #ffffff;
border: none;
border-radius: 5px;
padding: 0 15px;
}
.toolbox-body button:hover {
background: #2851a3;
}
/* 清空聊天窗口按钮 */
#clearChatBtn {
background: #e53935;
}
#clearChatBtn:hover {
background: #c62828;
}
/* 聊天区 */
.chat-container {
flex: 1;
overflow-y: auto;
padding: 20px;
background: #ffffff; /* 初始桌面背景颜色:白色 */
}
.message-wrapper {
display: flex;
width: 100%;
margin-bottom: 15px;
}
.wrapper-user {
justify-content: flex-end;
}
.wrapper-ai {
justify-content: flex-start;
}
.chat-message {
display: inline-flex;
flex-direction: column;
padding: 12px 16px;
border: 1px solid #e0e0e0;
border-radius: 15px;
max-width: 70%;
word-wrap: break-word;
line-height: 1.5;
white-space: pre-wrap; /* 保留换行 */
background-color: #f9f9f9; /* 初始气泡背景:白色 */
color: #333; /* 初始字体颜色 */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
position: relative;
}
/* 气泡箭头 */
.wrapper-user .chat-message::after {
content: '';
position: absolute;
top: 10px;
right: -10px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent transparent #f9f9f9;
}
.wrapper-ai .chat-message::after {
content: '';
position: absolute;
top: 10px;
left: -10px;
border-width: 5px;
border-style: solid;
border-color: transparent #f9f9f9 transparent transparent;
}
/* 每条消息下方的图标区域 */
.message-actions {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 8px;
}
.icon-btn {
background: #f0f0f0;
color: #555;
padding: 6px;
border-radius: 4px;
transition: background-color 0.3s, color 0.3s;
}
.icon-btn:hover {
background: #e0e0e0;
color: #000;
}
/* 底部输入区 */
.chat-input {
flex: 0 0 auto;
display: flex;
padding: 15px 20px;
background: #ffffff;
border-top: 1px solid #e0e0e0;
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.05);
}
.chat-input input {
flex: 1;
height: 50px;
font-size: 16px;
padding: 0 15px;
border: 1px solid #dcdcdc;
border-radius: 25px;
transition: border-color 0.3s;
}
.chat-input input:focus {
border-color: #3367d6;
outline: none;
}
.chat-input button {
width: 80px;
margin-left: 15px;
background: #3367d6;
color: #ffffff;
font-size: 16px;
border: none;
border-radius: 25px;
transition: background-color 0.3s;
}
.chat-input button:hover {
background: #2851a3;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-thumb {
background-color: #cccccc;
border-radius: 4px;
}
/* 聊天记录列表 */
.history-list {
border-top: 1px solid #e0e0e0;
padding-top: 15px;
margin-top: 15px;
max-height: 150px;
overflow-y: auto;
}
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
border-bottom: 1px solid #f0f0f0;
padding: 8px 0;
word-break: break-all;
}
.history-item:last-child {
border-bottom: none;
}
.history-item button {
background: #e0e0e0;
color: #555;
padding: 4px 8px;
border-radius: 4px;
transition: background-color 0.3s, color 0.3s;
}
.history-item button:hover {
background: #c0c0c0;
color: #000;
}
</style>
</head>
<body>
<!-- 顶栏 -->
<div class="header">
<div class="app-title">DeepSeek</div>
<div class="header-icons">
<!-- 全屏按钮 -->
<button class="fullscreen-btn" id="fullscreenToggle" title="全屏">?</button>
<!-- 工具箱按钮 -->
<button class="toolbox-btn" id="toolboxToggle" title="工具箱"></button>
</div>
</div>
<!-- 工具箱 -->
<div class="toolbox-container" id="toolboxContainer">
<div class="toolbox-header">工具箱</div>
<div class="toolbox-body">
<!-- 设置API Key -->
<div class="tool-section">
<label for="apiKeyInput">DeepSeek API Key</label>
<input id="apiKeyInput" type="text" placeholder="请输入 DeepSeek Key">
<button id="setKeyBtn">设置Key</button>
</div>
<!-- 设置记忆条数 -->
<div class="tool-section">
<label for="memoryLimit">记忆条数</label>
<input id="memoryLimit" type="number" min="1" max="999" placeholder="如:10">
<button id="setMemoryBtn">设置记忆</button>
</div>
<!-- 自定义颜色选项 -->
<div class="tool-section">
<label for="desktopColor">桌面背景颜色</label>
<input id="desktopColor" type="color" class="color-picker" value="#FFFFFF">
</div>
<div class="tool-section">
<label for="bubbleColorUser">用户气泡颜色</label>
<input id="bubbleColorUser" type="color" class="color-picker" value="#FFF0F0" />
</div>
<div class="tool-section">
<label for="bubbleColorAI">AI气泡颜色</label>
<input id="bubbleColorAI" type="color" class="color-picker" value="#F0FFF0" />
</div>
<div class="tool-section">
<label for="fontColor">字体颜色</label>
<input id="fontColor" type="color" class="color-picker" value="#333333" />
</div>
<button id="applyColorBtn">应用颜色</button>
<!-- 清空聊天窗口 -->
<button id="clearChatBtn">清空聊天窗口</button>
<!-- 聊天记录 -->
<div class="history-list">
<div style="font-weight: bold; margin-bottom: 8px;">聊天记录</div>
<div id="historyContainer"></div>
</div>
</div>
</div>
<!-- 聊天区 -->
<div id="chatContainer" class="chat-container"></div>
<!-- 底部输入框 -->
<div class="chat-input">
<input id="userInput" type="text" placeholder="请输入内容..." />
<button id="sendBtn">发送</button>
</div>
<script>
/************************************************************
* 全局变量 & DOM 获取
************************************************************/
let apiKey = "";
let memoryLimit = 10; // 默认记忆条数
const KEY_STORAGE = "DEEPSEEK_CHAT_HISTORY";
const COLOR_STORAGE = "DEEPSEEK_COLOR_CONFIG";
const toolboxToggle = document.getElementById("toolboxToggle");
const toolboxContainer = document.getElementById("toolboxContainer");
const apiKeyInput = document.getElementById("apiKeyInput");
const setKeyBtn = document.getElementById("setKeyBtn");
const memoryLimitInput = document.getElementById("memoryLimit");
const setMemoryBtn = document.getElementById("setMemoryBtn");
const clearChatBtn = document.getElementById("clearChatBtn");
const chatContainer = document.getElementById("chatContainer");
const userInput = document.getElementById("userInput");
const sendBtn = document.getElementById("sendBtn");
const historyContainer = document.getElementById("historyContainer");
// 自定义颜色相关
const desktopColorInput = document.getElementById("desktopColor");
const bubbleColorUserInput = document.getElementById("bubbleColorUser");
const bubbleColorAIInput = document.getElementById("bubbleColorAI");
const fontColorInput = document.getElementById("fontColor");
const applyColorBtn = document.getElementById("applyColorBtn");
// 全屏按钮
const fullscreenToggle = document.getElementById("fullscreenToggle");
// 聊天记录数组:[{role: "user"|"ai", content: "xxx", time: 167xxx }]
let chatHistory = [];
// 颜色配置(在本地缓存/读取)
let colorConfig = {
desktopColor: "#FFFFFF",
bubbleColorUser: "#FFF0F0",
bubbleColorAI: "#F0FFF0",
fontColor: "#333333"
};
/************************************************************
* 页面初始化
************************************************************/
window.addEventListener("DOMContentLoaded", () => {
// 从 localStorage 加载聊天记录
const saved = localStorage.getItem(KEY_STORAGE);
if (saved) {
try {
chatHistory = JSON.parse(saved);
} catch (e) {
console.warn("解析本地聊天记录失败:", e);
}
}
// 从 localStorage 加载颜色配置
const savedColor = localStorage.getItem(COLOR_STORAGE);
if (savedColor) {
try {
colorConfig = JSON.parse(savedColor);
} catch (e) {
console.warn("解析本地颜色配置失败:", e);
}
}
// 渲染历史 & 更新界面颜色
renderChatFromHistory();
renderHistoryList();
applyColorConfig(); // 应用颜色设置到界面
// 同步颜色选择器
desktopColorInput.value = colorConfig.desktopColor;
bubbleColorUserInput.value = colorConfig.bubbleColorUser;
bubbleColorAIInput.value = colorConfig.bubbleColorAI;
fontColorInput.value = colorConfig.fontColor;
});
/************************************************************
* 顶栏相关按钮
************************************************************/
// 全屏
fullscreenToggle.addEventListener("click", () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else if (document.exitFullscreen) {
document.exitFullscreen();
}
});
// 显示 / 隐藏工具箱
toolboxToggle.addEventListener("click", () => {
toolboxContainer.classList.toggle("show");
});
/************************************************************
* 工具箱交互
************************************************************/
// 设置 Key
setKeyBtn.addEventListener("click", () => {
const keyVal = apiKeyInput.value.trim();
if (!keyVal) {
alert("请输入有效的 DeepSeek Key");
return;
}
apiKey = keyVal;
alert("Key 设置成功!");
});
// 设置记忆条数
setMemoryBtn.addEventListener("click", () => {
const val = parseInt(memoryLimitInput.value, 10);
if (isNaN(val) || val < 1) {
alert("请输入正确的记忆条数");
return;
}
memoryLimit = val;
alert(`记忆条数已设置为:${memoryLimit}`);
});
// 应用颜色
applyColorBtn.addEventListener("click", () => {
colorConfig.desktopColor = desktopColorInput.value;
colorConfig.bubbleColorUser = bubbleColorUserInput.value;
colorConfig.bubbleColorAI = bubbleColorAIInput.value;
colorConfig.fontColor = fontColorInput.value;
// 应用到页面
applyColorConfig();
// 保存到 localStorage
localStorage.setItem(COLOR_STORAGE, JSON.stringify(colorConfig));
});
// 清空聊天窗口(不删除历史)
clearChatBtn.addEventListener("click", () => {
chatContainer.innerHTML = "";
});
/************************************************************
* 发送消息
************************************************************/
sendBtn.addEventListener("click", async () => {
const content = userInput.value.trim();
if (!content) return;
if (!apiKey) {
alert("请先在工具箱中设置 DeepSeek Key!");
return;
}
// 先渲染用户消息
addMessage(content, "user");
userInput.value = "";
// 构建带有“如果回答中涉及数学公式,请使用 $...$ 或 $...$ 标记”的 system 提示
const systemPrompt = "You are a helpful assistant. If your answer involves math formulas, please use $...$ or $...$ to mark the formula.";
// 将最近 memoryLimit 条对话一起发送给 DeepSeek
const messagesToSend = buildChatMessages(systemPrompt, content);
// 向 DeepSeek 发送请求
try {
const response = await fetch("https://api.deepseek.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`
},
body: JSON.stringify({
model: "deepseek-chat",
messages: messagesToSend
})
});
if (!response.ok) {
throw new Error(`请求失败,状态码: ${response.status}`);
}
const result = await response.json();
let aiReply = result?.choices?.[0]?.message?.content || "AI 未返回有效的消息。";
// 去除多余符号:★☆*# 等
aiReply = aiReply.replace(/[★☆*#]/g, "");
// 逐字打字
addMessage(aiReply, "ai", true);
} catch (err) {
console.error(err);
addMessage("请求失败,请检查 Key、网络或模型。", "ai");
}
});
/************************************************************
* 构建聊天上下文
************************************************************/
function buildChatMessages(systemPrompt, lastUserContent) {
// 1. 先放一个系统提示
const messages = [
{ role: "system", content: systemPrompt }
];
// 2. 获取最近 memoryLimit 条非 system 消息(含 user + ai)
const relevantMsgs = [];
for (let i = chatHistory.length - 1; i >= 0 && relevantMsgs.length < memoryLimit; i--) {
const msg = chatHistory[i];
if (msg.role === "user") {
relevantMsgs.push({ role: "user", content: msg.content });
} else if (msg.role === "ai") {
relevantMsgs.push({ role: "assistant", content: msg.content });
}
}
// 取完后要反转一下顺序(因为我们是从后往前取)
relevantMsgs.reverse();
// 3. 把这些消息推到 messages 数组中
messages.push(...relevantMsgs);
// 4. 最后再加上本次用户输入
messages.push({ role: "user", content: lastUserContent });
return messages;
}
/************************************************************
* 添加消息到屏幕 & 保存记录
************************************************************/
function addMessage(text, role, typed = false) {
// 存到 chatHistory
const messageData = { role, content: text, time: Date.now() };
chatHistory.push(messageData);
// 渲染当前消息到屏幕
renderSingleMessage(role, text, typed);
// 保存到 localStorage
localStorage.setItem(KEY_STORAGE, JSON.stringify(chatHistory));
// 重新渲染聊天记录列表
renderHistoryList();
}
/************************************************************
* 在屏幕渲染单条消息(可选 逐字打字 + MathJax 渲染)
************************************************************/
function renderSingleMessage(role, text, typed) {
const wrapper = document.createElement("div");
wrapper.classList.add("message-wrapper", role === "user" ? "wrapper-user" : "wrapper-ai");
const msgDiv = document.createElement("div");
msgDiv.classList.add("chat-message");
// 文字部分
const textSpan = document.createElement("span");
textSpan.classList.add("message-text");
// 图标按钮区域
const actionsDiv = document.createElement("div");
actionsDiv.classList.add("message-actions");
// 复制按钮
const copyBtn = document.createElement("button");
copyBtn.classList.add("icon-btn");
copyBtn.innerHTML = ""; // 剪贴板图标
copyBtn.title = "复制";
copyBtn.onclick = () => {
navigator.clipboard.writeText(text)
.then(() => alert("复制成功!"))
.catch(() => alert("复制失败,请手动复制。"));
};
// 删除按钮
const delBtn = document.createElement("button");
delBtn.classList.add("icon-btn");
delBtn.innerHTML = "?"; // 垃圾桶图标
delBtn.title = "删除";
delBtn.onclick = () => {
// 找到当前消息在 chatHistory 中的索引
const index = chatHistory.findIndex(msg => msg.content === text && msg.role === role);
if (index !== -1) {
chatHistory.splice(index, 1);
localStorage.setItem(KEY_STORAGE, JSON.stringify(chatHistory));
renderHistoryList();
renderChatFromHistory();
}
};
actionsDiv.appendChild(copyBtn);
actionsDiv.appendChild(delBtn);
msgDiv.appendChild(textSpan);
msgDiv.appendChild(actionsDiv);
wrapper.appendChild(msgDiv);
chatContainer.appendChild(wrapper);
// 逐字打字
if (typed) {
let idx = 0;
const timer = setInterval(() => {
textSpan.textContent += text.charAt(idx);
idx++;
scrollToBottom();
if (idx >= text.length) {
clearInterval(timer);
// 打字结束后进行公式渲染
if (window.MathJax) {
MathJax.typesetPromise([textSpan]).catch(err => console.log(err));
}
}
}, 30);
} else {
// 无需逐字打字,直接赋值
textSpan.textContent = text;
scrollToBottom();
// 直接公式渲染
if (window.MathJax) {
MathJax.typesetPromise([textSpan]).catch(err => console.log(err));
}
}
// 应用最新颜色(可能每次新消息都需要重新应用)
applyColorConfig();
}
/************************************************************
* 从历史记录渲染到屏幕
************************************************************/
function renderChatFromHistory() {
chatContainer.innerHTML = "";
chatHistory.forEach(msg => {
// 不渲染 system 的消息
if (msg.role === "system") return;
renderSingleMessage(msg.role, msg.content, false);
});
}
/************************************************************
* 聊天记录:渲染到“工具箱”
************************************************************/
function renderHistoryList() {
historyContainer.innerHTML = "";
chatHistory.forEach((item, idx) => {
if (item.role === "system") return;
const row = document.createElement("div");
row.classList.add("history-item");
const t = new Date(item.time);
const timeStr = t.toLocaleTimeString("zh-CN", { hour12: false })
+ " " + t.toLocaleDateString("zh-CN");
const shortContent = item.content.length > 30
? item.content.slice(0, 30) + "..."
: item.content;
row.innerHTML = `
<div style="flex:1;">
[${item.role === "user" ? "用户" : "AI"}] ${shortContent}
<div style="font-size:12px;color:#999;">${timeStr}</div>
</div>
`;
const delBtn = document.createElement("button");
delBtn.textContent = "删除";
delBtn.onclick = () => {
chatHistory.splice(idx, 1);
localStorage.setItem(KEY_STORAGE, JSON.stringify(chatHistory));
renderHistoryList();
renderChatFromHistory();
};
row.appendChild(delBtn);
historyContainer.appendChild(row);
});
}
/************************************************************
* 滚动到底部
************************************************************/
function scrollToBottom() {
chatContainer.scrollTop = chatContainer.scrollHeight;
}
/************************************************************
* 应用颜色配置
************************************************************/
function applyColorConfig() {
// 桌面背景
chatContainer.style.backgroundColor = colorConfig.desktopColor;
// 所有聊天气泡
const allMessages = document.querySelectorAll(".chat-message");
allMessages.forEach(msgDiv => {
// 判断是 user 还是 ai
const wrapper = msgDiv.parentElement;
if (wrapper.classList.contains("wrapper-user")) {
msgDiv.style.backgroundColor = colorConfig.bubbleColorUser;
} else {
msgDiv.style.backgroundColor = colorConfig.bubbleColorAI;
}
msgDiv.style.color = colorConfig.fontColor;
});
}
</script>
</body>
</html>
- 上一篇: 前端面试:BFC 是什么?
- 下一篇: 谷歌大语言模型最新升级手机桌面:请使用自己的谷歌官方API聊天
猜你喜欢
- 2025-01-04 「炫丽」从0开始做一个WPF+Blazor对话小程序
- 2025-01-04 adonisjs的模板以及路由
- 2025-01-04 5、谈谈你对BFC的理解?
- 2025-01-04 前端 BFC、IFC、GFC 和 FFC,这些你都知道吗?
- 2025-01-04 Wijmo5 Flexgrid基础教程:自定义编辑器
- 2025-01-04 H5小游戏开发教程之页面基础布局的开发
- 2025-01-04 web前端:CSS的常用属性速查表
- 2025-01-04 用网页做个ppt- 定时全屏切换图片
- 2025-01-04 HTML翻牌器:用CSS和HTML元素创造动态数字展示
- 2025-01-04 「网络安全」安全设备篇(漏洞扫描器-流量监控-安全审计产品)
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)