From 9c7e99e8297f2b38d234b7b1e11d2676ba3193f4 Mon Sep 17 00:00:00 2001
From: Chenhe Gu
Date: Tue, 2 Apr 2024 17:19:21 +0800
Subject: [PATCH 1/6] Update README.md (#3081)
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 154fdd8adb..fc104cdd6e 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@
-**Dify** is an LLM application development platform that has helped built over **100,000** applications. It integrates BaaS and LLMOps, covering the essential tech stack for building generative AI-native applications, including a built-in RAG engine. Dify allows you to **deploy your own version of Assistants API and GPTs, based on any LLMs.**
+**Dify** is an open-source LLM app development platform. Dify's intuitive interface combines a RAG pipeline, AI workflow orchestration, agent capabilities, model management, observability features and more, letting you quickly go from prototype to production.

From e12a0c154c500895986cf9a383e9ab92a4b136af Mon Sep 17 00:00:00 2001
From: Jyong <76649700+JohnJyong@users.noreply.github.com>
Date: Tue, 2 Apr 2024 17:55:49 +0800
Subject: [PATCH 2/6] add segment function billing check for SAAS env (#3082)
Co-authored-by: jyong
---
.../console/datasets/datasets_segments.py | 8 ++++-
api/controllers/console/wraps.py | 25 +++++++++++++--
.../service_api/dataset/segment.py | 7 ++++-
api/controllers/service_api/wraps.py | 31 ++++++++++++++++---
4 files changed, 62 insertions(+), 9 deletions(-)
diff --git a/api/controllers/console/datasets/datasets_segments.py b/api/controllers/console/datasets/datasets_segments.py
index 1395963f1d..7b58120a58 100644
--- a/api/controllers/console/datasets/datasets_segments.py
+++ b/api/controllers/console/datasets/datasets_segments.py
@@ -12,7 +12,11 @@ from controllers.console import api
from controllers.console.app.error import ProviderNotInitializeError
from controllers.console.datasets.error import InvalidActionError, NoFileUploadedError, TooManyFilesError
from controllers.console.setup import setup_required
-from controllers.console.wraps import account_initialization_required, cloud_edition_billing_resource_check
+from controllers.console.wraps import (
+ account_initialization_required,
+ cloud_edition_billing_knowledge_limit_check,
+ cloud_edition_billing_resource_check,
+)
from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError
from core.model_manager import ModelManager
from core.model_runtime.entities.model_entities import ModelType
@@ -207,6 +211,7 @@ class DatasetDocumentSegmentAddApi(Resource):
@login_required
@account_initialization_required
@cloud_edition_billing_resource_check('vector_space')
+ @cloud_edition_billing_knowledge_limit_check('add_segment')
def post(self, dataset_id, document_id):
# check dataset
dataset_id = str(dataset_id)
@@ -357,6 +362,7 @@ class DatasetDocumentSegmentBatchImportApi(Resource):
@login_required
@account_initialization_required
@cloud_edition_billing_resource_check('vector_space')
+ @cloud_edition_billing_knowledge_limit_check('add_segment')
def post(self, dataset_id, document_id):
# check dataset
dataset_id = str(dataset_id)
diff --git a/api/controllers/console/wraps.py b/api/controllers/console/wraps.py
index 84f9918470..7c8ad11078 100644
--- a/api/controllers/console/wraps.py
+++ b/api/controllers/console/wraps.py
@@ -51,14 +51,12 @@ def cloud_edition_billing_resource_check(resource: str,
@wraps(view)
def decorated(*args, **kwargs):
features = FeatureService.get_features(current_user.current_tenant_id)
-
if features.billing.enabled:
members = features.members
apps = features.apps
vector_space = features.vector_space
documents_upload_quota = features.documents_upload_quota
annotation_quota_limit = features.annotation_quota_limit
-
if resource == 'members' and 0 < members.limit <= members.size:
abort(403, error_msg)
elif resource == 'apps' and 0 < apps.limit <= apps.size:
@@ -80,7 +78,29 @@ def cloud_edition_billing_resource_check(resource: str,
return view(*args, **kwargs)
return view(*args, **kwargs)
+
return decorated
+
+ return interceptor
+
+
+def cloud_edition_billing_knowledge_limit_check(resource: str,
+ error_msg: str = "To unlock this feature and elevate your Dify experience, please upgrade to a paid plan."):
+ def interceptor(view):
+ @wraps(view)
+ def decorated(*args, **kwargs):
+ features = FeatureService.get_features(current_user.current_tenant_id)
+ if features.billing.enabled:
+ if resource == 'add_segment':
+ if features.billing.subscription.plan == 'sandbox':
+ abort(403, error_msg)
+ else:
+ return view(*args, **kwargs)
+
+ return view(*args, **kwargs)
+
+ return decorated
+
return interceptor
@@ -99,4 +119,5 @@ def cloud_utm_record(view):
except Exception as e:
pass
return view(*args, **kwargs)
+
return decorated
diff --git a/api/controllers/service_api/dataset/segment.py b/api/controllers/service_api/dataset/segment.py
index 5d3a081357..0849eb72ba 100644
--- a/api/controllers/service_api/dataset/segment.py
+++ b/api/controllers/service_api/dataset/segment.py
@@ -4,7 +4,11 @@ from werkzeug.exceptions import NotFound
from controllers.service_api import api
from controllers.service_api.app.error import ProviderNotInitializeError
-from controllers.service_api.wraps import DatasetApiResource, cloud_edition_billing_resource_check
+from controllers.service_api.wraps import (
+ DatasetApiResource,
+ cloud_edition_billing_knowledge_limit_check,
+ cloud_edition_billing_resource_check,
+)
from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError
from core.model_manager import ModelManager
from core.model_runtime.entities.model_entities import ModelType
@@ -18,6 +22,7 @@ class SegmentApi(DatasetApiResource):
"""Resource for segments."""
@cloud_edition_billing_resource_check('vector_space', 'dataset')
+ @cloud_edition_billing_knowledge_limit_check('add_segment', 'dataset')
def post(self, tenant_id, dataset_id, document_id):
"""Create single segment."""
# check dataset
diff --git a/api/controllers/service_api/wraps.py b/api/controllers/service_api/wraps.py
index bdcbaecbea..a75583469e 100644
--- a/api/controllers/service_api/wraps.py
+++ b/api/controllers/service_api/wraps.py
@@ -8,7 +8,7 @@ from flask import current_app, request
from flask_login import user_logged_in
from flask_restful import Resource
from pydantic import BaseModel
-from werkzeug.exceptions import NotFound, Unauthorized
+from werkzeug.exceptions import Forbidden, NotFound, Unauthorized
from extensions.ext_database import db
from libs.login import _get_user
@@ -92,13 +92,13 @@ def cloud_edition_billing_resource_check(resource: str,
documents_upload_quota = features.documents_upload_quota
if resource == 'members' and 0 < members.limit <= members.size:
- raise Unauthorized(error_msg)
+ raise Forbidden(error_msg)
elif resource == 'apps' and 0 < apps.limit <= apps.size:
- raise Unauthorized(error_msg)
+ raise Forbidden(error_msg)
elif resource == 'vector_space' and 0 < vector_space.limit <= vector_space.size:
- raise Unauthorized(error_msg)
+ raise Forbidden(error_msg)
elif resource == 'documents' and 0 < documents_upload_quota.limit <= documents_upload_quota.size:
- raise Unauthorized(error_msg)
+ raise Forbidden(error_msg)
else:
return view(*args, **kwargs)
@@ -107,6 +107,27 @@ def cloud_edition_billing_resource_check(resource: str,
return interceptor
+def cloud_edition_billing_knowledge_limit_check(resource: str,
+ api_token_type: str,
+ error_msg: str = "To unlock this feature and elevate your Dify experience, please upgrade to a paid plan."):
+ def interceptor(view):
+ @wraps(view)
+ def decorated(*args, **kwargs):
+ api_token = validate_and_get_api_token(api_token_type)
+ features = FeatureService.get_features(api_token.tenant_id)
+ if features.billing.enabled:
+ if resource == 'add_segment':
+ if features.billing.subscription.plan == 'sandbox':
+ raise Forbidden(error_msg)
+ else:
+ return view(*args, **kwargs)
+
+ return view(*args, **kwargs)
+
+ return decorated
+
+ return interceptor
+
def validate_dataset_token(view=None):
def decorator(view):
@wraps(view)
From 6b4c8e76e6b6fed86cd89233f8714c888e890ab5 Mon Sep 17 00:00:00 2001
From: Salem Korayem
Date: Tue, 2 Apr 2024 13:38:46 +0300
Subject: [PATCH 3/6] feat (new llm): add support for openrouter (#3042)
---
.../model_providers/_position.yaml | 1 +
.../model_providers/openrouter/__init__.py | 0
.../openrouter/_assets/openrouter.svg | 11 ++
.../openrouter/_assets/openrouter_square.svg | 10 ++
.../openrouter/llm/__init__.py | 0
.../model_providers/openrouter/llm/llm.py | 46 +++++++
.../model_providers/openrouter/openrouter.py | 11 ++
.../openrouter/openrouter.yaml | 75 +++++++++++
.../model_runtime/openrouter/__init__.py | 0
.../model_runtime/openrouter/test_llm.py | 118 ++++++++++++++++++
10 files changed, 272 insertions(+)
create mode 100644 api/core/model_runtime/model_providers/openrouter/__init__.py
create mode 100644 api/core/model_runtime/model_providers/openrouter/_assets/openrouter.svg
create mode 100644 api/core/model_runtime/model_providers/openrouter/_assets/openrouter_square.svg
create mode 100644 api/core/model_runtime/model_providers/openrouter/llm/__init__.py
create mode 100644 api/core/model_runtime/model_providers/openrouter/llm/llm.py
create mode 100644 api/core/model_runtime/model_providers/openrouter/openrouter.py
create mode 100644 api/core/model_runtime/model_providers/openrouter/openrouter.yaml
create mode 100644 api/tests/integration_tests/model_runtime/openrouter/__init__.py
create mode 100644 api/tests/integration_tests/model_runtime/openrouter/test_llm.py
diff --git a/api/core/model_runtime/model_providers/_position.yaml b/api/core/model_runtime/model_providers/_position.yaml
index 7b4416f44e..c06f122984 100644
--- a/api/core/model_runtime/model_providers/_position.yaml
+++ b/api/core/model_runtime/model_providers/_position.yaml
@@ -6,6 +6,7 @@
- cohere
- bedrock
- togetherai
+- openrouter
- ollama
- mistralai
- groq
diff --git a/api/core/model_runtime/model_providers/openrouter/__init__.py b/api/core/model_runtime/model_providers/openrouter/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/api/core/model_runtime/model_providers/openrouter/_assets/openrouter.svg b/api/core/model_runtime/model_providers/openrouter/_assets/openrouter.svg
new file mode 100644
index 0000000000..2e9590d923
--- /dev/null
+++ b/api/core/model_runtime/model_providers/openrouter/_assets/openrouter.svg
@@ -0,0 +1,11 @@
+
diff --git a/api/core/model_runtime/model_providers/openrouter/_assets/openrouter_square.svg b/api/core/model_runtime/model_providers/openrouter/_assets/openrouter_square.svg
new file mode 100644
index 0000000000..ed81fc041f
--- /dev/null
+++ b/api/core/model_runtime/model_providers/openrouter/_assets/openrouter_square.svg
@@ -0,0 +1,10 @@
+
diff --git a/api/core/model_runtime/model_providers/openrouter/llm/__init__.py b/api/core/model_runtime/model_providers/openrouter/llm/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/api/core/model_runtime/model_providers/openrouter/llm/llm.py b/api/core/model_runtime/model_providers/openrouter/llm/llm.py
new file mode 100644
index 0000000000..bb62fc7bb2
--- /dev/null
+++ b/api/core/model_runtime/model_providers/openrouter/llm/llm.py
@@ -0,0 +1,46 @@
+from collections.abc import Generator
+from typing import Optional, Union
+
+from core.model_runtime.entities.llm_entities import LLMResult
+from core.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool
+from core.model_runtime.entities.model_entities import AIModelEntity
+from core.model_runtime.model_providers.openai_api_compatible.llm.llm import OAIAPICompatLargeLanguageModel
+
+
+class OpenRouterLargeLanguageModel(OAIAPICompatLargeLanguageModel):
+
+ def _update_endpoint_url(self, credentials: dict):
+ credentials['endpoint_url'] = "https://openrouter.ai/api/v1"
+ return credentials
+
+ def _invoke(self, model: str, credentials: dict,
+ prompt_messages: list[PromptMessage], model_parameters: dict,
+ tools: Optional[list[PromptMessageTool]] = None, stop: Optional[list[str]] = None,
+ stream: bool = True, user: Optional[str] = None) \
+ -> Union[LLMResult, Generator]:
+ cred_with_endpoint = self._update_endpoint_url(credentials=credentials)
+
+ return super()._invoke(model, cred_with_endpoint, prompt_messages, model_parameters, tools, stop, stream, user)
+
+ def validate_credentials(self, model: str, credentials: dict) -> None:
+ cred_with_endpoint = self._update_endpoint_url(credentials=credentials)
+
+ return super().validate_credentials(model, cred_with_endpoint)
+
+ def _generate(self, model: str, credentials: dict, prompt_messages: list[PromptMessage], model_parameters: dict,
+ tools: Optional[list[PromptMessageTool]] = None, stop: Optional[list[str]] = None,
+ stream: bool = True, user: Optional[str] = None) -> Union[LLMResult, Generator]:
+ cred_with_endpoint = self._update_endpoint_url(credentials=credentials)
+
+ return super()._generate(model, cred_with_endpoint, prompt_messages, model_parameters, tools, stop, stream, user)
+
+ def get_customizable_model_schema(self, model: str, credentials: dict) -> AIModelEntity:
+ cred_with_endpoint = self._update_endpoint_url(credentials=credentials)
+
+ return super().get_customizable_model_schema(model, cred_with_endpoint)
+
+ def get_num_tokens(self, model: str, credentials: dict, prompt_messages: list[PromptMessage],
+ tools: Optional[list[PromptMessageTool]] = None) -> int:
+ cred_with_endpoint = self._update_endpoint_url(credentials=credentials)
+
+ return super().get_num_tokens(model, cred_with_endpoint, prompt_messages, tools)
diff --git a/api/core/model_runtime/model_providers/openrouter/openrouter.py b/api/core/model_runtime/model_providers/openrouter/openrouter.py
new file mode 100644
index 0000000000..81313fd29a
--- /dev/null
+++ b/api/core/model_runtime/model_providers/openrouter/openrouter.py
@@ -0,0 +1,11 @@
+import logging
+
+from core.model_runtime.model_providers.__base.model_provider import ModelProvider
+
+logger = logging.getLogger(__name__)
+
+
+class OpenRouterProvider(ModelProvider):
+
+ def validate_provider_credentials(self, credentials: dict) -> None:
+ pass
diff --git a/api/core/model_runtime/model_providers/openrouter/openrouter.yaml b/api/core/model_runtime/model_providers/openrouter/openrouter.yaml
new file mode 100644
index 0000000000..48a70700bb
--- /dev/null
+++ b/api/core/model_runtime/model_providers/openrouter/openrouter.yaml
@@ -0,0 +1,75 @@
+provider: openrouter
+label:
+ en_US: openrouter.ai
+icon_small:
+ en_US: openrouter_square.svg
+icon_large:
+ en_US: openrouter.svg
+background: "#F1EFED"
+help:
+ title:
+ en_US: Get your API key from openrouter.ai
+ zh_Hans: 从 openrouter.ai 获取 API Key
+ url:
+ en_US: https://openrouter.ai/keys
+supported_model_types:
+ - llm
+configurate_methods:
+ - customizable-model
+model_credential_schema:
+ model:
+ label:
+ en_US: Model Name
+ zh_Hans: 模型名称
+ placeholder:
+ en_US: Enter full model name
+ zh_Hans: 输入模型全称
+ credential_form_schemas:
+ - variable: api_key
+ required: true
+ label:
+ en_US: API Key
+ type: secret-input
+ placeholder:
+ zh_Hans: 在此输入您的 API Key
+ en_US: Enter your API Key
+ - variable: mode
+ show_on:
+ - variable: __model_type
+ value: llm
+ label:
+ en_US: Completion mode
+ type: select
+ required: false
+ default: chat
+ placeholder:
+ zh_Hans: 选择对话类型
+ en_US: Select completion mode
+ options:
+ - value: completion
+ label:
+ en_US: Completion
+ zh_Hans: 补全
+ - value: chat
+ label:
+ en_US: Chat
+ zh_Hans: 对话
+ - variable: context_size
+ label:
+ zh_Hans: 模型上下文长度
+ en_US: Model context size
+ required: true
+ type: text-input
+ default: "4096"
+ placeholder:
+ zh_Hans: 在此输入您的模型上下文长度
+ en_US: Enter your Model context size
+ - variable: max_tokens_to_sample
+ label:
+ zh_Hans: 最大 token 上限
+ en_US: Upper bound for max tokens
+ show_on:
+ - variable: __model_type
+ value: llm
+ default: "4096"
+ type: text-input
diff --git a/api/tests/integration_tests/model_runtime/openrouter/__init__.py b/api/tests/integration_tests/model_runtime/openrouter/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/api/tests/integration_tests/model_runtime/openrouter/test_llm.py b/api/tests/integration_tests/model_runtime/openrouter/test_llm.py
new file mode 100644
index 0000000000..c0164e6418
--- /dev/null
+++ b/api/tests/integration_tests/model_runtime/openrouter/test_llm.py
@@ -0,0 +1,118 @@
+import os
+from typing import Generator
+
+import pytest
+from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta
+from core.model_runtime.entities.message_entities import (AssistantPromptMessage, PromptMessageTool,
+ SystemPromptMessage, UserPromptMessage)
+from core.model_runtime.errors.validate import CredentialsValidateFailedError
+from core.model_runtime.model_providers.openrouter.llm.llm import OpenRouterLargeLanguageModel
+
+
+def test_validate_credentials():
+ model = OpenRouterLargeLanguageModel()
+
+ with pytest.raises(CredentialsValidateFailedError):
+ model.validate_credentials(
+ model='mistralai/mixtral-8x7b-instruct',
+ credentials={
+ 'api_key': 'invalid_key',
+ 'mode': 'chat'
+ }
+ )
+
+ model.validate_credentials(
+ model='mistralai/mixtral-8x7b-instruct',
+ credentials={
+ 'api_key': os.environ.get('TOGETHER_API_KEY'),
+ 'mode': 'chat'
+ }
+ )
+
+
+def test_invoke_model():
+ model = OpenRouterLargeLanguageModel()
+
+ response = model.invoke(
+ model='mistralai/mixtral-8x7b-instruct',
+ credentials={
+ 'api_key': os.environ.get('TOGETHER_API_KEY'),
+ 'mode': 'completion'
+ },
+ prompt_messages=[
+ SystemPromptMessage(
+ content='You are a helpful AI assistant.',
+ ),
+ UserPromptMessage(
+ content='Who are you?'
+ )
+ ],
+ model_parameters={
+ 'temperature': 1.0,
+ 'top_k': 2,
+ 'top_p': 0.5,
+ },
+ stop=['How'],
+ stream=False,
+ user="abc-123"
+ )
+
+ assert isinstance(response, LLMResult)
+ assert len(response.message.content) > 0
+
+
+def test_invoke_stream_model():
+ model = OpenRouterLargeLanguageModel()
+
+ response = model.invoke(
+ model='mistralai/mixtral-8x7b-instruct',
+ credentials={
+ 'api_key': os.environ.get('TOGETHER_API_KEY'),
+ 'mode': 'chat'
+ },
+ prompt_messages=[
+ SystemPromptMessage(
+ content='You are a helpful AI assistant.',
+ ),
+ UserPromptMessage(
+ content='Who are you?'
+ )
+ ],
+ model_parameters={
+ 'temperature': 1.0,
+ 'top_k': 2,
+ 'top_p': 0.5,
+ },
+ stop=['How'],
+ stream=True,
+ user="abc-123"
+ )
+
+ assert isinstance(response, Generator)
+
+ for chunk in response:
+ assert isinstance(chunk, LLMResultChunk)
+ assert isinstance(chunk.delta, LLMResultChunkDelta)
+ assert isinstance(chunk.delta.message, AssistantPromptMessage)
+
+
+def test_get_num_tokens():
+ model = OpenRouterLargeLanguageModel()
+
+ num_tokens = model.get_num_tokens(
+ model='mistralai/mixtral-8x7b-instruct',
+ credentials={
+ 'api_key': os.environ.get('TOGETHER_API_KEY'),
+ },
+ prompt_messages=[
+ SystemPromptMessage(
+ content='You are a helpful AI assistant.',
+ ),
+ UserPromptMessage(
+ content='Hello World!'
+ )
+ ]
+ )
+
+ assert isinstance(num_tokens, int)
+ assert num_tokens == 21
From f7d1d9b8b12a97c7267145375e50e1ee227353ef Mon Sep 17 00:00:00 2001
From: QIN2DIM <62018067+QIN2DIM@users.noreply.github.com>
Date: Tue, 2 Apr 2024 18:40:09 +0800
Subject: [PATCH 4/6] fix(duckduckgo-search): invoke error (#3077)
---
api/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/api/requirements.txt b/api/requirements.txt
index 0c7d568aa7..cbfde69125 100644
--- a/api/requirements.txt
+++ b/api/requirements.txt
@@ -67,7 +67,7 @@ yfinance~=0.2.35
pydub~=0.25.1
gmpy2~=2.1.5
numexpr~=2.9.0
-duckduckgo-search==5.1.0
+duckduckgo-search==5.2.2
arxiv==2.1.0
yarl~=1.9.4
twilio==9.0.0
From 7f55ea0c5374cb31674aed57bdcf76ca32b6d556 Mon Sep 17 00:00:00 2001
From: crazywoola <100913391+crazywoola@users.noreply.github.com>
Date: Tue, 2 Apr 2024 19:51:02 +0800
Subject: [PATCH 5/6] Chore/move chrome ext (#3085)
---
README.md | 3 +
third-party/chrome plug-in/README_CN.md | 33 -
third-party/chrome plug-in/README_CN.txt | 6 -
third-party/chrome plug-in/content.js | 168 -
third-party/chrome plug-in/favicon.png | Bin 2817 -> 0 bytes
third-party/chrome plug-in/images/128.png | Bin 15112 -> 0 bytes
third-party/chrome plug-in/images/16.png | Bin 8238 -> 0 bytes
third-party/chrome plug-in/images/32.png | Bin 11618 -> 0 bytes
third-party/chrome plug-in/images/48.png | Bin 13373 -> 0 bytes
third-party/chrome plug-in/images/favicon.ico | Bin 15406 -> 0 bytes
third-party/chrome plug-in/images/img-1.png | Bin 31346 -> 0 bytes
third-party/chrome plug-in/images/img-2.png | Bin 126710 -> 0 bytes
third-party/chrome plug-in/images/img-3.png | Bin 86708 -> 0 bytes
third-party/chrome plug-in/images/img-4.png | Bin 87487 -> 0 bytes
third-party/chrome plug-in/manifest.json | 29 -
third-party/chrome plug-in/options.css | 19 -
third-party/chrome plug-in/options.html | 45 -
third-party/chrome plug-in/options.js | 28 -
third-party/chrome plug-in/tailwind.css | 176015 ---------------
19 files changed, 3 insertions(+), 176343 deletions(-)
delete mode 100644 third-party/chrome plug-in/README_CN.md
delete mode 100644 third-party/chrome plug-in/README_CN.txt
delete mode 100644 third-party/chrome plug-in/content.js
delete mode 100644 third-party/chrome plug-in/favicon.png
delete mode 100644 third-party/chrome plug-in/images/128.png
delete mode 100644 third-party/chrome plug-in/images/16.png
delete mode 100644 third-party/chrome plug-in/images/32.png
delete mode 100644 third-party/chrome plug-in/images/48.png
delete mode 100644 third-party/chrome plug-in/images/favicon.ico
delete mode 100644 third-party/chrome plug-in/images/img-1.png
delete mode 100644 third-party/chrome plug-in/images/img-2.png
delete mode 100644 third-party/chrome plug-in/images/img-3.png
delete mode 100644 third-party/chrome plug-in/images/img-4.png
delete mode 100644 third-party/chrome plug-in/manifest.json
delete mode 100644 third-party/chrome plug-in/options.css
delete mode 100644 third-party/chrome plug-in/options.html
delete mode 100644 third-party/chrome plug-in/options.js
delete mode 100644 third-party/chrome plug-in/tailwind.css
diff --git a/README.md b/README.md
index fc104cdd6e..51c41a438f 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,9 @@ For those who'd like to contribute code, see our [Contribution Guide](https://gi
At the same time, please consider supporting Dify by sharing it on social media and at events and conferences.
+### Projects made by community
+
+- [Chatbot Chrome Extension by @charli117](https://github.com/langgenius/chatbot-chrome-extension)
### Contributors
diff --git a/third-party/chrome plug-in/README_CN.md b/third-party/chrome plug-in/README_CN.md
deleted file mode 100644
index 55586da3b3..0000000000
--- a/third-party/chrome plug-in/README_CN.md
+++ /dev/null
@@ -1,33 +0,0 @@
-## 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/)
-- 选择开启 “开发者模式”,并点击 “加载已解压的扩展程序”
-
-
-
-- 然后打开插件源文件所在根目录
- - third-party
- - chrome plug-in
- - content.js 浮动按钮JS脚本
- - favicon.png 插件图标
- - manifest.json 插件描述文件
- - options.css 插件配置页面样式文件
- - options.html 插件配置静态HTML页面
- - options.js 插件配置JS脚本
-
-### 插件导入完成后,后续配置无差异
-- 创建Dify应用配置,在应用概览中点击嵌入,切换到安装Chrome浏览器扩展视图,点击copy按钮获取ChatBot Url,如图:
-
-
-- 点击保存,确认提示配置成功即可
-
-
-
-- 保险起见重启浏览器确保所有分页刷新成功
-- Chrome打开任意页面均可正常加载DIfy机器人浮动栏,后续如需更换机器人只需要变更ChatBot Url即可
-
-
\ No newline at end of file
diff --git a/third-party/chrome plug-in/README_CN.txt b/third-party/chrome plug-in/README_CN.txt
deleted file mode 100644
index 83938dfa6e..0000000000
--- a/third-party/chrome plug-in/README_CN.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-## Chrome Dify ChatBot插件
-
-1、初始化设置Dify 应用配置,分别输入Dify根域名和应用Token,Token可以在Dify应用嵌入中获取;
-2、点击保存,确认提示配置成功即可;
-3、保险起见重启浏览器确保所有分页刷新成功;
-4、Chrome打开任意页面均可正常加载DIfy机器人浮动栏,后续如需更换机器人只需要变更Token即可;
\ No newline at end of file
diff --git a/third-party/chrome plug-in/content.js b/third-party/chrome plug-in/content.js
deleted file mode 100644
index 3f64f3be12..0000000000
--- a/third-party/chrome plug-in/content.js
+++ /dev/null
@@ -1,168 +0,0 @@
-const storage = chrome.storage.sync;
-chrome.storage.sync.get(['chatbotUrl'], function(result) {
- window.difyChatbotConfig = {
- chatbotUrl: result.chatbotUrl,
- };
-});
-
-document.body.onload = embedChatbot;
-
-async function embedChatbot() {
- const difyChatbotConfig = window.difyChatbotConfig;
- if (!difyChatbotConfig) {
- console.warn('Dify Chatbot Url is empty or is not provided');
- return;
- }
- 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 = difyChatbotConfig.chatbotUrl
- 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/favicon.png b/third-party/chrome plug-in/favicon.png
deleted file mode 100644
index 053fd442632bc765d34614b36acbced9fa7f9044..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 2817
zcmZ{mcQo6J7r?)Xm^EV0M{27TO(+q4Mv4+MtzES$XpyE=(GsNfY{DaU>`_&tel>!K
zn$?F#hqhFUnl-CN(VzFv@0{Ns@7#0m=bU@*=iGm9f~~a~50?ZN002Cf%`x_;g#VKq
zY^T)`d=P&Mn76sT6#zsi0sx5&0Eee7(h>lKo-VF<004>#0HTC~c02UxfX&O&3sPXUjhn9K}z%eocP+U|@hKlpgTuCsQ%D7^AI>6iu*(TU$Cu
z&lB40x!L}OHP+BFP%}r+izQlSKJ=Bw;lF7^K-ZH?D~cqJy0w@ID`J08^#Id$d2+fB^zcK!aQQ&2v(M4
zlDNn6ugJ5Tl-y2_M|k~}8t3O*FVNi4)1Ri=H$RRxM6XL7zk)8knZ6Q?09}Y}ea%WW
zg2NKwU;$XX9~l?~#e0-P3}wqP@CS}iSSVfU0ln3%sQB9Z==p4$?Vb$-!ohfc;A(N$
z$DS=0j(6?(27p;q8!%ct7Gfiy0Q(eVJ-qj9{u+fuz>euFb3vChk|Z6GjouCwKOa
z51FCAbogL#X;3g{tFnD8pyZPvG!C63%Ro6E=Rg?P0S+-E3L?FV^L_!7T?hZ6c>lyC
zDf0R^9qFIj{KP)qL$k&Z?0S61Qs0+M(G|TW{qomJjlL338bBk;zQz!1Mo5)jccVUU
z*zsoC(>3~Ka1xtOqG!2{!x-;9ALQ`MkHeQ)F8`AMr_Swa^MX
zq7IY-yH)sF^``~jDbor%Sc+o(Eo{wxP@2g?Ll+*|Hb#Mp3UR8UMgn;7@%pi6>rU8W
zOK2cOWQZ9+aug_{JWnTxS~AOajdy`n*JR*Tc3rTkbEH-5{IbWjFKxrSvxo8awPB
zSnN{Ul13}uYkVr(F-@;Wa#K4C5UV8f+^ieL%FnMt0R$YnvChyunzvh%N&wOs;s5Dc
zBo$u}BvNZyFEtap8EOb#E$Jg;(PZg;(?Wdx&^G++XQb*4`?cpf5kl_?JLweiQ`g
z`YzcF&r?N}bmgteXV%CPJW`BDBp3L7(%2Hew`RQ^
z@&*$+LoE<=m+1jF9M-?w!=}CG9m3A#2WB2SnJFcM@E==!p%%}Ta!n%
zoxv+H9t@p?{AS!!ENue>;ny01BS`Z=Joi4Wo0GW~;om?iAG+=7v5
z<0nGU%V+%9e96j#^n>~MpvKRI!5>oN1no-cc_7OOKDVyAw=XI8ryDOOfCwYq!SY0f
zvAU7;*Zxw4;}35GB9U>|+9xMOm2MLS-^=v%)VzP4p}+gLtY2)kHdUF_aI$|{%}VP{
zB+Ul*$ZO8abM&{`YxWWLWq*w8r5bk2v^~E-*w{61^PVw+%O*3ReM>`!))p6^EWxh&
zxU__=SCx0)B{tmC1p(uk$@L<`H|L&>`8(jl7j$@;V`ds68OKbmAN;XUZfZs>CRRdu
zm{SR6KY?;>G4SvEW=&e&6?G41ohyO-cmOlAOgqQb3@V1WI#k+;$w7Y(dJ?$fyq7X3
z*@%5HvoTJegovb|2QQJ
zFN8+*^NaNl>Y}_H>MLA?tpuq#1yfCh6$1lnoM(@_NAeQcYNa#Wk=!3&bLhPKSPDRxGNeDY`>!(3
zy@`{|wJ}`Tm(O{L2>{EKDQ(JCQ`H=1-2bewV6T+LG~e2;Yc>@flK<$cQe>m)B_*Sq
z6tq#x`J&ZrahmngLTE#;9Q^QEK$5q0Kn=y}t0j=pQLDwrlCC72i@|55`D1YDsx{-v
z%O!L84l@_=l;y2euj;H}`k_SOOzhqj-=rM$*QQ$Z1tt-Z=j-B9Wa?pG4uPVEl_4Ca
z!URpo0pE;uS3B>DFghKTN+)AkE)GOXXj&&d&^~AiX&5)Ma1c}~@yOn`G*@jF!xiZw
zDf=nD(=xow@J+XB=RHLm4r$eWlzj%$3ZDI_Q&m$XHrNGM{rcgXKj?INmUuDp#n0fG
zo(egBz*b+KYabnMzB4McsGw=l+LF)e5^ltqdG!6feND*~eC5Pwar{w{q|Ga7MZTH7
zHl|ZWBOQOH14lJgcbYmP=zZ9B42TRh+y!TUS9TR(%l&)+U0ZFJin3@L5Kd)z;g(h%
z{zQ=o`#N+-mSP(TS$OGL#`fUx&&Q&}?yC~E6XTXm~}~s2Dr1l{GCWSDJJDzhP1HR+j1K`1HDfNdwXQoK=N$<@rsUR
z=g-$gf^TFwAxECY;bbyQl!b1Jnh2UpI;h;mwhC2Te+Qp=-qEoo7QX9>W#7nXTVlPB
zlf5H$yTzpJSk+;`f+9|GYD-~r3;AM~zSq1MY*Uyg;}n>Rg#}Rl9%`~`4tQQ9;2KbI
zsMcs+9P2&GEqZM~-jZ)Lxm$(}P5h$k{#8e={IW3fzxjSb~eRH)=*QxKqW;50008Ae)GU&fmY!bx%pF(j})bjuU(D42z
zKtOgb@qbRBhn9jgpk|8v=)Vnujg+bs08pQR_F{$z00`$P$x7+?0?&e!C)k#~7WJQB
zUO$~WOC(<+2O)kyrm4%M2Gx^rQ{$kIfJ>xEEVnJe$ta_-IA-8nWM+^Ymn@Uyha8n;
zCOQUD-0dcy-glW+Hio1^5fyCN`aW-oH|>~}gyskTGvR}c=cS|fmg(c3kh7KAmCpyO
zCP4vbMxOy+J69HJyqkX+o!S4tO|d@_bt$hd~7MfSp0DMupWF%F=><^)|A>XgR
zvqlS4%I^Eh(qSqqvvCv&=8vSVP&ExJ?_@Tppsr+ndOgCzK2*Nb{ih$V!rbjm_cS}l
zy!US@__9{~fzI~%FKp=`0b;*&onOhi!5s%RHA+Np;uwxN74B|;DAOvk?XUJzt
zg;$4Kv84hkbyP}L`mOvuD|;yrDkvK%_}?oFf9F%!k*6r{anr5NU1JxZqc+vrjk_^x
zwhmh?zy0F~v^vB7S9(`vGP>$@Kv1$rFqpIScJCv8gKBt|n3C~eT`7w$L
zSCim|sh0_knveflSo6H{uhanM)<;H(*M+Z~r3D6fUtCS-QCDlg=e_1F$n9CG^<3F0
zl=vq)EF|bK)QWJry0+$qVrLBK&rJDrberuq1FJ*tZRwk7q4lA~cxt4<_}lT#XRoO>6mNc9V8hj3BvlwkPUOSLBE7eceszde&-r%E6Ld|`U|pF8F56Ah_xsY)rTR*YZ`WO*USk$ChJ&!^od%82^@sxoY6@sy+s
zj(HMcEm?w*N0rabzkiqM+$_{(Z8q&lfU;p1n-_iHv3o|x{r#aBwK&}T_^AG
z-4!c2X2tXfrBU0^*}mWF04qjn?Qwr7iuAIkWB$4@u6Zv8t0!?Fi~z>L)_QdFek!o>
z^lv(F-vMju1nQkZPCD<_wzk5Y&M1p|!lridOu?H5EpxIqKpv1SIvXpy!apO784fi_
zQYK!H&Wq%b<@m!D^kx%$vyOGT4hX_u@&{*2Yowr)t$+L!Zu+CJhP++F$3v!xAPtG2
z*{PgG6&)OtIng?9}iK62h|6qLe=N4XWX>=eC+-EMp|5GQ-5b7G`-;d@n3
z+&E@ra83H@-+6v}b>bSf$E1SSNdbxXMvmTqt`D8?9hnx|?tg?GPRBe>$?Kb{@!`{?
zZv1m&NAM))C?RfHjyz}GmCT1FTNN>1wFHRvD!@vy)+6_&*rEoNf54VC-7#f~*^Z^QIU9idoR-Bp<91L=4
zgs=Ig!dG!$meQ7)yzJslEk4^HzLlRLshrhSmkf`bNFwzZpZF3#0KcyiW=$$gh*(>8nkIp#B#_fy#nfY;dZz0d9**`
zR_2NT>X%}k9{wOxm5hdX7{+9l?BY-L3
zkh{;by?QnRhaV{{DYBSf)kd|tI=Oo(6UjB;-&w)?slg_edg9qd3mR6Ui
zE_B`Xo5y=-ak9@f#Lmo1VI5lpYGE+~nBp)x)z9OSrO%SuIlNuNiP_qQGlHk+f9
zS>7)nw-8YMGp{>!(WmWsgVyVrAk|%vQT#$rU6@!|
z8vmt`e^zD%f33Rc=vy?5z0v;+Gbx?}0Aun=&-)6;XolD_F*S;{A6i9y<7yf7)4HxP
zjTB?ZDN-MuKx1>mLgNBtE6ffffr58RUJeTx5Vx`m=4F*?83D>F8@urW-7(Oke@u|J
zyaV0x15?*B4ZGbTp;L056e-8j2>3={WV5bo$g$ew?Ut{)RCnjDMjd2Vt0
z$Vy8b?Gv8#{X9xOzfk&y%pY9n`7KW`g}2UvUyZQ$ky(UV($kNHIT3_2IA-bp#<-Lm
zgn-VYjU?S&+tk#s8+U{XsjG^tzA68K9Zt&bKNaB!k^wUFq#y{FftB=dZ>q%!rs
zd9cuzMDV*0aJvdBs+4;+)|w8jR1N$Fioeu`ff-j_e{{dM!;!V*@>#QpyfWVlv@>*c@_F4aOete?d2$HnU;j+ip4@O}sWIyA)QX
z^nmOE>#M)BlviMjF?CXHqf
z3ditB=aE#kPPH-eqX-1OTodPZL32ym+rGzG1HugY^qfUddX6}_LWG8yz1hjoJv}ZE
z9yyu=cjrEfskXK@<*SDVz4|D(zQ5#=)16B&IYKTUIBMY?D*L|%QC5UiU#TmEsa!l_
z7ZO=fjF0iBsEWs}d${l2mT;Ffcn@HL)Ejuh*t30;CRY2_N)$E(CJZm|ok)3(Z0PqM
zOZa&TmUK47?_SiQB9_ngwxh01z^dQRKh;A?N0RH{cB6{_Wl|5!BmMZWG8*sZ=zwsb
zZ*AT^v@D?!ldEZscf`Q7i^9}BX_~r+q+5SLb<|dw#Z|#*@QMAx=VdG;$maIeDqlC+
z`GMS9-yfY&Kx+Nt*Su0C;_;22>`2zmG6yG6r>LJ6Pbs(F_U2ahp9)ahxy)>GAzjrA
zmq%4;qu?xFp4R*FT@%V)lzr#hf!_P@arKT4{*t7KE2$+4@Ou62=mms3x{^g
zQr1oY@6;SM*=uAnQ--LPX}Tf(v@xT^B`X9rq}+b(xM
zykT7Gt4DV246YCyDlQfwMyXNB!KdPQ{
ze=F4odn5j))hdUPlsk)^vR3UPX8Hrx24g|Owwy?J6}4_NXTuyvcd#H0CVnWcEM)4N
z68C8Xbt4Dj<1RlO&y@(DB3xQvJBsr7{cQ*jAtug-%Ery-wTa{|uU`pxld!BlRxiGf
zoB~GS#k|>SnuZ=q*QOYi>w$P`xqL5gcW@_)h(3Ffz!|3Kd7_jce&qI|St4XFa#fDq)JDe0
zK4viX60D2KSrL2N{K9*vcS9J1nBF+GR8M&!
zI!thFmLiX-K5&ygEz?`Ed79j?8sKAhRZipR*lDY`F{Yp63}fDnxQFk(3skM;q)?;ba#llj#?TfQhSj%7
z*fp3S$Ja^;^K`}v>saDjF++-!R_MI>sf5}`+|XQ4vV7fRIm8*Zd;vg0v&Nqw4_n4~
zgN7NVr#XrkpB_RS_4Jy*4zjfc-Yy0E6f6(C5zhO(!{}2
z4yk;<;BBEFzZ#rb3Dzmgv!JDe5Yyz7GKBYhQa+l&lMWvB)8+fh6s4M4WNc!Px??l4)N
z=r&>`9J$dyiOFes{`tcke=JFT&y&$mHudPn=e*+vMHT6-
z$h%NDVe?bgaLtPRQUS%ow$=(InB*hN|daaCVZ+=)w`&zNQ2zkq^ua%C~oVRSA-NH
z%&rX*q9k^l`DQ}H!PIliQ4S5VslVK^({N04(ljNg3s)GYe>dHcQ+rU1H>^D(efQ31
zo_CZBU8Ji!5$~NLx8pqI&KHfA9KVBMnqF7#gn^oqIjYL7!~yh9I_r}0Kk4(?68q{X
z3a$B{doVEEuXMdx3`I!=fgUkCeVfc*)Pj!eM7J8Dv0!x2t!6MuEC0#w&UA|B+P%Zp
z%clUvt-GM#FantJO(-kIJdLtJi?!=_3;dw9{7@7r)v%;HiCF-{VXf;|CqTEeoWA7Z
z%%1$a+ns40yd2p4_zwH8Rtf@7W|}+R7xuyfg_>j&FB_3QhD5XeA=?@-laI%6!;Z9r
z5Gl6qhbT`pM}73e(eXr}c~moBlFdS?+NEP?M+=S;HzzXgJ|`o7ohL2vKyZAp<>D!(=v9Mm~n6M-%D;BpjIPG1gydf{sga^W
z^H!;T&!+3G_W%NIjtgTgU+{Zrg%OHi7sGX6tn2%i29@p7lH-4y!5Jy6ojkXucJSh+
zoUzDgD&sI*m^Tg{4l#vT<_dR!*PP#aH*yw@kzY+?R5LY2ciuv)Di;YIk~vDgrDc@W
ze*R*M7KcHiK^cZfq$AmJ195%5eU7-o_+U#e>-)y-o5+pQCR8mQC0$+e?J{ti?p{eY
zwS2Q~{~$)1RckKFr0ywO`%lSTWSO_h+qOw{Bz0FRNor*~iegLWyxs}3U){CqxWXOm
zF7J6H&&o@rMg&QGI@pzeo@}1_$l(Q1uw(v^L7LT6Al|pP-`%3r&y?FU+HNT%J
zOD*hgE1Tx~Si0|YB;Pj)G#^VMGg~%+?V$0MbSdSP)Otj+$ahh)giZ)YYo_3W+6;OP
zQ+s56nwieDA6ZHPpuS4)K@*~vzM4!-F;OFq$L~na#VtR9QD}u6uTX2BRSzEZ4&}E-
z6rA;eQY@d7W;z!t+lHYb`ZV_yUYWk@f0{v7*vh2~uNLkj@p$-e`nQ
zV=dn3S>ixJ@w$AX=OOUa!
zVobR$RoteEeKP4{q3F)prS6d9^5QI!f1lHuQN#ta3k?O!DZjZ1xkUSD(ZP3~;g2;Oq>SZ!>&uA&?5nJi2vEiMiMEVZmDibq
z2F5;VA!Cob;+OYJiDMspQCkhv9M85;z3qGW^L*pr8-hkTcfT+*NMth6)vWER-|?CS
z>2xm22kbb{fP+}Sw|-x)iIgI(Y-y^xlhI+mt3sSt4QtG=xke-_B!iNva>ymMZV-7g
z$!b8oQ>gdu(T#$C-fq-jNjF<9m9+?0EE*
z$0}9oju}*)y~gbxM9lkpx@gYPW1&`*vgw@n7WY+^Jp6G771boB2@!W~FLZh!4YRk2
zd0iWB?S&Nr=oeg^uM4xkagIGgQJVH+r6%4n1^m3m$61c(->G<&Y@i9xcnoFk7VL$&TZ^pV!NhHFk=!|o_>y|O#ccpBEDl$xQT_LX22akw$AZQD0G{i6UCpyyR-D
zT$swTZ%M!drGYyl6(RKPXG~ZxvX3c|`JsK3n|>eb7kmr7T;AR2`3=m~h*1T7YI=ma
z4FAGAq)&r8;;9%8wt8bv5kG%rl=0LZ9hEW%R6Rb$F`OLATlUGtQ_8a*%R388Sd
zdQ;#cgeh=vP+DV0?NfN)KbSRA2NMGlx&o0LdvWCp<^OTKrx?G)Y<{mDuz=N&b{J#0
zSrh;ax!WvVvLpi7)9-<3jw#F?+^#B9RU+JAfVTl{sMi)#t)JCZb_nxkS5=~DFLP$uK#^)ZbbC3FHDX}okDDA
zn};6(l_ZQoeYroZBDCR&V2ffU*mc_5vN$NG63lao)9xqB6HabXKL_2xF+MVUK&>dn
zksWYey@S@6Dieq*XBkD5mRL}bf4Fz)nlIKVyc?z5U7~7Q3g^_&va-Pki;@4#sR?`3
zn8S>#PqEqqjJR`-xPe#HMXmnwNX7!5jCm$iR!41M{>cf|#T?W^KQ&7}uCg(MxU|EeL|1RBcx0Z#SF{c(-y2x@BZURdXF@23N=nS4$aUfBk`t
z7d2&6IohsiOrN@mgu?oB>KB8w%VUu;u?S9$Oj^5^an(xX)gSUvnnelr34ywpKN&9w
zf|&+*c&e86f|W7JmrBW;3=^V~nw@R|*=e>bWUB~#S9qjn2mO6d3&ZP{NIU^wsO0QR
zKE%Z=S&%$Luc99>r1>~DY`Ge`+Oe_)9XLFW^^i=k@@1d438DLGLf31u5O|l0A!0An
z2X&ks6p!$7F^Fnm53F^wLL}oA??BPAv+)`BLe)GLaZDIF&Z(oEt3lkP>+BZ=L^l~VBCnm+|vKuQSoHl0VY{Qr>|A>vgA
zfzFU0(&R_7^}CMk>u9tLGPD@x+?cPaH4Pw3gdV97%OobDAiXUA1%k(54S+t>phP~2
z%&M2ugY-#HEP}qj>*YoipiSQER$4~q-}6N%>s8A;DXZW9PI}IL--&f$Ja8y^`-rU?
z>rIE8xrNFn5_OBVmdGAT9K886%0sU{TkTqrPiIm`+`RUDxurYTUFHrUN3$g!($Q
zSo4q#^-{1OCLIwba2m2Q-N5uF?u1hA
zl<4JQDB(N|th~a09#;Z%)jpSk&RN-JkCz3h+2H2w;yQzV4wZgZ-&`XqD|23~bKM&`EddOPY)o%x0I?ZCH;tdX>SuKa
zXlxiRML$W*-r6strk?)LMATc{zLTly&Jt`?W6wwXn8G|>-vtMV7nm__=()ZZet%tS
z)VRH#b9iY~XY{{6A~!AtVIk}B#8@<)@bvHV4j{mYm=g4T9zQs}RqqW@8YHB$Uc$VA
zqkT*ml&oji4F-0e*Z#O!^$D_aGeU>9AVuVqM{*qrsB4C%k%tlNE=n|0bdACP`HYq_
zp;>iWEa%d?yMObaW6^_XWGcj{M4{l0c6#XJC9$b+8cjh)E(_-kXwH9CM6_l0rlqI0
zZcn+Rs!C>m`ceF$v-iE<I
zGz5E^*x@vP^$s4ih3#e~Z7$NBG<%JAjSe2guv0o8sdvr?3QYG%JQrQi6rQa;pfqCd
z1-0MNx15~(jZEFi@j*0aUbxn*PG73tZKfRmn7!ymt<SE5?`JZ(Rx6gQ`u<81Yzh)i}84!=0zGD?U=v?;E0V+X?Zu|VqWhl}ciNAtQ2?yaBv*0JdGa5$>;
zD@&`!Oo}1`DSXaF#8(c5c##^WN%(;sH^^!$@@C)-vWXtB+nGzG?#F+Z~<@c)LW-dWTbGMS-wU;~8L>^?24woz#~L$w2~>Oq}#KbO&|Tc^7cD
zGxyl{=ZJDo7EWQICqhj~FRK4~H$yB?$WNQ?a;&&zw!h5aw&l#VTYgWu6!IS8csxu)
zYU$j)WON_0qC-0soaT+RFtvB4OQURX9c8({i*X){vC|b<0&b!1f^2;QFl?x)zAo33
zCm?T+-u6t999I)0d=8<)ne>PvSlc6If4Nm-S(^1@L`pG(2MLZT&K#aM0ssuPz47KZ
ziuZ~Cebd}}v=}Y9R{*=)hYP%tYsOUu_-Sr8w^0WW!^is?Iw#)o1tP0Zq72O*KXUDV0}QoH+y*ceddeEppd
zha`+M?n^6xO)LJcTR~_qOTfX)OjG*_?#P1b&O!&n`v4$w^$6DfVlZQ8{Sz%g*O}Fi
zS{L-~vpFl`#9a>8>4pezds4>7J46MYuRr#AL0-5{R_cNZmvifDqxKAbVo>=7U*i;W
zmp98jRA2<3>(6@dhFkKZW8s{bwQVycsaozlZ-L?DqN0=}>bkgeH7lh-gSqj%{!=uZeMR9^M>grmNrsR=*TRPW
zG{8qBGSPDZ{kW~Dn-asFxF8AhlT&>MUSfUK1ERWuSd-BdRuJ6U;}t!tGB*+WO;eN{
zSdZRo&0c3((y;YI-toj1paIZ$XJOE_xqKom;bh%1jg;LdraYm1XMiq;6BQX0y*TH$yZ`9wf9
zzy=lVgl`DY2&zXlaWa>yY|)oayAp*OS~#X0A07k)>pHO|{s`cG@)@n1L_nPe@oiCN
z$SEf5zg9f&oB%XVKK6b#7I3Q)-w%8i=iHjHo$kVQsYLas(P2f4aC`1>#-;|@=F*g<
zN6#Bg*Wyt96#~$Yuz*v#x2RwD@aJ{a&4>0Ko?icZmmO_U&519Xuh2uAqwfrfpegfw14S|WWFXuJybUuvH3Dlc&(x2M>x|-TE-|0Cm+a
zC3CseD3Vk6Zidl&f+*I2-xIR>_T)-|iWTG7ha6dYgR3)1I25t}SS$o2cpdCmWIWn>
z+AA>$SK;Ef8=dpO-Nbal;c)zN0xxdpe$|d9M`vPv8-}QInQP0TotUJ%%~m1%z#h~D
zy9}dT%RXK25eApW1}0jL8h5ik0C%|%HN0(meI^RNc>*FYCmNQ*gMtSMT(Aoym1E5o
zl!QPP#^!KDn;7yMP8@b+%GK*Y*K6+x)cer}s>mY2aAmW7{A&=b{L^q4ox#N=y`4pt
zp-=3Wjm{VCFIclgTbQRGl4;4Jd*i)|1-bWZlfS$dA~>S7pB*BEWtHyEG(u2evWn|5
zX4lyvp;spt-{EavKxJbJ^MC$qBrlb3Lmc
zPQYQ;wIJag4|v?)vj<1No42-)0v4Yv(>1h34p4AI*UDLxoT$PDW)0wupkp?R)0*zn
zuoPmTsv5oxpRO5s_B91Ga#`X&hZ;3HTqybn%HhrjzD;WPTa9)8`$TdonFc5Wr?t-7
zf8OC4EuB=pNml`-7HbuMJR}EwT{ejjsWakh5@B{9)y7`EB~8bg-$y>H*BHh>U7f>V
z8Te4%f{|%Ju8fgqEh4#^F^pAZ0c-e3d_*HTsRe1gK~VAg?cx!1%SZi1*`=XD{p5K9
zw)O>~Jdcg3l{nX$NY=VMfL(~NeYR{lH+oW4u`EGaFf)sKae4+K3d@{BU}?k>M&OAJ
ze-2_pg23Iu9a=_ni*SIirdii=r6YvCO~VC^tqBA$Ue6RaNCT3Pjpu
z_2(f0;Dq4p$MVoE)JsvIdhp`|RNa1v=TP?H8JfD$)0jAT_qbf8m=5~JX(!vge{Reh
zt&;4fR+}F19-9YB1pPlUo*_ep@u40`5#p2qoYM%Af&;7y!4!IWb8y?;_;7B?r35Swze=Ro62e6rM+!kgrm~-VGH~wF
z%T!k4$)M+6a>)piM`!1RyjHzOSOa-nwnU~Oc@0q$
zFL!WyYE&kGb%4YK5nwgl&BbKQsaw?t_0Wi3q1l~9;jIrie^JLP^ZMwd!XY3nNq~!==mOtzu98i~9>+mblZ)VON1T0@a>R
z3hs;rSag${OkxYiV+X-jPO9cUTM7ERN_iubvv~ieMuWv@$dS%kwVV;y^@+$%)T0e%
zRV3BM)w-4-M#|8Iu4JDuoz%TET0$+#q+M53s*u#mLzjI*e}l3JqLuJ19D(N&H#S0(
zJ`+5llSGgjt=fEFY%04!6+CWIO=v_`hW)Rnps{m_gU{W>vp!WtKLY
zwoI&@NMTrC#$psArBiQz&KdHX1ls{!qm0do!|9cGzLoZIcPlx#5dXdwKcS%k@d?at|82LR=PeW
zZ!K6G)oUXyoe`K2Rw+u;uD=Xl#tB3k?pMLTu3Y>XQ`V%cp{W>5SMj%b-LQNjMVd
zI2z_dS9O&?8I#`@o*X6HLormbio^S$QOV
z5*MQ&HbA4t4`e9b*m+1pokfr2{v|=8
z{3xWK`wG1(zMf|4d4eVg-Mb-=M40#z5u94J)@N8=RL^>g*x=)jVO>XII-!+53t?R*9gm;*B;{RW44jV!jh@DGMQ&4NGB|*Vm_c*k9MS2
zO4T>o2fFlrA{hn@bV%`25`&aTagvX;o-qXxPDRc3n5MYANS$U2<0MsY_Osg#+6)0+bg%{JEwmNCz5V2WRmkG16ogCu}qxkoE
z>k#oCci!Hg40?FjHxYyA;eg!Q2h22?B`>l25&{0A^up&3zfINI_`^W|V4#hjLuDoX
zU?9C-MU0H~3rfHIhisMKSMBa=b8Y`a4q=NlZ|LhtRyv7@PT+@SKD`lUI=svhvD{gV
zPXT`#As6oO$x1yaUjCsY73~YC&+2J1i$#r5vCF3Fx5$G(uIQ?wb;2N?jECntpPpLw
zUYf~IqX&=zGWcEb4ht~fihR9tNfWgc*dmgj^R5u_4E`Hxa*=eYZnVo2p)y2^5-GN^8eni=ic3i`>&uT5$Car{~;pxfnUv_=*9Vnw;xKUjvI{q
zPP37$Jcbts5+yrsRiwW6*{gEf7jUT!3CCZZ;%nyG*6
z%_b!e`Su<6*qZ`b{NI+i1HZL54hPaLq#(8t077}eK?0Rj2O?Srj0pieB)YoDqWF)1
z6n@qWnv0zLxQ`8xqdi}88|Ra9Pu`ITvyoXPs`*w6IQ#OP^1Y;@`yXzpj0=Q;ub^4E
z<@P4veZ!M`^wmFtn+B4Rv^etxSttg|^fPX|SZ8wiF0C~ZTxv7i;#MwshLp6^{jqQgVyu1v
z{txj{jt9SyOP8684l-fWciLh~lE3B_AxA5hhPVnWy@I#v?{%omoe0;a`
z*m*&h*=V#IP2dWi3+s(?BIx}1kh{@>3uHm7G`n^cKkF{^>)iXHqn0qRY(#MY=SLZr
zql=1n(=5Dq=X%|eBTAX-N9!*1hx%MD&$tEPddLV*D^pdJGwAIm
zk<4Hu{>u*c;Ws36ZyzWdGw`6<=Jnxt?m}4t`C;%r#JrRS@}U-C(rRdC!q7M)uj5eH
zBxR6C=-WqY22|oTgV(D13WXvg-}?_+?&J`4otjS5-wBjwnl3RT+heJqfOSIC+u5hv}&9D-aKuj`I{=zRKKhI@6p^R+8bmR_P
z?s!3@CpC;-GC9MU_z1ZV^U#?94f6zrhZ15ou{%%4qazHAg1#>DtImxhslsM7bW}tH
zx;nWMD{B;fv{_7PZUQCKxQ-d0GT%}V#F5HQWfndAr|RL&kZTmaM@eyW?J^bL3noH_
zszs@x?%!R(gVO;qM30s{dIf-Ws0NR6iVoKF95UeEEXpAK`Hq<$7RB*rLFl35i}aX+&3!rvHnaI
z3HSg45rc0e?MXP3#u(Rn)Ia;(>77d21%FXqCr@s@uF#5npOWV+-qe!sBGg(4fiCm7{0#cOECsk&-1(dOPxAuRrakKL(2@U+-6;?lwM~p7Ae82?
zuMNNs>8FEh2UIToia!Y$v>o@o0;l3KP0<(xqAmG=jE2`5$_IMVbV!`R0s6LsP7^;*
zED*v5@BCk2tzEAFq`D4Fr@Z^hd+boHgFk1$H%iGOdm7vH4OhNddp;KX1N%`@4#|CG
z&bxF7KiAIW(NgX+toxL&(D~_gg_sTGm{A6az0?bc5t_zPIIK-5Knwy%BmaVfbF*32!|<-yohBK7X*(
zp?3)aP)m1oxpGE8IR@vhR-B8D7>O_#45`*gORz0faXmJ>!`
z?h7Luy3*+uCVi((kZw1~)y&JAyt3q4Ii$0sbf4Vk^-f{HSw!9^Y#%>8Dw0HDqo%|a_>bV-Vw6c2+MpUN$93~W*@d%xClv2XrzPppL<5Y*~@v@^1
z+3~6)?bLkUgr(*bkHS?gY-q981Xfw){
z>F3Lfp07iGB=~!F_fOM&XH|jhvaJR&eUHfbiaeL1|InB8&|q^FjD9%PJiIBR(+d&w
zM{;3p&;_HhFQz!e*LMk+<>b>!k&NJR`UlLU1|c!Dso0?|az$Y#YM|&(7f9LqO$!
z#y91~3b@Z}B3e1?^hcTs>R;gMuFepn_;@@hP4BeUfa@QWNB%e;kpKDw;9lJ@#@y9-
zWa;~n$!D&fsT?=fQ*i?J-KLdpu?o1n$oMrwz0(Xpd=VBTbGK@IAdaqIKuMJlZgAx;
zX|}u5C(qbPka)*X?`G*D#B%6#u!SWOeRNT*+?CEt`<)}>B$q!LhDo4VD=t5SgdF&5
z--WeEn=%rr>z>O4#edt&_)7SGDlBEgdn+*?@wyT9kK&FK`Fn
zArB?=81Gbs76xrdpLz&8Rjddut`7JMN6e9#7$2-iysi-pj(Ok9#hdWO2XUZ|G
z4ch2z%(DrS8TAkzo(PzZ#QY{l@8j^Qz9RQwuTt0b+a@qE`F&ek^YXfEQ_$}Bh`J5?
zk9-1$Ig#Yt5=9$gv9vcj5C6AtRu9ni{U8%%G-~5#<#Yz{Kw4<56%+ma0(iB6n9fo4
z@vU)s%@7z^b9UUqGl9xJ2GIpCH#C|rVh~7i{abGOh8-qFT4*#;uk*SEWFg5~`_tt$
zgZHvA)?=dIxj+<;U=nx?s13r{irI8kRG&|te75Wa3bXx_SS)xD*d>i{gjdleO6Gu9
zyzfyjGQDA{dS}!98Xq0Tml}VE+I%@Xt2oQD2#?vCBPh=jS^XjTNN4?{VMr%S1<`0)
z1e?{zquxeYp%Q{7KuBF#*G7Cw-&4TJ)&=Uy|DWgie~F;hXYcSujNbwtn*X}|M_dIc
M$*IZKNSlWKAKs!CEdT%j
diff --git a/third-party/chrome plug-in/images/16.png b/third-party/chrome plug-in/images/16.png
deleted file mode 100644
index c26df616ffb6e499ca93babc7417fdf7254cfe90..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 8238
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