Dify 是一个开源 LLM 应用开发平台。Dify 的直观界面结合了 AI 工作流、RAG 管道、代理功能、模型管理、可观察性功能等,让您可以快速从原型转向生产。
申请API需要去官网申请
https://cloud.dify.ai/apps《需要科学上网》
使用手机桌面请保存下面二维码,使用浏览器打开,输入自己的API就可以聊天。
手机桌面开源代码↓
:root {
--theme-color: #4CAF50;
--text-color: #333;
--bg-color: #f8f8f8;
--message-bg-bot: #fff;
--message-bg-user: #DCF8C6;
--border-color: #ddd;
--header-bg-color: #4CAF50;
--header-text-color: #fff;
--input-bg-color: #fff;
--font-color: #333;
--toolbox-bg-color: #fff;
--toolbox-border-color: #ddd;
}
body {
font-family: '微软雅黑', 'Helvetica Neue', Arial, sans-serif;
margin: 0;
padding: 0;
background: var(--bg-color);
color: var(--text-color);
display: flex;
flex-direction: column;
height: 100vh;
transition: all 0.3s ease;
}
header {
background-color: var(--header-bg-color);
color: var(--header-text-color);
padding: 15px 20px;
text-align: center;
font-size: 1.5em;
font-weight: bold;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
z-index: 10;
}
#app-container {
flex: 1;
display: flex;
flex-direction: column;
margin: 10px;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 5px 30px rgba(0,0,0,0.1);
background: #fff;
padding: 20px;
}
#toolbox-toggle {
display: none;
}
#toolbox-toggle-label {
padding: 8px 16px;
border: none;
background-color: var(--theme-color);
color: #fff;
border-radius: 20px;
cursor: pointer;
font-size: 0.9em;
transition: background-color 0.3s;
margin-bottom: 10px;
align-self: flex-start;
}
#toolbox-toggle-label:hover {
background-color: #367c39;
}
#toolbox {
display: none;
flex-direction: column;
background: var(--toolbox-bg-color);
border: 1px solid var(--toolbox-border-color);
border-radius: 15px;
padding: 10px;
margin-bottom: 10px;
}
#toolbox-toggle:checked ~ #toolbox {
display: flex;
}
#toolbox .toolbox-section {
margin-bottom: 10px;
display: flex;
flex-wrap: wrap;
align-items: center;
}
#toolbox .toolbox-section label {
margin-right: 10px;
}
#prompt-list {
width: 100%;
border: 1px solid var(--border-color);
padding: 8px;
background-color: #fff;
border-radius: 15px;
max-height: 150px;
overflow-y: auto;
}
.prompt-item {
display: flex;
align-items: center;
margin-bottom: 5px;
padding: 5px;
border-radius: 10px;
background-color: #f0f0f0;
}
.prompt-item:hover {
background-color: #e0e0e0;
}
.prompt-item span {
flex: 1;
font-size: 0.9em;
margin-right: 10px;
word-break: break-all;
}
.prompt-item button {
background-color: #F44336;
color: white;
border: none;
padding: 5px 8px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 0.7em;
cursor: pointer;
border-radius: 8px;
margin-left: 5px;
}
#toolbox .toolbox-section input[type="text"] {
padding: 8px 10px;
border: 1px solid var(--border-color);
background-color: var(--input-bg-color);
border-radius: 20px;
margin-right: 10px;
font-size: 0.9em;
flex: 1;
}
#toolbox .toolbox-section button {
padding: 8px 16px;
border: none;
background-color: var(--theme-color);
color: #fff;
border-radius: 20px;
cursor: pointer;
font-size: 0.9em;
transition: background-color 0.3s;
margin-left: 5px;
}
#toolbox .toolbox-section button:hover {
background-color: #367c39;
}
#toolbox .toolbox-section select {
padding: 8px 10px;
border-radius: 20px;
border: 1px solid var(--border-color);
cursor: pointer;
font-size: 0.9em;
margin-right: 10px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23333' width='18px' height='18px'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 8px center;
padding-right: 25px;
margin: 5px;
}
#chat-container {
flex: 1;
padding: 15px;
overflow-y: auto;
background: var(--bg-color);
transition: background 0.3s;
}
.message {
margin: 10px 0;
max-width: 80%;
padding: 12px 15px;
border-radius: 15px;
white-space: pre-wrap;
word-wrap: break-word;
position: relative;
line-height: 1.4;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
font-size: 0.95em;
color: var(--font-color);
}
.message-actions {
position: absolute;
top: 5px;
right: 5px;
display: none;
}
.message:hover .message-actions {
display: flex;
}
.message-actions button {
background-color: #4CAF50;
color: white;
border: none;
padding: 5px 8px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 0.7em;
cursor: pointer;
border-radius: 8px;
margin-left: 5px;
}
.message-actions button:hover {
background-color: #367c39;
}
.message.user {
background-color: var(--message-bg-user);
align-self: flex-end;
text-align: right;
border-top-right-radius: 0;
}
.message.bot {
background-color: var(--message-bg-bot);
align-self: flex-start;
text-align: left;
border-top-left-radius: 0;
}
#input-container {
display: flex;
padding: 10px 15px;
background-color: var(--input-bg-color);
align-items: center;
border-top: 1px solid var(--border-color);
}
#input-container input[type="text"] {
flex: 1;
padding: 10px 15px;
border: 1px solid var(--border-color);
border-radius: 25px;
margin-right: 10px;
font-size: 0.9em;
}
/* 滚动条美化 */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: var(--theme-color);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: #367c39;
}
.icon {
width: 20px;
height: 20px;
fill: currentColor;
}
/* 响应式设计 */
@media (max-width: 768px) {
#app-container {
margin: 5px;
border-radius: 10px;
padding: 10px;
}
.message {
max-width: 95%;
font-size: 0.85em;
}
header {
padding: 10px 15px;
font-size: 1.3em;
}
#toolbox .toolbox-section input[type="text"],
#toolbox .toolbox-section select,
#input-container input[type="text"] {
font-size: 0.85em;
}
#toolbox .toolbox-section button {
font-size: 0.85em;
padding: 7px 14px;
}
#toolbox-toggle-label {
font-size: 0.85em;
padding: 7px 14px;
}
#chat-container {
padding: 10px;
}
}
let apiKey = '';
let conversationId = '';
let memorySize = 10;
let prompts = [];
const themes = {
"green": {
themeColor: "#4CAF50",
textColor: "#333",
bgColor: "#f8f8f8",
botMsg: "#fff",
userMsg: "#DCF8C6",
borderColor: "#ddd",
headerBgColor: "#4CAF50",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"blue": {
themeColor: "#2196F3",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#e3f2fd",
borderColor: "#ccc",
headerBgColor: "#2196F3",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"purple": {
themeColor: "#9C27B0",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#f3e5f5",
borderColor: "#ccc",
headerBgColor: "#9C27B0",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"orange": {
themeColor: "#FF5722",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#ffe0b2",
borderColor: "#ccc",
headerBgColor: "#FF5722",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"red": {
themeColor: "#F44336",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#ffcdd2",
borderColor: "#ccc",
headerBgColor: "#F44336",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"teal": {
themeColor: "#009688",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#b2dfdb",
borderColor: "#ccc",
headerBgColor: "#009688",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"deep-purple": {
themeColor: "#673AB7",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#d1c4e9",
borderColor: "#ccc",
headerBgColor: "#673AB7",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"indigo": {
themeColor: "#3F51B5",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#c5cae9",
borderColor: "#ccc",
headerBgColor: "#3F51B5",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"cyan": {
themeColor: "#00BCD4",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#b2ebf2",
borderColor: "#ccc",
headerBgColor: "#00BCD4",
headerTextColor: "#fff",
inputBgColor: "#fff"
},
"light-green": {
themeColor: "#8BC34A",
textColor: "#333",
bgColor: "#f5f5f5",
botMsg: "#fff",
userMsg: "#dcedc8",
borderColor: "#ccc",
headerBgColor: "#8BC34A",
headerTextColor: "#fff",
inputBgColor: "#fff"
}
};
const fontColors = {
"#333": "默认黑",
"#F44336": "热情红",
"#4CAF50": "清新绿",
"#2196F3": "天蓝",
"#9C27B0": "浪漫紫",
"#FF5722": "夕阳橙",
"#009688": "青翠",
"#673AB7": "深紫",
"#3F51B5": "靛蓝",
"#00BCD4": "薄荷蓝",
};
function applyTheme(name) {
const t = themes[name];
document.documentElement.style.setProperty('--theme-color', t.themeColor);
document.documentElement.style.setProperty('--text-color', t.textColor);
document.documentElement.style.setProperty('--bg-color', t.bgColor);
document.documentElement.style.setProperty('--message-bg-bot', t.botMsg);
document.documentElement.style.setProperty('--message-bg-user', t.userMsg);
document.documentElement.style.setProperty('--border-color', t.borderColor);
document.documentElement.style.setProperty('--header-bg-color', t.headerBgColor);
document.documentElement.style.setProperty('--header-text-color', t.headerTextColor);
document.documentElement.style.setProperty('--input-bg-color', t.inputBgColor);
}
function applyFontColor(color) {
document.documentElement.style.setProperty('--font-color', color);
}
function saveApiKey() {
const key = document.getElementById('api-key').value.trim();
if (key) {
apiKey = key;
alert('API密钥已保存!');
document.getElementById('api-key').disabled = true;
} else {
alert('请输入有效的API密钥。');
}
}
function clearAllMessages() {
const chatContainer = document.getElementById('chat-container');
chatContainer.innerHTML = '';
conversationId = '';
prompts = [];
updatePromptList();
}
function updatePromptList() {
const promptListDiv = document.getElementById('prompt-list');
promptListDiv.innerHTML = '';
prompts.forEach((prompt, index) => {
const promptItem = document.createElement('div');
promptItem.classList.add('prompt-item');
const promptTextSpan = document.createElement('span');
promptTextSpan.textContent = prompt;
promptItem.appendChild(promptTextSpan);
const removeBtn = document.createElement('button');
removeBtn.textContent = '删除';
removeBtn.onclick = () => removePrompt(index);
promptItem.appendChild(removeBtn);
promptListDiv.appendChild(promptItem);
});
}
function appendMessage(content, sender) {
const chatContainer = document.getElementById('chat-container');
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', sender);
messageDiv.textContent = content;
const messageActions = document.createElement('div');
messageActions.classList.add('message-actions');
const copyBtn = document.createElement('button');
copyBtn.textContent = '复制';
copyBtn.onclick = () => {
navigator.clipboard.writeText(content).then(() => {
alert('消息已复制到剪贴板!');
});
};
const deleteBtn = document.createElement('button');
deleteBtn.textContent = '删除';
deleteBtn.onclick = () => removeMessage(messageDiv);
const repeatBtn = document.createElement('button');
repeatBtn.textContent = '重复';
repeatBtn.onclick = () => repeatMessage(content);
messageActions.appendChild(copyBtn);
messageActions.appendChild(deleteBtn);
messageActions.appendChild(repeatBtn);
messageDiv.appendChild(messageActions)
chatContainer.appendChild(messageDiv);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function removeMessage(messageDiv) {
messageDiv.remove();
}
function repeatMessage(content) {
sendMessage(content,true)
}
function addPrompt() {
const promptInput = document.getElementById('prompt-input');
const promptText = promptInput.value.trim();
if (promptText) {
prompts.push(promptText);
alert('提示词已添加!');
promptInput.value = '';
updatePromptList();
}
}
function removePrompt(index) {
prompts.splice(index, 1);
updatePromptList();
}
function cleanText(text) {
return text.replace(/[^a-zA-Z0-9\u4e00-\u9fa5\s.,!?;:,。!?;:]/g, '');
}
async function typeText(element, text, delay = 50) {
for (const char of text) {
element.textContent += char;
element.parentNode.scrollTop = element.parentNode.scrollHeight;
await new Promise(res => setTimeout(res, delay));
}
}
async function sendMessage(userInput = document.getElementById('user-input').value.trim(),isRepeat = false) {
if (!userInput) return;
if (!apiKey) {
alert('请先输入并保存你的API密钥。');
return;
}
appendMessage(userInput, 'user');
if(!isRepeat){
document.getElementById('user-input').value = '';
}
try {
let requestBody = {
inputs: {},
query: userInput,
response_mode: "blocking",
user: "abc-123",
conversation_id: conversationId,
memory_size: memorySize,
prompts: prompts
};
const response = await fetch('https://api.dify.ai/v1/chat-messages', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
const errorText = await response.text();
appendMessage('Error: ' + errorText, 'bot');
return;
}
const responseData = await response.json();
if (responseData && responseData.answer) {
let cleanedText = cleanText(responseData.answer);
let botMessageDiv = document.createElement('div');
botMessageDiv.classList.add('message', 'bot');
const chatContainer = document.getElementById('chat-container');
chatContainer.appendChild(botMessageDiv);
await typeText(botMessageDiv, cleanedText);
const messageActions = document.createElement('div');
messageActions.classList.add('message-actions');
const copyBtn = document.createElement('button');
copyBtn.textContent = '复制';
copyBtn.onclick = () => {
navigator.clipboard.writeText(cleanedText).then(() => {
alert('消息已复制到剪贴板!');
});
};
const deleteBtn = document.createElement('button');
deleteBtn.textContent = '删除';
deleteBtn.onclick = () => removeMessage(botMessageDiv);
const repeatBtn = document.createElement('button');
repeatBtn.textContent = '重复';
repeatBtn.onclick = () => repeatMessage(cleanedText);
messageActions.appendChild(copyBtn);
messageActions.appendChild(deleteBtn);
messageActions.appendChild(repeatBtn);
botMessageDiv.appendChild(messageActions)
}
if (responseData.conversation_id) {
conversationId = responseData.conversation_id;
}
} catch (error) {
console.error('Error:', error);
appendMessage('请求失败: ' + error.message, 'bot');
}
}
function setMemory(size) {
memorySize = parseInt(size);
alert('记忆组数已设置为 ' + memorySize + ' 组');
}
document.getElementById('user-input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
updatePromptList();
applyTheme('green');
applyFontColor('#333');