diff --git a/api/core/model_providers/providers/anthropic_provider.py b/api/core/model_providers/providers/anthropic_provider.py index eab61c60ccc2f0..2f667aed965732 100644 --- a/api/core/model_providers/providers/anthropic_provider.py +++ b/api/core/model_providers/providers/anthropic_provider.py @@ -172,7 +172,7 @@ def is_provider_type_system_supported(cls) -> bool: def should_deduct_quota(self): if hosted_model_providers.anthropic and \ - hosted_model_providers.anthropic.quota_limit and hosted_model_providers.anthropic.quota_limit > 0: + hosted_model_providers.anthropic.quota_limit and hosted_model_providers.anthropic.quota_limit > -1: return True return False diff --git a/api/core/model_providers/providers/azure_openai_provider.py b/api/core/model_providers/providers/azure_openai_provider.py index a34b463286a76a..242d9109cf28b2 100644 --- a/api/core/model_providers/providers/azure_openai_provider.py +++ b/api/core/model_providers/providers/azure_openai_provider.py @@ -329,7 +329,7 @@ def is_provider_type_system_supported(cls) -> bool: def should_deduct_quota(self): if hosted_model_providers.azure_openai \ - and hosted_model_providers.azure_openai.quota_limit and hosted_model_providers.azure_openai.quota_limit > 0: + and hosted_model_providers.azure_openai.quota_limit and hosted_model_providers.azure_openai.quota_limit > -1: return True return False diff --git a/api/core/model_providers/providers/hosted.py b/api/core/model_providers/providers/hosted.py index d2dc39b73f15c5..fd90a0a360cfe6 100644 --- a/api/core/model_providers/providers/hosted.py +++ b/api/core/model_providers/providers/hosted.py @@ -11,7 +11,7 @@ class HostedOpenAI(BaseModel): api_organization: str = None api_key: str quota_limit: int = 0 - """Quota limit for the openai hosted model. 0 means unlimited.""" + """Quota limit for the openai hosted model. -1 means unlimited.""" paid_enabled: bool = False paid_stripe_price_id: str = None paid_increase_quota: int = 1 @@ -21,14 +21,14 @@ class HostedAzureOpenAI(BaseModel): api_base: str api_key: str quota_limit: int = 0 - """Quota limit for the azure openai hosted model. 0 means unlimited.""" + """Quota limit for the azure openai hosted model. -1 means unlimited.""" class HostedAnthropic(BaseModel): api_base: str = None api_key: str quota_limit: int = 0 - """Quota limit for the anthropic hosted model. 0 means unlimited.""" + """Quota limit for the anthropic hosted model. -1 means unlimited.""" paid_enabled: bool = False paid_stripe_price_id: str = None paid_increase_quota: int = 1000000 diff --git a/api/core/model_providers/providers/openai_provider.py b/api/core/model_providers/providers/openai_provider.py index d72ad3c03bc18d..e2e17eab4570f3 100644 --- a/api/core/model_providers/providers/openai_provider.py +++ b/api/core/model_providers/providers/openai_provider.py @@ -250,7 +250,7 @@ def is_provider_type_system_supported(cls) -> bool: def should_deduct_quota(self): if hosted_model_providers.openai \ - and hosted_model_providers.openai.quota_limit and hosted_model_providers.openai.quota_limit > 0: + and hosted_model_providers.openai.quota_limit and hosted_model_providers.openai.quota_limit > -1: return True return False diff --git a/api/core/model_providers/rules/anthropic.json b/api/core/model_providers/rules/anthropic.json index c0aac8617c05d7..e617842b94d9c0 100644 --- a/api/core/model_providers/rules/anthropic.json +++ b/api/core/model_providers/rules/anthropic.json @@ -9,7 +9,7 @@ "trial" ], "quota_unit": "tokens", - "quota_limit": 600000 + "quota_limit": 0 }, "model_flexibility": "fixed", "price_config": { diff --git a/third-party/chrome plug-in/README_CN.md b/third-party/chrome plug-in/README_CN.md new file mode 100644 index 00000000000000..3c1ebabf9b8bcd --- /dev/null +++ b/third-party/chrome plug-in/README_CN.md @@ -0,0 +1,35 @@ +## Chrome Dify ChatBot插件 + +### 方式1:Chrome插件商店 * [点击访问](https://chrome.google.com/webstore/detail/dify-chatbot/ceehdapohffmjmkdcifjofadiaoeggaf/related?hl=zh-CN&authuser=0) * + +### 方式2:本地开发者模式加载 + +- 进入Chrome浏览器管理扩展程序,可直接访问 [chrome://extensions/](chrome://extensions/) +- 选择开启 “开发者模式”,并点击 “加载已解压的扩展程序” + +![img-1.png](images/img-1.png) + +- 然后打开插件源文件所在根目录 + - third-party + - chrome plug-in + - content.js 浮动按钮JS脚本 + - favicon.png 插件图标 + - manifest.json 插件描述文件 + - options.css 插件配置页面样式文件 + - options.html 插件配置静态HTML页面 + - options.js 插件配置JS脚本 + +### 插件导入完成后,后续配置无差异 +- 初始化设置Dify 应用配置,分别输入Dify根域名和应用Token,Token可以在Dify应用嵌入中获取,如图: + +![img-2.png](images/img-2.png) +![img-3.png](images/img-3.png) + +- 点击保存,确认提示配置成功即可 + +![img-4.png](images/img-4.png) + +- 保险起见重启浏览器确保所有分页刷新成功 +- Chrome打开任意页面均可正常加载DIfy机器人浮动栏,后续如需更换机器人只需要变更Token即可 + +![img-5.png](images/img-5.png) \ No newline at end of file diff --git a/third-party/chrome plug-in/content.js b/third-party/chrome plug-in/content.js new file mode 100644 index 00000000000000..24d25f330f65e0 --- /dev/null +++ b/third-party/chrome plug-in/content.js @@ -0,0 +1,170 @@ +var storage = chrome.storage.sync; +chrome.storage.sync.get(['baseUrl', 'token'], function(result) { + window.difyChatbotConfig = { + baseUrl: result.baseUrl, + token: result.token + }; +}); + +document.body.onload = embedChatbot; + +async function embedChatbot() { + const difyChatbotConfig = window.difyChatbotConfig; + if (!difyChatbotConfig || !difyChatbotConfig.token) { + console.warn('difyChatbotConfig is empty or token is not provided'); + return; + } + const baseUrl = difyChatbotConfig.baseUrl + const openIcon = ` + + `; + const closeIcon = ` + + `; + + // create iframe + function createIframe() { + const iframe = document.createElement('iframe'); + iframe.allow = "fullscreen;microphone" + iframe.title = "dify chatbot bubble window" + iframe.id = 'dify-chatbot-bubble-window' + iframe.src = `${baseUrl}/chat/${difyChatbotConfig.token}` + iframe.style.cssText = 'border: none; position: fixed; flex-direction: column; justify-content: space-between; box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px; bottom: 6.7rem; right: 1rem; width: 30rem; height: 48rem; border-radius: 0.75rem; display: flex; z-index: 2147483647; overflow: hidden; left: unset; background-color: #F3F4F6;' + document.body.appendChild(iframe); + } + + /** + * rem to px + * @param {*} rem :30rem + */ + function handleRemToPx(rem) { + if (!rem) return; + let pxValue = 0; + try { + const regex = /\d+/; + // extract the numeric part and convert it to a numeric type + const remValue = parseInt(regex.exec(rem)[0], 10); + const rootFontSize = parseFloat( + window.getComputedStyle(document.documentElement).fontSize + ); + pxValue = remValue * rootFontSize; + } catch (error) { + console.error(error); + } + return pxValue; + } + + /** + * support element drag + * @param {*} targetButton entry element + */ + function handleElementDrag(targetButton) { + // define a variable to hold the mouse position + let mouseX = 0, + mouseY = 0, + offsetX = 0, + offsetY = 0; + + // Listen for mouse press events, get mouse position and element position + targetButton.addEventListener("mousedown", function (event) { + // calculate mouse position + mouseX = event.clientX; + mouseY = event.clientY; + + // calculate element position + const rect = targetButton.getBoundingClientRect(); + offsetX = mouseX - rect.left; + offsetY = mouseY - rect.top; + + // listen for mouse movement events + document.addEventListener("mousemove", onMouseMove); + }); + + // listen for mouse lift events and stop listening for mouse move events + document.addEventListener("mouseup", function () { + document.removeEventListener("mousemove", onMouseMove); + }); + + // the mouse moves the event handler to update the element position + function onMouseMove(event) { + // calculate element position + let newX = event.clientX - offsetX, + newY = event.clientY - offsetY; + + // 计算视线边界 + const viewportWidth = window.innerWidth, + viewportHeight = window.innerHeight; + + const maxX = viewportWidth - targetButton.offsetWidth, + maxY = viewportHeight - targetButton.offsetHeight; + + // application limitation + newX = Math.max(12, Math.min(newX, maxX)); + newY = Math.max(12, Math.min(newY, maxY)); + + // update element position + targetButton.style.left = newX + "px"; + targetButton.style.top = newY + "px"; + } + } + + const targetButton = document.getElementById("dify-chatbot-bubble-button"); + + if (!targetButton) { + // create button + const containerDiv = document.createElement("div"); + containerDiv.id = 'dify-chatbot-bubble-button'; + containerDiv.style.cssText = `position: fixed; bottom: 3rem; right: 1rem; width: 50px; height: 50px; border-radius: 25px; background-color: #155EEF; box-shadow: rgba(0, 0, 0, 0.2) 0px 4px 8px 0px; cursor: move; z-index: 2147483647; transition: all 0.2s ease-in-out 0s; left: unset; transform: scale(1); :hover {transform: scale(1.1);}`; + const displayDiv = document.createElement('div'); + displayDiv.style.cssText = "display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; z-index: 2147483647;"; + displayDiv.innerHTML = openIcon; + containerDiv.appendChild(displayDiv); + document.body.appendChild(containerDiv); + handleElementDrag(containerDiv); + + // add click event to control iframe display + containerDiv.addEventListener('click', function () { + const targetIframe = document.getElementById('dify-chatbot-bubble-window'); + if (!targetIframe) { + createIframe(); + displayDiv.innerHTML = closeIcon; + return; + } + if (targetIframe.style.display === "none") { + targetIframe.style.display = "block"; + displayDiv.innerHTML = closeIcon; + } else { + targetIframe.style.display = "none"; + displayDiv.innerHTML = openIcon; + } + }); + } else { + // add any drag and drop to the floating icon + handleElementDrag(targetButton); + } +} \ No newline at end of file diff --git a/third-party/chrome plug-in/images/128.png b/third-party/chrome plug-in/images/128.png new file mode 100644 index 00000000000000..c88deb377aeefc Binary files /dev/null and b/third-party/chrome plug-in/images/128.png differ diff --git a/third-party/chrome plug-in/images/16.png b/third-party/chrome plug-in/images/16.png new file mode 100644 index 00000000000000..c26df616ffb6e4 Binary files /dev/null and b/third-party/chrome plug-in/images/16.png differ diff --git a/third-party/chrome plug-in/images/32.png b/third-party/chrome plug-in/images/32.png new file mode 100644 index 00000000000000..a748ace09fa445 Binary files /dev/null and b/third-party/chrome plug-in/images/32.png differ diff --git a/third-party/chrome plug-in/images/48.png b/third-party/chrome plug-in/images/48.png new file mode 100644 index 00000000000000..0cc74d8df053f6 Binary files /dev/null and b/third-party/chrome plug-in/images/48.png differ diff --git a/third-party/chrome plug-in/images/img-1.png b/third-party/chrome plug-in/images/img-1.png new file mode 100644 index 00000000000000..92dadaf37ea00a Binary files /dev/null and b/third-party/chrome plug-in/images/img-1.png differ diff --git a/third-party/chrome plug-in/images/img-2.png b/third-party/chrome plug-in/images/img-2.png new file mode 100644 index 00000000000000..ccc7100034b436 Binary files /dev/null and b/third-party/chrome plug-in/images/img-2.png differ diff --git a/third-party/chrome plug-in/images/img-3.png b/third-party/chrome plug-in/images/img-3.png new file mode 100644 index 00000000000000..b524df7e11e424 Binary files /dev/null and b/third-party/chrome plug-in/images/img-3.png differ diff --git a/third-party/chrome plug-in/images/img-4.png b/third-party/chrome plug-in/images/img-4.png new file mode 100644 index 00000000000000..193171bccf0612 Binary files /dev/null and b/third-party/chrome plug-in/images/img-4.png differ diff --git a/third-party/chrome plug-in/images/img-5.png b/third-party/chrome plug-in/images/img-5.png new file mode 100644 index 00000000000000..282a4a68397d0b Binary files /dev/null and b/third-party/chrome plug-in/images/img-5.png differ diff --git a/third-party/chrome plug-in/manifest.json b/third-party/chrome plug-in/manifest.json new file mode 100644 index 00000000000000..fe824c5d836c54 --- /dev/null +++ b/third-party/chrome plug-in/manifest.json @@ -0,0 +1,29 @@ +{ + "manifest_version": 3, + "name": "Dify Chatbot", + "version": "1.3", + "description": "This is a chrome extension to inject a dify chatbot on any pages", + "content_scripts": [ + { + "matches": [""], + "js": ["content.js"] + } + ], + "permissions": ["webRequest", "storage"], + "action": { + "default_popup": "options.html", + "default_icon": { + "16": "images/16.png", + "32": "images/32.png", + "48": "images/48.png", + "128": "images/128.png" + + } + }, + "icons": { + "16": "images/16.png", + "32": "images/32.png", + "48": "images/48.png", + "128": "images/128.png" + } +} \ No newline at end of file diff --git a/third-party/chrome plug-in/options.html b/third-party/chrome plug-in/options.html new file mode 100644 index 00000000000000..a0f614a1dc20cb --- /dev/null +++ b/third-party/chrome plug-in/options.html @@ -0,0 +1,56 @@ + + + + + Dify Chatbot Extension + + + + + +
+

Dify Chatbot Extension

+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/third-party/chrome plug-in/options.js b/third-party/chrome plug-in/options.js new file mode 100644 index 00000000000000..95895dc05c0182 --- /dev/null +++ b/third-party/chrome plug-in/options.js @@ -0,0 +1,39 @@ + +document.getElementById('save-button').addEventListener('click', function (e) { + e.preventDefault(); + var baseUrl = document.getElementById('base-url').value; + var token = document.getElementById('token').value; + var errorTip = document.getElementById('error-tip'); + + if (baseUrl.trim() === "" || token.trim() === "") { + if (baseUrl.trim() === "") { + errorTip.textContent = "Base URL cannot be empty."; + } else { + errorTip.textContent = "Token cannot be empty."; + } + } else { + errorTip.textContent = ""; + + chrome.storage.sync.set({ + 'baseUrl': baseUrl, + 'token': token + }, function () { + alert('Save Success!'); + }); + } + +}); + +// Load parameters from chrome.storage when the page loads +chrome.storage.sync.get(['baseUrl', 'token'], function (result) { + const baseUrlInput = document.getElementById('base-url'); + const tokenInput = document.getElementById('token'); + + if (result.baseUrl) { + baseUrlInput.value = result.baseUrl; + } + + if (result.token) { + tokenInput.value = result.token; + } +}); \ No newline at end of file