diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..0cafc1cde --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.venv/ \ No newline at end of file diff --git a/dev.Dockerfile b/dev.Dockerfile index 3fcc0803d..ed3631516 100644 --- a/dev.Dockerfile +++ b/dev.Dockerfile @@ -15,4 +15,4 @@ COPY ./ ./ # Install dependencies RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi -CMD ["uvicorn","--factory", "langflow.main:create_app", "--host", "0.0.0.0", "--port", "5003", "--reload", "log-level", "debug"] \ No newline at end of file +CMD ["uvicorn", "--factory", "src.backend.langflow.main:create_app", "--host", "0.0.0.0", "--port", "7860", "--reload", "--log-level", "debug"] diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml index 25cddd9f7..6a9802e38 100644 --- a/docker-compose.debug.yml +++ b/docker-compose.debug.yml @@ -11,7 +11,7 @@ services: [ "sh", "-c", - "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload", + "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn --factory src.backend.langflow.main:create_app --host 0.0.0.0 --port 7860 --reload", ] ports: - 7860:7860 diff --git a/docker-compose.yml b/docker-compose.yml index 961cd0e33..13d39e1f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: - "7860:7860" volumes: - ./:/app - command: bash -c "uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload" + command: bash -c "uvicorn --factory src.backend.langflow.main:create_app --host 0.0.0.0 --port 7860 --reload" frontend: build: diff --git a/docs/docs/components/embeddings.mdx b/docs/docs/components/embeddings.mdx index 644d91fee..5b134f08d 100644 --- a/docs/docs/components/embeddings.mdx +++ b/docs/docs/components/embeddings.mdx @@ -73,3 +73,25 @@ Used to load [OpenAI’s](https://openai.com/) embedding models. - **request_timeout:** Used to specify the maximum amount of time, in milliseconds, to wait for a response from the OpenAI API when generating embeddings for a given text. - **tiktoken_model_name:** Used to count the number of tokens in documents to constrain them to be under a certain limit. By default, when set to None, this will be the same as the embedding model name. + +--- + +### VertexAIEmbeddings + +Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) [Embeddings API](https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings). + +:::info +Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. +::: + +- **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. +- **location:** The default location to use when making API calls – defaults to `us-central1`. +- **max_output_tokens:** Token limit determines the maximum amount of text output from one prompt – defaults to `128`. +- **model_name:** The name of the Vertex AI large language model – defaults to `text-bison`. +- **project:** The default GCP project to use when making Vertex API calls. +- **request_parallelism:** The amount of parallelism allowed for requests issued to VertexAI models – defaults to `5`. +- **temperature:** Tunes the degree of randomness in text generations. Should be a non-negative value – defaults to `0`. +- **top_k:** How the model selects tokens for output, the next token is selected from – defaults to `40`. +- **top_p:** Tokens are selected from most probable to least until the sum of their – defaults to `0.95`. +- **tuned_model_name:** The name of a tuned model. If provided, model_name is ignored. +- **verbose:** This parameter is used to control the level of detail in the output of the chain. When set to True, it will print out some internal states of the chain while it is being run, which can help debug and understand the chain's behavior. If set to False, it will suppress the verbose output – defaults to `False`. \ No newline at end of file diff --git a/docs/docs/components/llms.mdx b/docs/docs/components/llms.mdx index ccca8fdd4..088556d2f 100644 --- a/docs/docs/components/llms.mdx +++ b/docs/docs/components/llms.mdx @@ -185,6 +185,28 @@ Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) large lang Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. ::: +- **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. +- **location:** The default location to use when making API calls – defaults to `us-central1`. +- **max_output_tokens:** Token limit determines the maximum amount of text output from one prompt – defaults to `128`. +- **model_name:** The name of the Vertex AI large language model – defaults to `text-bison`. +- **project:** The default GCP project to use when making Vertex API calls. +- **request_parallelism:** The amount of parallelism allowed for requests issued to VertexAI models – defaults to `5`. +- **temperature:** Tunes the degree of randomness in text generations. Should be a non-negative value – defaults to `0`. +- **top_k:** How the model selects tokens for output, the next token is selected from – defaults to `40`. +- **top_p:** Tokens are selected from most probable to least until the sum of their – defaults to `0.95`. +- **tuned_model_name:** The name of a tuned model. If provided, model_name is ignored. +- **verbose:** This parameter is used to control the level of detail in the output of the chain. When set to True, it will print out some internal states of the chain while it is being run, which can help debug and understand the chain's behavior. If set to False, it will suppress the verbose output – defaults to `False`. + +--- + +### ChatVertexAI + +Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) large language models. + +:::info +Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. +::: + - **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. - **location:** The default location to use when making API calls – defaults to `us-central1`. - **max_output_tokens:** Token limit determines the maximum amount of text output from one prompt – defaults to `128`. diff --git a/pyproject.toml b/pyproject.toml index a3b7f9a28..b9d514546 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ unstructured = "^0.7.0" pypdf = "^3.11.0" lxml = "^4.9.2" pysrt = "^1.1.2" -fake-useragent = "^1.1.3" +fake-useragent = "^1.2.1" docstring-parser = "^0.15" psycopg2-binary = "^2.9.6" pyarrow = "^12.0.0" diff --git a/src/backend/Dockerfile b/src/backend/Dockerfile index 13f2dc62e..8257d89b0 100644 --- a/src/backend/Dockerfile +++ b/src/backend/Dockerfile @@ -11,4 +11,4 @@ RUN rm *.whl EXPOSE 80 -CMD [ "uvicorn", "--host", "0.0.0.0", "--port", "80", "langflow.backend.app:app" ] +CMD [ "uvicorn", "--host", "0.0.0.0", "--port", "7860", "--factory", "langflow.main:create_app" ] diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index 63e8cdf99..d25893c25 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -104,6 +104,8 @@ embeddings: documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/sentence_transformers" CohereEmbeddings: documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/cohere" + VertexAIEmbeddings: + documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/google_vertex_ai_palm" llms: OpenAI: documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/openai" @@ -127,8 +129,8 @@ llms: # There's a bug in this component deactivating until we get it sorted: _language_models.py", line 804, in send_message # is_blocked=safety_attributes.get("blocked", False), # AttributeError: 'list' object has no attribute 'get' - # ChatVertexAI: - # documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/google_vertex_ai_palm" + ChatVertexAI: + documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/google_vertex_ai_palm" ### memories: # https://github.com/supabase-community/supabase-py/issues/482 diff --git a/src/backend/langflow/interface/initialize/loading.py b/src/backend/langflow/interface/initialize/loading.py index dc8188ea5..c315a9577 100644 --- a/src/backend/langflow/interface/initialize/loading.py +++ b/src/backend/langflow/interface/initialize/loading.py @@ -88,7 +88,7 @@ def instantiate_based_on_type(class_object, base_type, node_type, params): elif base_type == "toolkits": return instantiate_toolkit(node_type, class_object, params) elif base_type == "embeddings": - return instantiate_embedding(class_object, params) + return instantiate_embedding(node_type, class_object, params) elif base_type == "vectorstores": return instantiate_vectorstore(class_object, params) elif base_type == "documentloaders": @@ -147,7 +147,7 @@ def instantiate_llm(node_type, class_object, params: Dict): # This is a workaround so JinaChat works until streaming is implemented # if "openai_api_base" in params and "jina" in params["openai_api_base"]: # False if condition is True - if node_type == "VertexAI": + if "VertexAI" in node_type: return initialize_vertexai(class_object=class_object, params=params) # max_tokens sometimes is a string and should be an int if "max_tokens" in params: @@ -261,9 +261,13 @@ def instantiate_toolkit(node_type, class_object: Type[BaseToolkit], params: Dict return loaded_toolkit -def instantiate_embedding(class_object, params: Dict): +def instantiate_embedding(node_type, class_object, params: Dict): params.pop("model", None) params.pop("headers", None) + + if "VertexAI" in node_type: + return initialize_vertexai(class_object=class_object, params=params) + try: return class_object(**params) except ValidationError: diff --git a/src/backend/langflow/template/frontend_node/embeddings.py b/src/backend/langflow/template/frontend_node/embeddings.py index d466b11a4..4e7e25112 100644 --- a/src/backend/langflow/template/frontend_node/embeddings.py +++ b/src/backend/langflow/template/frontend_node/embeddings.py @@ -5,6 +5,47 @@ from langflow.template.frontend_node.base import FrontendNode class EmbeddingFrontendNode(FrontendNode): + def add_extra_fields(self) -> None: + if "VertexAI" in self.template.type_name: + # Add credentials field which should of type file. + self.template.add_field( + TemplateField( + field_type="file", + required=False, + show=True, + name="credentials", + value="", + suffixes=[".json"], + file_types=["json"], + ) + ) + + @staticmethod + def format_vertex_field(field: TemplateField, name: str): + if "VertexAI" in name: + advanced_fields = [ + "verbose", + "top_p", + "top_k", + "max_output_tokens", + ] + if field.name in advanced_fields: + field.advanced = True + show_fields = [ + "verbose", + "project", + "location", + "credentials", + "max_output_tokens", + "model_name", + "temperature", + "top_p", + "top_k", + ] + + if field.name in show_fields: + field.show = True + @staticmethod def format_jina_fields(field: TemplateField): if "jina" in field.name: @@ -41,10 +82,36 @@ class EmbeddingFrontendNode(FrontendNode): @staticmethod def format_field(field: TemplateField, name: Optional[str] = None) -> None: FrontendNode.format_field(field, name) + if name and "vertex" in name.lower(): + EmbeddingFrontendNode.format_vertex_field(field, name) field.advanced = not field.required field.show = True if field.name == "headers": field.show = False + if field.name == "model_kwargs": + field.field_type = "code" + field.advanced = True + field.show = True + elif field.name in [ + "model_name", + "temperature", + "model_file", + "model_type", + "deployment_name", + "credentials", + ]: + field.advanced = False + field.show = True + if field.name == "credentials": + field.field_type = "file" + if name == "VertexAI" and field.name not in [ + "callbacks", + "client", + "stop", + "tags", + "cache", + ]: + field.show = True # Format Jina fields EmbeddingFrontendNode.format_jina_fields(field) diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index ab9de7f63..0ff77cf45 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -508,84 +508,3 @@ export const URL_EXCLUDED_FROM_ERROR_RETRIES = [ "/api/v1/custom_component", "/api/v1/validate/prompt", ]; - -export const tabsCode = []; - -export function tabsArray(codes: string[], method: number) { - if (!method) return; - if (method === 0) { - return [ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: codes[0], - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: codes[1], - }, - { - name: "Python Code", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[2], - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[3], - }, - ]; - } - return [ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: codes[0], - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: codes[1], - }, - { - name: "Python Code", - mode: "python", - language: "py", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - code: codes[2], - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[3], - }, - { - name: "Tweaks", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[4], - }, - ]; -} diff --git a/src/frontend/src/modals/ApiModal/index.tsx b/src/frontend/src/modals/ApiModal/index.tsx index 307e48208..8410ee7d4 100644 --- a/src/frontend/src/modals/ApiModal/index.tsx +++ b/src/frontend/src/modals/ApiModal/index.tsx @@ -22,6 +22,7 @@ import { getPythonApiCode, getPythonCode, getWidgetCode, + tabsArray, } from "../../utils/utils"; import BaseModal from "../baseModal"; @@ -48,39 +49,8 @@ const ApiModal = forwardRef( const pythonCode = getPythonCode(flow, tweak.current, tabsState); const widgetCode = getWidgetCode(flow, tabsState); const tweaksCode = buildTweaks(flow); - const [tabs, setTabs] = useState([ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: curl_code, - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: pythonApiCode, - }, - { - name: "Python Code", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: pythonCode, - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: widgetCode, - }, - ]); + const codesArray = [curl_code, pythonApiCode, pythonCode, widgetCode, pythonCode]; + const [tabs, setTabs] = useState(tabsArray(codesArray, 0)); function startState() { tweak.current = []; @@ -101,80 +71,9 @@ const ApiModal = forwardRef( if (Object.keys(tweaksCode).length > 0) { setActiveTab("0"); - setTabs([ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: curl_code, - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: pythonApiCode, - }, - { - name: "Python Code", - mode: "python", - language: "py", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - code: pythonCode, - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: widgetCode, - }, - { - name: "Tweaks", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: pythonCode, - }, - ]); + setTabs(tabsArray(codesArray, 1)); } else { - setTabs([ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: curl_code, - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: pythonApiCode, - }, - { - name: "Python Code", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: pythonCode, - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: widgetCode, - }, - ]); + setTabs(tabsArray(codesArray, 1)); } }, [flow["data"]["nodes"], open]); diff --git a/src/frontend/src/modals/formModal/index.tsx b/src/frontend/src/modals/formModal/index.tsx index 6dd426045..68137c0da 100644 --- a/src/frontend/src/modals/formModal/index.tsx +++ b/src/frontend/src/modals/formModal/index.tsx @@ -160,7 +160,7 @@ export default function FormModal({ } function getWebSocketUrl(chatId, isDevelopment = false) { - const isSecureProtocol = window.location.protocol === "https:"; + const isSecureProtocol = window.location.protocol === "https:" || window.location.port === "443"; const webSocketProtocol = isSecureProtocol ? "wss" : "ws"; const host = isDevelopment ? "localhost:7860" : window.location.host; const chatEndpoint = `/api/v1/chat/${chatId}`; diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 42fbe8773..5b40e8c05 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -205,6 +205,7 @@ export const nodeIconsLucide = { SupabaseVectorStore: SupabaseIcon, VertexAI: VertexAIIcon, ChatVertexAI: VertexAIIcon, + VertexAIEmbeddings: VertexAIIcon, agents: Rocket, WikipediaAPIWrapper: SvgWikipedia, chains: Link, diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index dec07fbe7..ea1c137b0 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -410,3 +410,82 @@ chat_input_field: Input key that you want the chat to send the user message with }host_url="http://localhost:7860" >`; } + +export function tabsArray(codes: string[], method: number) { + if (!method) return; + if (method === 0) { + return [ + { + name: "cURL", + mode: "bash", + image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", + code: codes[0], + }, + { + name: "Python API", + mode: "python", + image: + "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", + code: codes[1], + }, + { + name: "Python Code", + mode: "python", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[2], + }, + { + name: "Chat Widget HTML", + description: + "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", + mode: "html", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[3], + }, + ]; + } + return [ + { + name: "cURL", + mode: "bash", + image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", + code: codes[0], + }, + { + name: "Python API", + mode: "python", + image: + "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", + code: codes[1], + }, + { + name: "Python Code", + mode: "python", + language: "py", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + code: codes[2], + }, + { + name: "Chat Widget HTML", + description: + "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", + mode: "html", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[3], + }, + { + name: "Tweaks", + mode: "python", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[4], + }, + ]; +} diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts index f051c2eee..d477ce539 100644 --- a/src/frontend/vite.config.ts +++ b/src/frontend/vite.config.ts @@ -6,6 +6,9 @@ const apiRoutes = ["^/api/v1/", "/health"]; // Use environment variable to determine the target. const target = process.env.VITE_PROXY_TARGET || "http://127.0.0.1:7860"; +// Use environment variable to determine the UI server port +const port = process.env.VITE_PORT || 3000; + const proxyTargets = apiRoutes.reduce((proxyObj, route) => { proxyObj[route] = { target: target, @@ -22,7 +25,7 @@ export default defineConfig(() => { }, plugins: [react(), svgr()], server: { - port: 3000, + port: port, proxy: { ...proxyTargets, },