@@ -493,57 +548,57 @@
let artifactGenerating = false;
let artifactCodeBuffer = '';
let artifactMessagePlaceholder = null;
-
-
+
+
function updateCodePlaceholder(botMessageContainer, contentBeforeCodeblock, isLoading = true) {
if (isLoading) {
if (artifactMessagePlaceholder) {
-
+
const beforeContent = botMessageContainer.querySelector('.content-before-code');
if (beforeContent) {
beforeContent.innerHTML = renderMarkdown(contentBeforeCodeblock);
} else {
-
+
const currentHTML = botMessageContainer.innerHTML;
-
+
const placeholderDiv = botMessageContainer.querySelector('.code-placeholder');
if (placeholderDiv) {
botMessageContainer.innerHTML = `
${renderMarkdown(contentBeforeCodeblock)}
`;
botMessageContainer.appendChild(placeholderDiv);
} else {
-
+
botMessageContainer.innerHTML = `${renderMarkdown(contentBeforeCodeblock)}
` +
`autorenewCODING...
`;
artifactMessagePlaceholder = botMessageContainer.querySelector('.code-placeholder');
}
}
} else {
-
+
botMessageContainer.innerHTML = `${renderMarkdown(contentBeforeCodeblock)}
` +
`autorenewCODING...
`;
artifactMessagePlaceholder = botMessageContainer.querySelector('.code-placeholder');
}
} else {
-
-
+
+
const afterContent = botMessageContainer.querySelector('.content-after-code');
if (afterContent) {
afterContent.remove();
}
-
-
+
+
const beforeContent = botMessageContainer.querySelector('.content-before-code');
if (beforeContent) {
beforeContent.innerHTML = renderMarkdown(contentBeforeCodeblock);
} else {
-
+
const beforeDiv = document.createElement('div');
beforeDiv.className = 'content-before-code';
beforeDiv.innerHTML = renderMarkdown(contentBeforeCodeblock);
botMessageContainer.prepend(beforeDiv);
}
-
-
+
+
const placeholder = botMessageContainer.querySelector('.code-placeholder');
if (placeholder) {
placeholder.className = 'code-placeholder code-placeholder-completed';
@@ -552,8 +607,8 @@
const completeDiv = document.createElement('div');
completeDiv.className = 'code-placeholder code-placeholder-completed';
completeDiv.innerHTML = 'check_circleCode generation completed';
-
-
+
+
const beforeContent = botMessageContainer.querySelector('.content-before-code');
if (beforeContent) {
beforeContent.after(completeDiv);
@@ -563,49 +618,51 @@
}
}
}
-
+
marked.setOptions({
gfm: true,
breaks: true,
sanitize: false,
smartypants: true,
- highlight: function (code, lang) {
+ highlight: function(code, lang) {
return code;
}
});
- tabCode.onclick = function () {
+ tabCode.onclick = function() {
tabCode.classList.add('active');
tabPreview.classList.remove('active');
artifactCode.style.display = '';
artifactPreview.style.display = 'none';
};
- tabPreview.onclick = function () {
+ tabPreview.onclick = function() {
tabPreview.classList.add('active');
tabCode.classList.remove('active');
artifactCode.style.display = 'none';
artifactPreview.style.display = '';
-
+
if (artifactGenerating) {
artifactPreview.innerHTML = `autorenewCODING...
`;
} else if (lastArtifactHtml) {
try {
// 清空预览区域
artifactPreview.innerHTML = '';
-
+
// 创建一个blob URL
- const blob = new Blob([lastArtifactHtml], {type: 'text/html'});
+ const blob = new Blob([lastArtifactHtml], {
+ type: 'text/html'
+ });
const blobUrl = URL.createObjectURL(blob);
-
+
// 创建iframe并设置src为blob URL
const iframe = document.createElement('iframe');
iframe.style.width = '100%';
iframe.style.height = '100%';
iframe.style.border = 'none';
iframe.src = blobUrl;
-
+
// 添加iframe到预览区域
artifactPreview.appendChild(iframe);
-
+
// 在iframe加载完成后释放blob URL
iframe.onload = function() {
URL.revokeObjectURL(blobUrl);
@@ -617,6 +674,7 @@
artifactPreview.innerHTML = '';
}
};
+
function appendMessage(text, sender) {
const msg = document.createElement('div');
msg.className = 'message ' + sender;
@@ -625,6 +683,7 @@
chatLog.scrollTop = chatLog.scrollHeight;
return msg;
}
+
function showArtifact(htmlCode) {
artifactPane.classList.add('active');
artifactCode.textContent = htmlCode;
@@ -634,6 +693,7 @@
artifactPreview.style.display = 'none';
lastArtifactHtml = htmlCode;
}
+
function hideArtifact() {
artifactPane.classList.remove('active');
artifactCode.textContent = '';
@@ -674,9 +734,14 @@
const htmlBlockStartRegex = /```html[\r\n]+/;
const htmlBlockCompleteRegex = /```html[\r\n]+([\s\S]*?)```/;
while (true) {
- const { value, done } = await reader.read();
+ const {
+ value,
+ done
+ } = await reader.read();
if (done) break;
- buffer += decoder.decode(value, { stream: true });
+ buffer += decoder.decode(value, {
+ stream: true
+ });
const lines = buffer.split('\n\n');
buffer = lines.pop() || '';
for (const line of lines) {
@@ -714,9 +779,9 @@
const codeEndIndex = accumulatedText.indexOf('```', codeStartIndex + 6) + 3;
const contentBeforeCodeblock = accumulatedText.substring(0, codeStartIndex);
let contentAfterCodeblock = accumulatedText.substring(codeEndIndex);
-
+
contentAfterCodeblock = contentAfterCodeblock.trim();
-
+
updateCodePlaceholder(botMessageContainer, contentBeforeCodeblock, false);
if (contentAfterCodeblock) {
const afterContent = document.createElement('div');
@@ -724,10 +789,10 @@
afterContent.innerHTML = renderMarkdown(contentAfterCodeblock);
botMessageContainer.appendChild(afterContent);
}
-
+
artifactCode.textContent = artifactCodeBuffer;
lastArtifactHtml = artifactCodeBuffer;
-
+
// 预加载iframe以便立即渲染
if (tabPreview.classList.contains('active')) {
tabPreview.onclick();
@@ -743,16 +808,16 @@
}
}
} else if (!codeBlockStarted || codeBlockEnded) {
-
+
if (codeBlockEnded) {
-
+
const codeStartIndex = accumulatedText.indexOf('```html');
const codeEndIndex = accumulatedText.indexOf('```', codeStartIndex + 6) + 3;
const contentBeforeCodeblock = accumulatedText.substring(0, codeStartIndex);
let contentAfterCodeblock = accumulatedText.substring(codeEndIndex);
-
+
contentAfterCodeblock = contentAfterCodeblock.trim();
-
+
updateCodePlaceholder(botMessageContainer, contentBeforeCodeblock, false);
if (contentAfterCodeblock) {
const afterContent = document.createElement('div');
@@ -761,7 +826,7 @@
botMessageContainer.appendChild(afterContent);
}
} else {
-
+
botMessageContainer.innerHTML = renderMarkdown(accumulatedText);
}
}
@@ -770,22 +835,21 @@
conversationId = data.conversation_id;
localStorage.setItem('conversation_id', conversationId);
}
- } catch (error) {
- }
+ } catch (error) {}
}
}
if (codeBlockEnded && lastArtifactHtml) {
-
+
tabPreview.onclick();
-
-
+
+
const codeStartIndex = accumulatedText.indexOf('```html');
const codeEndIndex = accumulatedText.indexOf('```', codeStartIndex + 6) + 3;
const contentBeforeCodeblock = accumulatedText.substring(0, codeStartIndex);
let contentAfterCodeblock = accumulatedText.substring(codeEndIndex);
-
+
contentAfterCodeblock = contentAfterCodeblock.trim();
-
+
updateCodePlaceholder(botMessageContainer, contentBeforeCodeblock, false);
if (contentAfterCodeblock) {
const afterContent = document.createElement('div');
@@ -802,43 +866,51 @@
hideArtifact();
}
}
+
function startNewConversation() {
-
+
chatLog.innerHTML = '';
-
-
+
+
conversationId = '';
localStorage.removeItem('conversation_id');
-
-
+
+
hideArtifact();
globalAccumulatedText = '';
globalCodeBlockStarted = false;
globalCodeBlockEnded = false;
-
-
+
+
appendMessage('New Chat', 'bot');
}
-
-
+
+
newChatBtn.addEventListener('click', startNewConversation);
-
-
+
+
sendBtn.addEventListener('click', () => sendMessage());
- userInput.addEventListener('keypress', function (event) {
+ userInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') sendMessage();
});
+
function renderMarkdown(text, codeBlockStarted, codeBlockEnded) {
let renderedHtml = marked.parse(text);
renderedHtml = DOMPurify.sanitize(renderedHtml);
return renderedHtml;
}
+
function escapeHtml(str) {
- return str.replace(/[&<>]/g, function (tag) {
- const chars = { '&': '&', '<': '<', '>': '>' };
+ return str.replace(/[&<>]/g, function(tag) {
+ const chars = {
+ '&': '&',
+ '<': '<',
+ '>': '>'
+ };
return chars[tag] || tag;
});
}
+
\ No newline at end of file
diff --git a/endpoints/chat.py b/endpoints/chat.py
index 1f5112f..e82bc18 100644
--- a/endpoints/chat.py
+++ b/endpoints/chat.py
@@ -1,12 +1,16 @@
from collections.abc import Mapping
import json
from typing import Optional
+import os
+import logging
from werkzeug import Request, Response
+import requests
from dify_plugin import Endpoint
+
class Chat(Endpoint):
def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response:
"""
@@ -20,20 +24,43 @@ def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response:
data = r.get_json()
query = data.get("query")
conversation_id = data.get("conversation_id")
+ api_key = settings.get("api-key")
if not query:
return Response("Query is required", status=400)
def generator():
- response = self.session.app.chat.invoke(
- app_id=app.get("app_id"),
- query=query,
- inputs={},
- conversation_id=conversation_id,
- response_mode="streaming",
- )
-
- for chunk in response:
- yield json.dumps(chunk) + "\n\n"
+ dify_url = os.getenv(
+ "DIFY_INNER_API_URL", "https://api.dify.ai")
+ url = f"{dify_url}/v1/chat-messages"
+ headers = {
+ "Authorization": f"Bearer {api_key}",
+ "Content-Type": "application/json"
+ }
+ payload = {
+ "inputs": {},
+ "query": query,
+ "response_mode": "streaming",
+ "conversation_id": conversation_id,
+ "user": "abc-123", # 这里可以根据实际情况传递
+ }
+ print(url)
+ print(headers)
+ print(payload)
+ with requests.post(url, headers=headers, json=payload, stream=True) as resp:
+ for line in resp.iter_lines():
+ if line:
+ line_str = line.decode()
+ print(line_str)
+ if line_str.startswith("data:"):
+ try:
+ data_json = json.loads(line_str[5:].strip())
+ print(data_json)
+ if data_json["event"] != "message":
+ continue
+ if data_json is not None:
+ yield json.dumps(data_json) + "\n\n"
+ except Exception:
+ continue
return Response(generator(), status=200, content_type="text/event-stream")
diff --git a/provider/artifacts.yaml b/provider/artifacts.yaml
index 33abec6..65adc51 100644
--- a/provider/artifacts.yaml
+++ b/provider/artifacts.yaml
@@ -9,6 +9,16 @@ settings:
en_US: Please input your bot name
zh_Hans: 请输入你的机器人名称
default: "Candy"
+ - name: api-key
+ type: text-input
+ required: true
+ label:
+ en_US: api key
+ zh_Hans: dify api 密钥
+ placeholder:
+ en_US: Please input your API key
+ zh_Hans: 请输入你的api密钥
+ default: "Candy"
- name: app
type: app-selector
scope: chat