merge
This commit is contained in:
parent
999ce405c4
commit
9d033c9e34
157 changed files with 6860 additions and 5525 deletions
|
|
@ -11,6 +11,7 @@ from alembic import op
|
|||
import sqlalchemy as sa
|
||||
import sqlmodel
|
||||
from sqlalchemy.engine.reflection import Inspector
|
||||
from langflow.utils import migration
|
||||
${imports if imports else ""}
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
|
@ -22,13 +23,9 @@ depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
|||
|
||||
def upgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
table_names = inspector.get_table_names()
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
table_names = inspector.get_table_names()
|
||||
${downgrades if downgrades else "pass"}
|
||||
|
|
|
|||
|
|
@ -48,10 +48,12 @@ def upgrade() -> None:
|
|||
with op.batch_alter_table("folder", schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f("ix_folder_name"), ["name"], unique=False)
|
||||
|
||||
if "folder_id" not in inspector.get_columns("flow"):
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
column_names = [column["name"] for column in inspector.get_columns("flow")]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
if "folder_id" not in column_names:
|
||||
batch_op.add_column(sa.Column("folder_id", sqlmodel.sql.sqltypes.GUID(), nullable=True))
|
||||
batch_op.create_foreign_key("flow_folder_id_fkey", "folder", ["folder_id"], ["id"])
|
||||
if "folder" in column_names:
|
||||
batch_op.drop_column("folder")
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -62,11 +64,13 @@ def downgrade() -> None:
|
|||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
table_names = inspector.get_table_names()
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
if "folder_id" in inspector.get_columns("flow"):
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
column_names = [column["name"] for column in inspector.get_columns("flow")]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
if "folder" not in column_names:
|
||||
batch_op.add_column(sa.Column("folder", sa.VARCHAR(), nullable=True))
|
||||
batch_op.drop_constraint("flow_folder_id_fkey", type_="foreignkey")
|
||||
if "folder_id" in column_names:
|
||||
batch_op.drop_column("folder_id")
|
||||
batch_op.drop_constraint("flow_folder_id_fkey", type_="foreignkey")
|
||||
|
||||
indexes = inspector.get_indexes("folder")
|
||||
if "ix_folder_name" in [index["name"] for index in indexes]:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
"""Add unique constraints per user in folder table
|
||||
|
||||
Revision ID: 1c79524817ed
|
||||
Revises: 3bb0ddf32dfb
|
||||
Create Date: 2024-05-29 23:12:09.146880
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
from sqlalchemy.engine.reflection import Inspector
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "1c79524817ed"
|
||||
down_revision: Union[str, None] = "3bb0ddf32dfb"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("folder")]
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table("folder", schema=None) as batch_op:
|
||||
if "unique_folder_name" not in constraints_names:
|
||||
batch_op.create_unique_constraint("unique_folder_name", ["user_id", "name"])
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("folder")]
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table("folder", schema=None) as batch_op:
|
||||
if "unique_folder_name" in constraints_names:
|
||||
batch_op.drop_constraint("unique_folder_name", type_="unique")
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
"""Add unique constraints per user in flow table
|
||||
|
||||
Revision ID: 3bb0ddf32dfb
|
||||
Revises: a72f5cf9c2f9
|
||||
Create Date: 2024-05-29 23:08:43.935040
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
from sqlalchemy.engine.reflection import Inspector
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "3bb0ddf32dfb"
|
||||
down_revision: Union[str, None] = "a72f5cf9c2f9"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
indexes_names = [index["name"] for index in inspector.get_indexes("flow")]
|
||||
constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("flow")]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
if "ix_flow_endpoint_name" in indexes_names:
|
||||
batch_op.drop_index("ix_flow_endpoint_name")
|
||||
batch_op.create_index(batch_op.f("ix_flow_endpoint_name"), ["endpoint_name"], unique=False)
|
||||
if "unique_flow_endpoint_name" not in constraints_names:
|
||||
batch_op.create_unique_constraint("unique_flow_endpoint_name", ["user_id", "endpoint_name"])
|
||||
if "unique_flow_name" not in constraints_names:
|
||||
batch_op.create_unique_constraint("unique_flow_name", ["user_id", "name"])
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
indexes_names = [index["name"] for index in inspector.get_indexes("flow")]
|
||||
constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("flow")]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
if "unique_flow_name" in constraints_names:
|
||||
batch_op.drop_constraint("unique_flow_name", type_="unique")
|
||||
if "unique_flow_endpoint_name" in constraints_names:
|
||||
batch_op.drop_constraint("unique_flow_endpoint_name", type_="unique")
|
||||
if "ix_flow_endpoint_name" in indexes_names:
|
||||
batch_op.drop_index(batch_op.f("ix_flow_endpoint_name"))
|
||||
batch_op.create_index("ix_flow_endpoint_name", ["endpoint_name"], unique=1)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
"""Add webhook columns
|
||||
|
||||
Revision ID: 631faacf5da2
|
||||
Revises: 1c79524817ed
|
||||
Create Date: 2024-04-22 15:14:43.454784
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
from sqlalchemy.engine.reflection import Inspector
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "631faacf5da2"
|
||||
down_revision: Union[str, None] = "1c79524817ed"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
table_names = inspector.get_table_names()
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
column_names = [column["name"] for column in inspector.get_columns("flow")]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
if "flow" in table_names and "webhook" not in column_names:
|
||||
batch_op.add_column(sa.Column("webhook", sa.Boolean(), nullable=True))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
table_names = inspector.get_table_names()
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
column_names = [column["name"] for column in inspector.get_columns("flow")]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
if "flow" in table_names and "webhook" in column_names:
|
||||
batch_op.drop_column("webhook")
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -52,9 +52,14 @@ def upgrade() -> None:
|
|||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
try:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
column_names = [column["name"] for column in inspector.get_columns("flow")]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
batch_op.drop_column("folder")
|
||||
batch_op.drop_column("updated_at")
|
||||
if "folder" in column_names:
|
||||
batch_op.drop_column("folder")
|
||||
if "updated_at" in column_names:
|
||||
batch_op.drop_column("updated_at")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
"""Add endpoint name col
|
||||
|
||||
Revision ID: a72f5cf9c2f9
|
||||
Revises: 29fe8f1f806b
|
||||
Create Date: 2024-05-29 21:44:04.240816
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel
|
||||
from alembic import op
|
||||
from sqlalchemy.engine.reflection import Inspector
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "a72f5cf9c2f9"
|
||||
down_revision: Union[str, None] = "29fe8f1f806b"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
column_names = [column["name"] for column in inspector.get_columns("flow")]
|
||||
indexes = inspector.get_indexes("flow")
|
||||
index_names = [index["name"] for index in indexes]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
if "endpoint_name" not in column_names:
|
||||
batch_op.add_column(sa.Column("endpoint_name", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
|
||||
if "ix_flow_endpoint_name" not in index_names:
|
||||
batch_op.create_index(batch_op.f("ix_flow_endpoint_name"), ["endpoint_name"], unique=True)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
inspector = Inspector.from_engine(conn) # type: ignore
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
column_names = [column["name"] for column in inspector.get_columns("flow")]
|
||||
indexes = inspector.get_indexes("flow")
|
||||
index_names = [index["name"] for index in indexes]
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
if "ix_flow_endpoint_name" in index_names:
|
||||
batch_op.drop_index(batch_op.f("ix_flow_endpoint_name"))
|
||||
if "endpoint_name" in column_names:
|
||||
batch_op.drop_column("endpoint_name")
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -286,7 +286,7 @@ async def get_next_runnable_vertices(
|
|||
for v_id in set(next_runnable_vertices): # Use set to avoid duplicates
|
||||
graph.vertices_to_run.remove(v_id)
|
||||
graph.remove_from_predecessors(v_id)
|
||||
await chat_service.set_cache(flow_id=flow_id, data=graph, lock=lock)
|
||||
await chat_service.set_cache(key=flow_id, data=graph, lock=lock)
|
||||
return next_runnable_vertices
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import time
|
||||
import uuid
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Annotated, Optional
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException
|
||||
|
|
@ -164,7 +163,6 @@ async def build_vertex(
|
|||
vertex = graph.get_vertex(vertex_id)
|
||||
try:
|
||||
lock = chat_service._cache_locks[flow_id_str]
|
||||
set_cache_coro = partial(chat_service.set_cache, flow_id=flow_id_str)
|
||||
(
|
||||
next_runnable_vertices,
|
||||
top_level_vertices,
|
||||
|
|
@ -175,7 +173,7 @@ async def build_vertex(
|
|||
vertex,
|
||||
) = await graph.build_vertex(
|
||||
lock=lock,
|
||||
set_cache_coro=set_cache_coro,
|
||||
chat_service=chat_service,
|
||||
vertex_id=vertex_id,
|
||||
user_id=current_user.id,
|
||||
inputs_dict=inputs.model_dump() if inputs else {},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Annotated, List, Optional, Union
|
|||
from uuid import UUID
|
||||
|
||||
import sqlalchemy as sa
|
||||
from fastapi import APIRouter, Body, Depends, HTTPException, UploadFile, status
|
||||
from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException, Request, UploadFile, status
|
||||
from loguru import logger
|
||||
from sqlmodel import Session, select
|
||||
|
||||
|
|
@ -22,11 +22,14 @@ from langflow.api.v1.schemas import (
|
|||
from langflow.custom import CustomComponent
|
||||
from langflow.custom.utils import build_custom_component_template
|
||||
from langflow.graph.graph.base import Graph
|
||||
from langflow.graph.schema import RunOutputs
|
||||
from langflow.helpers.flow import get_flow_by_id_or_endpoint_name
|
||||
from langflow.processing.process import process_tweaks, run_graph_internal
|
||||
from langflow.schema.graph import Tweaks
|
||||
from langflow.services.auth.utils import api_key_security, get_current_active_user
|
||||
from langflow.services.cache.utils import save_uploaded_file
|
||||
from langflow.services.database.models.flow import Flow
|
||||
from langflow.services.database.models.flow.utils import get_all_webhook_components_in_flow, get_flow_by_id
|
||||
from langflow.services.database.models.user.model import User
|
||||
from langflow.services.deps import get_session, get_session_service, get_settings_service, get_task_service
|
||||
from langflow.services.session.service import SessionService
|
||||
|
|
@ -53,10 +56,70 @@ def get_all(
|
|||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post("/run/{flow_id}", response_model=RunResponse, response_model_exclude_none=True)
|
||||
async def simple_run_flow(
|
||||
db: Session,
|
||||
flow: Flow,
|
||||
input_request: SimplifiedAPIRequest,
|
||||
session_service: SessionService,
|
||||
stream: bool = False,
|
||||
api_key_user: Optional[User] = None,
|
||||
):
|
||||
try:
|
||||
task_result: List[RunOutputs] = []
|
||||
artifacts = {}
|
||||
user_id = api_key_user.id if api_key_user else None
|
||||
flow_id_str = str(flow.id)
|
||||
if input_request.session_id:
|
||||
session_data = await session_service.load_session(input_request.session_id, flow_id=flow_id_str)
|
||||
graph, artifacts = session_data if session_data else (None, None)
|
||||
if graph is None:
|
||||
raise ValueError(f"Session {input_request.session_id} not found")
|
||||
else:
|
||||
if flow.data is None:
|
||||
raise ValueError(f"Flow {flow_id_str} has no data")
|
||||
graph_data = flow.data
|
||||
graph_data = process_tweaks(graph_data, input_request.tweaks or {}, stream=stream)
|
||||
graph = Graph.from_payload(graph_data, flow_id=flow_id_str, user_id=str(user_id))
|
||||
inputs = [
|
||||
InputValueRequest(components=[], input_value=input_request.input_value, type=input_request.input_type)
|
||||
]
|
||||
if input_request.output_component:
|
||||
outputs = [input_request.output_component]
|
||||
else:
|
||||
outputs = [
|
||||
vertex.id
|
||||
for vertex in graph.vertices
|
||||
if input_request.output_type == "debug"
|
||||
or (
|
||||
vertex.is_output
|
||||
and (input_request.output_type == "any" or input_request.output_type in vertex.id.lower())
|
||||
)
|
||||
]
|
||||
task_result, session_id = await run_graph_internal(
|
||||
graph=graph,
|
||||
flow_id=flow_id_str,
|
||||
session_id=input_request.session_id,
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
artifacts=artifacts,
|
||||
session_service=session_service,
|
||||
stream=stream,
|
||||
)
|
||||
|
||||
return RunResponse(outputs=task_result, session_id=session_id)
|
||||
|
||||
except sa.exc.StatementError as exc:
|
||||
# StatementError('(builtins.ValueError) badly formed hexadecimal UUID string')
|
||||
if "badly formed hexadecimal UUID string" in str(exc):
|
||||
logger.error(f"Flow ID {flow_id_str} is not a valid UUID")
|
||||
# This means the Flow ID is not a valid UUID which means it can't find the flow
|
||||
raise ValueError(str(exc)) from exc
|
||||
|
||||
|
||||
@router.post("/run/{flow_id_or_name}", response_model=RunResponse, response_model_exclude_none=True)
|
||||
async def simplified_run_flow(
|
||||
db: Annotated[Session, Depends(get_session)],
|
||||
flow_id: UUID,
|
||||
flow: Annotated[Flow, Depends(get_flow_by_id_or_endpoint_name)],
|
||||
input_request: SimplifiedAPIRequest = SimplifiedAPIRequest(),
|
||||
stream: bool = False,
|
||||
api_key_user: User = Depends(api_key_security),
|
||||
|
|
@ -67,7 +130,7 @@ async def simplified_run_flow(
|
|||
|
||||
### Parameters:
|
||||
- `db` (Session): Database session for executing queries.
|
||||
- `flow_id` (str): Unique identifier of the flow to be executed.
|
||||
- `flow_id_or_name` (str): ID or endpoint name of the flow to run.
|
||||
- `input_request` (SimplifiedAPIRequest): Request object containing input values, types, output selection, tweaks, and session ID.
|
||||
- `api_key_user` (User): User object derived from the provided API key, used for authentication.
|
||||
- `session_service` (SessionService): Service for managing flow sessions, essential for session reuse and caching.
|
||||
|
|
@ -110,73 +173,21 @@ async def simplified_run_flow(
|
|||
|
||||
This endpoint provides a powerful interface for executing flows with enhanced flexibility and efficiency, supporting a wide range of applications by allowing for dynamic input and output configuration along with performance optimizations through session management and caching.
|
||||
"""
|
||||
session_id = input_request.session_id
|
||||
|
||||
try:
|
||||
flow_id_str = str(flow_id)
|
||||
artifacts = {}
|
||||
if input_request.session_id:
|
||||
session_data = await session_service.load_session(input_request.session_id, flow_id=flow_id_str)
|
||||
graph, artifacts = session_data if session_data else (None, None)
|
||||
if graph is None:
|
||||
raise ValueError(f"Session {input_request.session_id} not found")
|
||||
else:
|
||||
# Get the flow that matches the flow_id and belongs to the user
|
||||
# flow = session.query(Flow).filter(Flow.id == flow_id).filter(Flow.user_id == api_key_user.id).first()
|
||||
flow = db.exec(select(Flow).where(Flow.id == flow_id_str).where(Flow.user_id == api_key_user.id)).first()
|
||||
if flow is None:
|
||||
raise ValueError(f"Flow {flow_id_str} not found")
|
||||
|
||||
if flow.data is None:
|
||||
raise ValueError(f"Flow {flow_id_str} has no data")
|
||||
graph_data = flow.data
|
||||
|
||||
graph_data = process_tweaks(graph_data, input_request.tweaks or {}, stream=stream)
|
||||
graph = Graph.from_payload(graph_data, flow_id=flow_id_str, user_id=str(api_key_user.id))
|
||||
inputs = [
|
||||
InputValueRequest(components=[], input_value=input_request.input_value, type=input_request.input_type)
|
||||
]
|
||||
# outputs is a list of all components that should return output
|
||||
# we need to get them by checking their type
|
||||
# if the output type is debug, we return all outputs
|
||||
# if the output type is any, we return all outputs that are either chat or text
|
||||
# if the output type is chat or text, we return only the outputs that match the type
|
||||
if input_request.output_component:
|
||||
outputs = [input_request.output_component]
|
||||
else:
|
||||
outputs = [
|
||||
vertex.id
|
||||
for vertex in graph.vertices
|
||||
if input_request.output_type == "debug"
|
||||
or (
|
||||
vertex.is_output
|
||||
and (input_request.output_type == "any" or input_request.output_type in vertex.id.lower())
|
||||
)
|
||||
]
|
||||
task_result, session_id = await run_graph_internal(
|
||||
graph=graph,
|
||||
flow_id=flow_id_str,
|
||||
session_id=input_request.session_id,
|
||||
inputs=inputs,
|
||||
outputs=outputs,
|
||||
artifacts=artifacts,
|
||||
return await simple_run_flow(
|
||||
db=db,
|
||||
flow=flow,
|
||||
input_request=input_request,
|
||||
session_service=session_service,
|
||||
stream=stream,
|
||||
api_key_user=api_key_user,
|
||||
)
|
||||
|
||||
return RunResponse(outputs=task_result, session_id=session_id)
|
||||
except sa.exc.StatementError as exc:
|
||||
# StatementError('(builtins.ValueError) badly formed hexadecimal UUID string')
|
||||
if "badly formed hexadecimal UUID string" in str(exc):
|
||||
logger.error(f"Flow ID {flow_id_str} is not a valid UUID")
|
||||
# This means the Flow ID is not a valid UUID which means it can't find the flow
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
except ValueError as exc:
|
||||
if f"Flow {flow_id_str} not found" in str(exc):
|
||||
logger.error(f"Flow {flow_id_str} not found")
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
elif f"Session {session_id} not found" in str(exc):
|
||||
logger.error(f"Session {session_id} not found")
|
||||
if "badly formed hexadecimal UUID string" in str(exc):
|
||||
# This means the Flow ID is not a valid UUID which means it can't find the flow
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
if "not found" in str(exc):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
else:
|
||||
logger.exception(exc)
|
||||
|
|
@ -186,6 +197,68 @@ async def simplified_run_flow(
|
|||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post("/webhook/{flow_id}", response_model=dict, status_code=HTTPStatus.ACCEPTED)
|
||||
async def webhook_run_flow(
|
||||
db: Annotated[Session, Depends(get_session)],
|
||||
flow: Annotated[Flow, Depends(get_flow_by_id)],
|
||||
request: Request,
|
||||
background_tasks: BackgroundTasks,
|
||||
session_service: SessionService = Depends(get_session_service),
|
||||
):
|
||||
"""
|
||||
Run a flow using a webhook request.
|
||||
|
||||
Args:
|
||||
db (Session): The database session.
|
||||
request (Request): The incoming HTTP request.
|
||||
background_tasks (BackgroundTasks): The background tasks manager.
|
||||
session_service (SessionService, optional): The session service. Defaults to Depends(get_session_service).
|
||||
flow (Flow, optional): The flow to be executed. Defaults to Depends(get_flow_by_id).
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the status of the task.
|
||||
|
||||
Raises:
|
||||
HTTPException: If the flow is not found or if there is an error processing the request.
|
||||
"""
|
||||
try:
|
||||
logger.debug("Received webhook request")
|
||||
data = await request.body()
|
||||
if not data:
|
||||
logger.error("Request body is empty")
|
||||
raise ValueError(
|
||||
"Request body is empty. You should provide a JSON payload containing the flow ID.",
|
||||
)
|
||||
|
||||
# get all webhook components in the flow
|
||||
webhook_components = get_all_webhook_components_in_flow(flow.data)
|
||||
tweaks = {}
|
||||
data_dict = await request.json()
|
||||
for component in webhook_components:
|
||||
tweaks[component["id"]] = {"data": data.decode() if isinstance(data, bytes) else data}
|
||||
input_request = SimplifiedAPIRequest(
|
||||
input_value=data_dict.get("input_value", ""),
|
||||
input_type=data_dict.get("input_type", "chat"),
|
||||
output_type=data_dict.get("output_type", "chat"),
|
||||
tweaks=tweaks,
|
||||
session_id=data_dict.get("session_id"),
|
||||
)
|
||||
logger.debug("Starting background task")
|
||||
background_tasks.add_task(
|
||||
simple_run_flow,
|
||||
db=db,
|
||||
flow=flow,
|
||||
input_request=input_request,
|
||||
session_service=session_service,
|
||||
)
|
||||
return {"message": "Task started in the background", "status": "in progress"}
|
||||
except Exception as exc:
|
||||
if "Flow ID is required" in str(exc) or "Request body is empty" in str(exc):
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
logger.exception(exc)
|
||||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post("/run/advanced/{flow_id}", response_model=RunResponse, response_model_exclude_none=True)
|
||||
async def experimental_run_flow(
|
||||
session: Annotated[Session, Depends(get_session)],
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from langflow.api.v1.schemas import FlowListCreate, FlowListIds, FlowListRead
|
|||
from langflow.initial_setup.setup import STARTER_FOLDER_NAME
|
||||
from langflow.services.auth.utils import get_current_active_user
|
||||
from langflow.services.database.models.flow import Flow, FlowCreate, FlowRead, FlowUpdate
|
||||
from langflow.services.database.models.flow.utils import get_webhook_component_in_flow
|
||||
from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME
|
||||
from langflow.services.database.models.folder.model import Folder
|
||||
from langflow.services.database.models.user.model import User
|
||||
|
|
@ -57,8 +58,22 @@ def read_flows(
|
|||
current_user: User = Depends(get_current_active_user),
|
||||
session: Session = Depends(get_session),
|
||||
settings_service: "SettingsService" = Depends(get_settings_service),
|
||||
remove_example_flows: bool = False,
|
||||
):
|
||||
"""Read all flows."""
|
||||
"""
|
||||
Retrieve a list of flows.
|
||||
|
||||
Args:
|
||||
current_user (User): The current authenticated user.
|
||||
session (Session): The database session.
|
||||
settings_service (SettingsService): The settings service.
|
||||
remove_example_flows (bool, optional): Whether to remove example flows. Defaults to False.
|
||||
|
||||
|
||||
Returns:
|
||||
List[Dict]: A list of flows in JSON format.
|
||||
"""
|
||||
|
||||
try:
|
||||
auth_settings = settings_service.auth_settings
|
||||
if auth_settings.AUTO_LOGIN:
|
||||
|
|
@ -73,15 +88,16 @@ def read_flows(
|
|||
flows = validate_is_component(flows) # type: ignore
|
||||
flow_ids = [flow.id for flow in flows]
|
||||
# with the session get the flows that DO NOT have a user_id
|
||||
try:
|
||||
folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first()
|
||||
if not remove_example_flows:
|
||||
try:
|
||||
folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first()
|
||||
|
||||
example_flows = folder.flows if folder else []
|
||||
for example_flow in example_flows:
|
||||
if example_flow.id not in flow_ids:
|
||||
flows.append(example_flow) # type: ignore
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
example_flows = folder.flows if folder else []
|
||||
for example_flow in example_flows:
|
||||
if example_flow.id not in flow_ids:
|
||||
flows.append(example_flow) # type: ignore
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e)) from e
|
||||
return [jsonable_encoder(flow) for flow in flows]
|
||||
|
|
@ -120,30 +136,51 @@ def update_flow(
|
|||
settings_service=Depends(get_settings_service),
|
||||
):
|
||||
"""Update a flow."""
|
||||
try:
|
||||
db_flow = read_flow(
|
||||
session=session,
|
||||
flow_id=flow_id,
|
||||
current_user=current_user,
|
||||
settings_service=settings_service,
|
||||
)
|
||||
if not db_flow:
|
||||
raise HTTPException(status_code=404, detail="Flow not found")
|
||||
flow_data = flow.model_dump(exclude_unset=True)
|
||||
if settings_service.settings.remove_api_keys:
|
||||
flow_data = remove_api_keys(flow_data)
|
||||
for key, value in flow_data.items():
|
||||
if value is not None:
|
||||
setattr(db_flow, key, value)
|
||||
webhook_component = get_webhook_component_in_flow(db_flow.data)
|
||||
db_flow.webhook = webhook_component is not None
|
||||
db_flow.updated_at = datetime.now(timezone.utc)
|
||||
if db_flow.folder_id is None:
|
||||
default_folder = session.exec(select(Folder).where(Folder.name == DEFAULT_FOLDER_NAME)).first()
|
||||
if default_folder:
|
||||
db_flow.folder_id = default_folder.id
|
||||
session.add(db_flow)
|
||||
session.commit()
|
||||
session.refresh(db_flow)
|
||||
return db_flow
|
||||
except Exception as e:
|
||||
# If it is a validation error, return the error message
|
||||
if hasattr(e, "errors"):
|
||||
raise HTTPException(status_code=400, detail=str(e)) from e
|
||||
elif "UNIQUE constraint failed" in str(e):
|
||||
# Get the name of the column that failed
|
||||
columns = str(e).split("UNIQUE constraint failed: ")[1].split(".")[1].split("\n")[0]
|
||||
# UNIQUE constraint failed: flow.user_id, flow.name
|
||||
# or UNIQUE constraint failed: flow.name
|
||||
# if the column has id in it, we want the other column
|
||||
column = columns.split(",")[1] if "id" in columns.split(",")[0] else columns.split(",")[0]
|
||||
|
||||
db_flow = read_flow(
|
||||
session=session,
|
||||
flow_id=flow_id,
|
||||
current_user=current_user,
|
||||
settings_service=settings_service,
|
||||
)
|
||||
if not db_flow:
|
||||
raise HTTPException(status_code=404, detail="Flow not found")
|
||||
flow_data = flow.model_dump(exclude_unset=True)
|
||||
if settings_service.settings.remove_api_keys:
|
||||
flow_data = remove_api_keys(flow_data)
|
||||
for key, value in flow_data.items():
|
||||
if value is not None:
|
||||
setattr(db_flow, key, value)
|
||||
db_flow.updated_at = datetime.now(timezone.utc)
|
||||
if db_flow.folder_id is None:
|
||||
default_folder = session.exec(select(Folder).where(Folder.name == DEFAULT_FOLDER_NAME)).first()
|
||||
if default_folder:
|
||||
db_flow.folder_id = default_folder.id
|
||||
session.add(db_flow)
|
||||
session.commit()
|
||||
session.refresh(db_flow)
|
||||
return db_flow
|
||||
raise HTTPException(
|
||||
status_code=400, detail=f"{column.capitalize().replace('_', ' ')} must be unique"
|
||||
) from e
|
||||
elif isinstance(e, HTTPException):
|
||||
raise e
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail=str(e)) from e
|
||||
|
||||
|
||||
@router.delete("/{flow_id}", status_code=200)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from typing import List
|
||||
from uuid import UUID
|
||||
|
||||
import orjson
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status
|
||||
|
|
@ -88,7 +87,7 @@ def read_folders(
|
|||
def read_folder(
|
||||
*,
|
||||
session: Session = Depends(get_session),
|
||||
folder_id: UUID,
|
||||
folder_id: str,
|
||||
current_user: User = Depends(get_current_active_user),
|
||||
):
|
||||
try:
|
||||
|
|
@ -106,7 +105,7 @@ def read_folder(
|
|||
def update_folder(
|
||||
*,
|
||||
session: Session = Depends(get_session),
|
||||
folder_id: UUID,
|
||||
folder_id: str,
|
||||
folder: FolderUpdate, # Assuming FolderUpdate is a Pydantic model defining updatable fields
|
||||
current_user: User = Depends(get_current_active_user),
|
||||
):
|
||||
|
|
@ -155,7 +154,7 @@ def update_folder(
|
|||
def delete_folder(
|
||||
*,
|
||||
session: Session = Depends(get_session),
|
||||
folder_id: UUID,
|
||||
folder_id: str,
|
||||
current_user: User = Depends(get_current_active_user),
|
||||
):
|
||||
try:
|
||||
|
|
@ -177,7 +176,7 @@ def delete_folder(
|
|||
async def download_file(
|
||||
*,
|
||||
session: Session = Depends(get_session),
|
||||
folder_id: UUID,
|
||||
folder_id: str,
|
||||
current_user: User = Depends(get_current_active_user),
|
||||
):
|
||||
"""Download all flows from folder."""
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ async def login_to_get_access_token(
|
|||
samesite=auth_settings.REFRESH_SAME_SITE,
|
||||
secure=auth_settings.REFRESH_SECURE,
|
||||
expires=auth_settings.REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
domain=auth_settings.COOKIE_DOMAIN,
|
||||
)
|
||||
response.set_cookie(
|
||||
"access_token_lf",
|
||||
|
|
@ -54,6 +55,7 @@ async def login_to_get_access_token(
|
|||
samesite=auth_settings.ACCESS_SAME_SITE,
|
||||
secure=auth_settings.ACCESS_SECURE,
|
||||
expires=auth_settings.ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
domain=auth_settings.COOKIE_DOMAIN,
|
||||
)
|
||||
variable_service.initialize_user_variables(user.id, db)
|
||||
# Create default folder for user if it doesn't exist
|
||||
|
|
@ -71,8 +73,7 @@ async def login_to_get_access_token(
|
|||
async def auto_login(
|
||||
response: Response,
|
||||
db: Session = Depends(get_session),
|
||||
settings_service=Depends(get_settings_service),
|
||||
variable_service: VariableService = Depends(get_variable_service),
|
||||
settings_service=Depends(get_settings_service)
|
||||
):
|
||||
auth_settings = settings_service.auth_settings
|
||||
if settings_service.auth_settings.AUTO_LOGIN:
|
||||
|
|
@ -84,9 +85,9 @@ async def auto_login(
|
|||
samesite=auth_settings.ACCESS_SAME_SITE,
|
||||
secure=auth_settings.ACCESS_SECURE,
|
||||
expires=None, # Set to None to make it a session cookie
|
||||
domain=auth_settings.COOKIE_DOMAIN,
|
||||
)
|
||||
variable_service.initialize_user_variables(user_id, db)
|
||||
create_default_folder_if_it_doesnt_exist(db, user_id)
|
||||
|
||||
return tokens
|
||||
|
||||
raise HTTPException(
|
||||
|
|
@ -117,6 +118,7 @@ async def refresh_token(
|
|||
samesite=auth_settings.REFRESH_SAME_SITE,
|
||||
secure=auth_settings.REFRESH_SECURE,
|
||||
expires=auth_settings.REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
domain=auth_settings.COOKIE_DOMAIN,
|
||||
)
|
||||
response.set_cookie(
|
||||
"access_token_lf",
|
||||
|
|
@ -125,6 +127,7 @@ async def refresh_token(
|
|||
samesite=auth_settings.ACCESS_SAME_SITE,
|
||||
secure=auth_settings.ACCESS_SECURE,
|
||||
expires=auth_settings.ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
domain=auth_settings.COOKIE_DOMAIN,
|
||||
)
|
||||
return tokens
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ class ResultDataResponse(BaseModel):
|
|||
messages: List[ChatOutputResponse | None] = Field(default_factory=list)
|
||||
timedelta: Optional[float] = None
|
||||
duration: Optional[str] = None
|
||||
used_frozen_result: Optional[bool] = False
|
||||
|
||||
|
||||
class VertexBuildResponse(BaseModel):
|
||||
|
|
|
|||
0
src/backend/base/langflow/base/curl/__init__.py
Normal file
0
src/backend/base/langflow/base/curl/__init__.py
Normal file
89
src/backend/base/langflow/base/curl/parse.py
Normal file
89
src/backend/base/langflow/base/curl/parse.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
"""
|
||||
This file contains a fix for the implementation of the `uncurl` library, which is available at https://github.com/spulec/uncurl.git.
|
||||
|
||||
The `uncurl` library provides a way to parse and convert cURL commands into Python requests. However, there are some issues with the original implementation that this file aims to fix.
|
||||
|
||||
The `parse_context` function in this file takes a cURL command as input and returns a `ParsedContext` object, which contains the parsed information from the cURL command, such as the HTTP method, URL, headers, cookies, etc.
|
||||
|
||||
The `normalize_newlines` function is a helper function that replaces the line continuation character ("\") followed by a newline with a space.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
import shlex
|
||||
from collections import OrderedDict, namedtuple
|
||||
from http.cookies import SimpleCookie
|
||||
|
||||
from uncurl.api import parser # type: ignore
|
||||
|
||||
parser.add_argument("-x", "--proxy", default={})
|
||||
parser.add_argument("-U", "--proxy-user", default="")
|
||||
|
||||
ParsedContext = namedtuple("ParsedContext", ["method", "url", "data", "headers", "cookies", "verify", "auth", "proxy"])
|
||||
|
||||
|
||||
def normalize_newlines(multiline_text):
|
||||
return multiline_text.replace(" \\\n", " ")
|
||||
|
||||
|
||||
def parse_context(curl_command):
|
||||
method = "get"
|
||||
|
||||
tokens = shlex.split(normalize_newlines(curl_command))
|
||||
tokens = [token for token in tokens if token and token != " "]
|
||||
parsed_args = parser.parse_args(tokens)
|
||||
|
||||
post_data = parsed_args.data or parsed_args.data_binary
|
||||
if post_data:
|
||||
method = "post"
|
||||
|
||||
if parsed_args.X:
|
||||
method = parsed_args.X.lower()
|
||||
|
||||
cookie_dict = OrderedDict()
|
||||
quoted_headers = OrderedDict()
|
||||
|
||||
for curl_header in parsed_args.header:
|
||||
if curl_header.startswith(":"):
|
||||
occurrence = [m.start() for m in re.finditer(":", curl_header)]
|
||||
header_key, header_value = curl_header[: occurrence[1]], curl_header[occurrence[1] + 1 :]
|
||||
else:
|
||||
header_key, header_value = curl_header.split(":", 1)
|
||||
|
||||
if header_key.lower().strip("$") == "cookie":
|
||||
cookie = SimpleCookie(bytes(header_value, "ascii").decode("unicode-escape"))
|
||||
for key in cookie:
|
||||
cookie_dict[key] = cookie[key].value
|
||||
else:
|
||||
quoted_headers[header_key] = header_value.strip()
|
||||
|
||||
# add auth
|
||||
user = parsed_args.user
|
||||
if parsed_args.user:
|
||||
user = tuple(user.split(":"))
|
||||
|
||||
# add proxy and its authentication if it's available.
|
||||
proxies = parsed_args.proxy
|
||||
# proxy_auth = parsed_args.proxy_user
|
||||
if parsed_args.proxy and parsed_args.proxy_user:
|
||||
proxies = {
|
||||
"http": "http://{}@{}/".format(parsed_args.proxy_user, parsed_args.proxy),
|
||||
"https": "http://{}@{}/".format(parsed_args.proxy_user, parsed_args.proxy),
|
||||
}
|
||||
elif parsed_args.proxy:
|
||||
proxies = {
|
||||
"http": "http://{}/".format(parsed_args.proxy),
|
||||
"https": "http://{}/".format(parsed_args.proxy),
|
||||
}
|
||||
|
||||
return ParsedContext(
|
||||
method=method,
|
||||
url=parsed_args.url,
|
||||
data=post_data,
|
||||
headers=quoted_headers,
|
||||
cookies=cookie_dict,
|
||||
verify=parsed_args.insecure,
|
||||
auth=user,
|
||||
proxy=proxies,
|
||||
)
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
import asyncio
|
||||
import json
|
||||
from typing import List, Optional
|
||||
from typing import Any, List, Optional
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
from langflow.base.curl.parse import parse_context
|
||||
from langflow.custom import CustomComponent
|
||||
from langflow.field_typing import NestedDict
|
||||
from langflow.schema import Record
|
||||
from langflow.schema.dotdict import dotdict
|
||||
|
||||
|
||||
class APIRequest(CustomComponent):
|
||||
|
|
@ -17,10 +21,15 @@ class APIRequest(CustomComponent):
|
|||
|
||||
field_config = {
|
||||
"urls": {"display_name": "URLs", "info": "URLs to make requests to."},
|
||||
"curl": {
|
||||
"display_name": "Curl",
|
||||
"info": "Paste a curl command to populate the fields.",
|
||||
"refresh_button": True,
|
||||
"refresh_button_text": "",
|
||||
},
|
||||
"method": {
|
||||
"display_name": "Method",
|
||||
"info": "The HTTP method to use.",
|
||||
"field_type": "str",
|
||||
"options": ["GET", "POST", "PATCH", "PUT"],
|
||||
"value": "GET",
|
||||
},
|
||||
|
|
@ -36,12 +45,33 @@ class APIRequest(CustomComponent):
|
|||
},
|
||||
"timeout": {
|
||||
"display_name": "Timeout",
|
||||
"field_type": "int",
|
||||
"info": "The timeout to use for the request.",
|
||||
"value": 5,
|
||||
},
|
||||
}
|
||||
|
||||
def parse_curl(self, curl: str, build_config: dotdict) -> dotdict:
|
||||
try:
|
||||
parsed = parse_context(curl)
|
||||
build_config["urls"]["value"] = [parsed.url]
|
||||
build_config["method"]["value"] = parsed.method.upper()
|
||||
build_config["headers"]["value"] = dict(parsed.headers)
|
||||
|
||||
try:
|
||||
json_data = json.loads(parsed.data)
|
||||
build_config["body"]["value"] = json_data
|
||||
except json.JSONDecodeError as e:
|
||||
print(e)
|
||||
except Exception as exc:
|
||||
logger.error(f"Error parsing curl: {exc}")
|
||||
raise ValueError(f"Error parsing curl: {exc}")
|
||||
return build_config
|
||||
|
||||
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
|
||||
if field_name == "curl" and field_value is not None:
|
||||
build_config = self.parse_curl(field_value, build_config)
|
||||
return build_config
|
||||
|
||||
async def make_request(
|
||||
self,
|
||||
client: httpx.AsyncClient,
|
||||
|
|
@ -94,21 +124,25 @@ class APIRequest(CustomComponent):
|
|||
self,
|
||||
method: str,
|
||||
urls: List[str],
|
||||
headers: Optional[Record] = None,
|
||||
body: Optional[Record] = None,
|
||||
curl: Optional[str] = None,
|
||||
headers: Optional[NestedDict] = {},
|
||||
body: Optional[NestedDict] = {},
|
||||
timeout: int = 5,
|
||||
) -> List[Record]:
|
||||
if headers is None:
|
||||
headers_dict = {}
|
||||
else:
|
||||
elif isinstance(headers, Record):
|
||||
headers_dict = headers.data
|
||||
else:
|
||||
headers_dict = headers
|
||||
|
||||
bodies = []
|
||||
if body:
|
||||
if isinstance(body, list):
|
||||
bodies = [b.data for b in body]
|
||||
if not isinstance(body, list):
|
||||
bodies = [body]
|
||||
else:
|
||||
bodies = [body.data]
|
||||
bodies = body
|
||||
bodies = [b.data if isinstance(b, Record) else b for b in bodies] # type: ignore
|
||||
|
||||
if len(urls) != len(bodies):
|
||||
# add bodies with None
|
||||
|
|
|
|||
39
src/backend/base/langflow/components/data/Webhook.py
Normal file
39
src/backend/base/langflow/components/data/Webhook.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import json
|
||||
import uuid
|
||||
from typing import Any, Optional
|
||||
|
||||
from langflow.custom import CustomComponent
|
||||
from langflow.schema.dotdict import dotdict
|
||||
from langflow.schema.schema import Record
|
||||
|
||||
|
||||
class WebhookComponent(CustomComponent):
|
||||
display_name = "Webhook Input"
|
||||
description = "Defines a webhook input for the flow."
|
||||
|
||||
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
|
||||
if field_name == "webhook_id":
|
||||
build_config["webhook_id"]["value"] = uuid.uuid4().hex
|
||||
return build_config
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"data": {
|
||||
"display_name": "Data",
|
||||
"info": "Use this field to quickly test the webhook component by providing a JSON payload.",
|
||||
"multiline": True,
|
||||
}
|
||||
}
|
||||
|
||||
def build(self, data: Optional[str] = "") -> Record:
|
||||
message = ""
|
||||
try:
|
||||
body = json.loads(data or "{}")
|
||||
except json.JSONDecodeError:
|
||||
body = {"payload": data}
|
||||
message = f"Invalid JSON payload. Please check the format.\n\n{data}"
|
||||
record = Record(data=body)
|
||||
if not message:
|
||||
message = json.dumps(body, indent=2)
|
||||
self.status = message
|
||||
return record
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
from .APIRequest import APIRequest
|
||||
from .Directory import DirectoryComponent
|
||||
from .File import FileComponent
|
||||
from .Webhook import WebhookComponent
|
||||
|
||||
from .URL import URLComponent
|
||||
|
||||
__all__ = ["APIRequest", "DirectoryComponent", "FileComponent", "URLComponent"]
|
||||
__all__ = ["APIRequest", "DirectoryComponent", "FileComponent", "URLComponent", "WebhookComponent"]
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class SplitTextComponent(CustomComponent):
|
|||
chunks = [chunk[:truncate_size] for chunk in chunks]
|
||||
|
||||
for chunk in chunks:
|
||||
outputs.append(Record(text=chunk, data={"parent": text}))
|
||||
outputs.append(Record(data={"parent": text, "text": chunk}))
|
||||
|
||||
self.status = outputs
|
||||
return outputs
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
|
||||
|
||||
from langchain_community.chat_models.ollama import ChatOllama
|
||||
from langflow.base.constants import STREAM_INFO_TEXT
|
||||
from langflow.base.models.model import LCModelComponent
|
||||
from langchain_core.caches import BaseCache
|
||||
|
||||
from langflow.field_typing import Text
|
||||
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import httpx
|
||||
from langchain_community.chat_models.ollama import ChatOllama
|
||||
|
||||
from langflow.base.constants import STREAM_INFO_TEXT
|
||||
from langflow.base.models.model import LCModelComponent
|
||||
from langflow.field_typing import Text
|
||||
|
||||
|
||||
class ChatOllamaComponent(LCModelComponent):
|
||||
|
|
@ -26,18 +16,12 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
field_order = [
|
||||
"base_url",
|
||||
"headers",
|
||||
|
||||
"keep_alive_flag",
|
||||
"keep_alive",
|
||||
|
||||
"metadata",
|
||||
"model",
|
||||
|
||||
|
||||
"temperature",
|
||||
"cache",
|
||||
|
||||
|
||||
"format",
|
||||
"metadata",
|
||||
"mirostat",
|
||||
|
|
@ -67,10 +51,7 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
"base_url": {
|
||||
"display_name": "Base URL",
|
||||
"info": "Endpoint of the Ollama API. Defaults to 'http://localhost:11434' if not specified.",
|
||||
|
||||
},
|
||||
|
||||
|
||||
"format": {
|
||||
"display_name": "Format",
|
||||
"info": "Specify the format of the output (e.g., json)",
|
||||
|
|
@ -79,13 +60,10 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
"headers": {
|
||||
"display_name": "Headers",
|
||||
"advanced": True,
|
||||
|
||||
|
||||
},
|
||||
|
||||
"keep_alive_flag": {
|
||||
"display_name": "Unload interval",
|
||||
"options": ["Keep", "Immediately","Minute", "Hour", "sec" ],
|
||||
"options": ["Keep", "Immediately", "Minute", "Hour", "sec"],
|
||||
"real_time_refresh": True,
|
||||
"refresh_button": True,
|
||||
},
|
||||
|
|
@ -93,9 +71,6 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
"display_name": "interval",
|
||||
"info": "How long the model will stay loaded into memory.",
|
||||
},
|
||||
|
||||
|
||||
|
||||
"model": {
|
||||
"display_name": "Model Name",
|
||||
"options": [],
|
||||
|
|
@ -109,14 +84,6 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
"value": 0.8,
|
||||
"info": "Controls the creativity of model responses.",
|
||||
},
|
||||
|
||||
|
||||
"format": {
|
||||
"display_name": "Format",
|
||||
"field_type": "str",
|
||||
"info": "Specify the format of the output (e.g., json).",
|
||||
"advanced": True,
|
||||
},
|
||||
"metadata": {
|
||||
"display_name": "Metadata",
|
||||
"info": "Metadata to add to the run trace.",
|
||||
|
|
@ -129,7 +96,6 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
"advanced": False,
|
||||
"real_time_refresh": True,
|
||||
"refresh_button": True,
|
||||
|
||||
},
|
||||
"mirostat_eta": {
|
||||
"display_name": "Mirostat Eta",
|
||||
|
|
@ -260,10 +226,14 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
build_config["mirostat_tau"]["value"] = 5
|
||||
|
||||
if field_name == "model":
|
||||
base_url = build_config.get("base_url", {}).get(
|
||||
"value", "http://localhost:11434")
|
||||
build_config["model"]["options"] = self.get_model(
|
||||
base_url + "/api/tags")
|
||||
base_url_dict = build_config.get("base_url", {})
|
||||
base_url_load_from_db = base_url_dict.get("load_from_db", False)
|
||||
base_url_value = base_url_dict.get("value")
|
||||
if base_url_load_from_db:
|
||||
base_url_value = self.variables(base_url_value)
|
||||
elif not base_url_value:
|
||||
base_url_value = "http://localhost:11434"
|
||||
build_config["model"]["options"] = self.get_model(base_url_value + "/api/tags")
|
||||
|
||||
if field_name == "keep_alive_flag":
|
||||
if field_value == "Keep":
|
||||
|
|
@ -276,9 +246,6 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
build_config["keep_alive"]["advanced"] = False
|
||||
|
||||
return build_config
|
||||
|
||||
|
||||
|
||||
|
||||
def get_model(self, url: str) -> List[str]:
|
||||
try:
|
||||
|
|
@ -287,8 +254,7 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
model_names = [model['name']
|
||||
for model in data.get("models", [])]
|
||||
model_names = [model["name"] for model in data.get("models", [])]
|
||||
return model_names
|
||||
except Exception as e:
|
||||
raise ValueError("Could not retrieve models") from e
|
||||
|
|
@ -299,15 +265,13 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
base_url: Optional[str],
|
||||
model: str,
|
||||
input_value: Text,
|
||||
|
||||
mirostat: Optional[str],
|
||||
mirostat: Optional[str] = "Disabled",
|
||||
mirostat_eta: Optional[float] = None,
|
||||
mirostat_tau: Optional[float] = None,
|
||||
|
||||
repeat_last_n: Optional[int] = None,
|
||||
verbose: Optional[bool] = None,
|
||||
keep_alive: Optional[int] = None,
|
||||
keep_alive_flag: Optional[str] = None,
|
||||
keep_alive_flag: Optional[str] = "Keep",
|
||||
num_ctx: Optional[int] = None,
|
||||
num_gpu: Optional[int] = None,
|
||||
format: Optional[str] = None,
|
||||
|
|
@ -326,12 +290,9 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
stream: bool = False,
|
||||
system_message: Optional[str] = None,
|
||||
) -> Text:
|
||||
|
||||
if not base_url:
|
||||
base_url = "http://localhost:11434"
|
||||
|
||||
|
||||
|
||||
if keep_alive_flag == "Minute":
|
||||
keep_alive_instance = f"{keep_alive}m"
|
||||
elif keep_alive_flag == "Hour":
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class OpenAIModelComponent(LCModelComponent):
|
|||
self,
|
||||
input_value: Text,
|
||||
openai_api_key: str,
|
||||
temperature: float,
|
||||
temperature: float = 0.1,
|
||||
model_name: str = "gpt-4o",
|
||||
max_tokens: Optional[int] = 256,
|
||||
model_kwargs: NestedDict = {},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
from typing import List, Optional
|
||||
|
||||
from langchain_core.embeddings import Embeddings
|
||||
|
||||
from langflow.components.vectorstores.base.model import LCVectorStoreComponent
|
||||
from langflow.components.vectorstores.Upstash import UpstashVectorStoreComponent
|
||||
from langflow.field_typing import Text
|
||||
from langflow.schema import Record
|
||||
|
||||
|
||||
class UpstashSearchComponent(UpstashVectorStoreComponent, LCVectorStoreComponent):
|
||||
"""
|
||||
A custom component for implementing a Vector Store using Upstash.
|
||||
"""
|
||||
|
||||
display_name: str = "Upstash Search"
|
||||
description: str = "Search an Upstash Vector Store for similar documents."
|
||||
|
||||
def build_config(self):
|
||||
"""
|
||||
Builds the configuration for the component.
|
||||
|
||||
Returns:
|
||||
- dict: A dictionary containing the configuration options for the component.
|
||||
"""
|
||||
return {
|
||||
"search_type": {
|
||||
"display_name": "Search Type",
|
||||
"options": ["Similarity", "MMR"],
|
||||
},
|
||||
"input_value": {"display_name": "Input"},
|
||||
"inputs": {"display_name": "Input", "input_types": ["Document", "Record"]},
|
||||
"embedding": {
|
||||
"display_name": "Embedding",
|
||||
"input_types": ["Embeddings"],
|
||||
"info": "To use Upstash's embeddings, don't provide an embedding.",
|
||||
},
|
||||
"index_url": {
|
||||
"display_name": "Index URL",
|
||||
"info": "The URL of the Upstash index.",
|
||||
},
|
||||
"index_token": {
|
||||
"display_name": "Index Token",
|
||||
"info": "The token for the Upstash index.",
|
||||
},
|
||||
"number_of_results": {
|
||||
"display_name": "Number of Results",
|
||||
"info": "Number of results to return.",
|
||||
"advanced": True,
|
||||
},
|
||||
"text_key": {
|
||||
"display_name": "Text Key",
|
||||
"info": "The key in the record to use as text.",
|
||||
"advanced": True,
|
||||
},
|
||||
}
|
||||
|
||||
def build( # type: ignore[override]
|
||||
self,
|
||||
input_value: Text,
|
||||
search_type: str,
|
||||
text_key: str = "text",
|
||||
index_url: Optional[str] = None,
|
||||
index_token: Optional[str] = None,
|
||||
embedding: Optional[Embeddings] = None,
|
||||
number_of_results: int = 4,
|
||||
) -> List[Record]:
|
||||
vector_store = super().build(
|
||||
embedding=embedding,
|
||||
text_key=text_key,
|
||||
index_url=index_url,
|
||||
index_token=index_token,
|
||||
)
|
||||
if not vector_store:
|
||||
raise ValueError("Failed to load the Upstash Vector Store.")
|
||||
|
||||
return self.search_with_vector_store(
|
||||
input_value=input_value, search_type=search_type, vector_store=vector_store, k=number_of_results
|
||||
)
|
||||
|
|
@ -67,22 +67,19 @@ class QdrantComponent(CustomComponent):
|
|||
documents.append(_input.to_lc_document())
|
||||
else:
|
||||
documents.append(_input)
|
||||
if documents is None:
|
||||
if not documents:
|
||||
from qdrant_client import QdrantClient
|
||||
|
||||
client = QdrantClient(
|
||||
location=location,
|
||||
url=host,
|
||||
url=url,
|
||||
port=port,
|
||||
grpc_port=grpc_port,
|
||||
https=https,
|
||||
prefix=prefix,
|
||||
timeout=timeout,
|
||||
prefer_grpc=prefer_grpc,
|
||||
metadata_payload_key=metadata_payload_key,
|
||||
content_payload_key=content_payload_key,
|
||||
api_key=api_key,
|
||||
collection_name=collection_name,
|
||||
host=host,
|
||||
path=path,
|
||||
)
|
||||
|
|
@ -90,6 +87,8 @@ class QdrantComponent(CustomComponent):
|
|||
client=client,
|
||||
collection_name=collection_name,
|
||||
embeddings=embedding,
|
||||
content_payload_key=content_payload_key,
|
||||
metadata_payload_key=metadata_payload_key,
|
||||
)
|
||||
return vs
|
||||
else:
|
||||
|
|
|
|||
89
src/backend/base/langflow/components/vectorstores/Upstash.py
Normal file
89
src/backend/base/langflow/components/vectorstores/Upstash.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
from typing import List, Optional, Union
|
||||
|
||||
from langchain_community.vectorstores.upstash import UpstashVectorStore
|
||||
from langchain_core.embeddings import Embeddings
|
||||
from langchain_core.retrievers import BaseRetriever
|
||||
from langchain_core.vectorstores import VectorStore
|
||||
|
||||
from langflow.custom import CustomComponent
|
||||
from langflow.schema.schema import Record
|
||||
|
||||
|
||||
class UpstashVectorStoreComponent(CustomComponent):
|
||||
"""
|
||||
A custom component for implementing a Vector Store using Upstash.
|
||||
"""
|
||||
|
||||
display_name: str = "Upstash"
|
||||
description: str = "Create and Utilize an Upstash Vector Store"
|
||||
|
||||
def build_config(self):
|
||||
"""
|
||||
Builds the configuration for the component.
|
||||
|
||||
Returns:
|
||||
- dict: A dictionary containing the configuration options for the component.
|
||||
"""
|
||||
return {
|
||||
"inputs": {"display_name": "Input", "input_types": ["Document", "Record"]},
|
||||
"embedding": {
|
||||
"display_name": "Embedding",
|
||||
"input_types": ["Embeddings"],
|
||||
"info": "To use Upstash's embeddings, don't provide an embedding.",
|
||||
},
|
||||
"index_url": {
|
||||
"display_name": "Index URL",
|
||||
"info": "The URL of the Upstash index.",
|
||||
},
|
||||
"index_token": {
|
||||
"display_name": "Index Token",
|
||||
"info": "The token for the Upstash index.",
|
||||
},
|
||||
"text_key": {
|
||||
"display_name": "Text Key",
|
||||
"info": "The key in the record to use as text.",
|
||||
"advanced": True,
|
||||
},
|
||||
}
|
||||
|
||||
def build(
|
||||
self,
|
||||
inputs: Optional[List[Record]] = None,
|
||||
text_key: str = "text",
|
||||
index_url: Optional[str] = None,
|
||||
index_token: Optional[str] = None,
|
||||
embedding: Optional[Embeddings] = None,
|
||||
) -> Union[VectorStore, BaseRetriever]:
|
||||
documents = []
|
||||
for _input in inputs or []:
|
||||
if isinstance(_input, Record):
|
||||
documents.append(_input.to_lc_document())
|
||||
else:
|
||||
documents.append(_input)
|
||||
|
||||
use_upstash_embedding = embedding is None
|
||||
if not documents:
|
||||
upstash_vs = UpstashVectorStore(
|
||||
embedding=embedding or use_upstash_embedding,
|
||||
text_key=text_key,
|
||||
index_url=index_url,
|
||||
index_token=index_token,
|
||||
)
|
||||
else:
|
||||
if use_upstash_embedding:
|
||||
upstash_vs = UpstashVectorStore(
|
||||
embedding=use_upstash_embedding,
|
||||
text_key=text_key,
|
||||
index_url=index_url,
|
||||
index_token=index_token,
|
||||
)
|
||||
upstash_vs.add_documents(documents)
|
||||
elif embedding:
|
||||
upstash_vs = UpstashVectorStore.from_documents(
|
||||
documents=documents, # type: ignore
|
||||
embedding=embedding,
|
||||
text_key=text_key,
|
||||
index_url=index_url,
|
||||
index_token=index_token,
|
||||
)
|
||||
return upstash_vs
|
||||
|
|
@ -159,6 +159,11 @@ def add_new_custom_field(
|
|||
if field_type == "bool" and field_value is None:
|
||||
field_value = False
|
||||
|
||||
if field_type == "SecretStr":
|
||||
field_config["password"] = True
|
||||
field_config["load_from_db"] = True
|
||||
field_config["input_types"] = ["Text"]
|
||||
|
||||
# If options is a list, then it's a dropdown
|
||||
# If options is None, then it's a list of strings
|
||||
is_list = isinstance(field_config.get("options"), list)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@ from langflow.graph.vertex.base import Vertex
|
|||
from langflow.graph.vertex.types import InterfaceVertex, StateVertex
|
||||
from langflow.schema import Record
|
||||
from langflow.schema.schema import INPUT_FIELD_NAME, InputType
|
||||
from langflow.services.cache.utils import CacheMiss
|
||||
from langflow.services.chat.service import ChatService
|
||||
from langflow.services.deps import get_chat_service
|
||||
from langflow.services.monitor.utils import log_transaction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.graph.schema import ResultData
|
||||
|
|
@ -704,7 +707,7 @@ class Graph:
|
|||
async def build_vertex(
|
||||
self,
|
||||
lock: asyncio.Lock,
|
||||
set_cache_coro: Callable[["Graph", asyncio.Lock], Coroutine],
|
||||
chat_service: ChatService,
|
||||
vertex_id: str,
|
||||
inputs_dict: Optional[Dict[str, str]] = None,
|
||||
files: Optional[list[str]] = None,
|
||||
|
|
@ -740,13 +743,14 @@ class Graph:
|
|||
result_dict = vertex.result
|
||||
else:
|
||||
raise ValueError(f"No result found for vertex {vertex_id}")
|
||||
|
||||
set_cache_coro = partial(chat_service.set_cache, key=self.flow_id)
|
||||
next_runnable_vertices, top_level_vertices = await self.get_next_and_top_level_vertices(
|
||||
lock, set_cache_coro, vertex
|
||||
)
|
||||
return next_runnable_vertices, top_level_vertices, result_dict, params, valid, log_type, vertex
|
||||
except Exception as exc:
|
||||
logger.exception(f"Error building vertex: {exc}")
|
||||
log_transaction(vertex, status="failure", error=str(exc))
|
||||
raise exc
|
||||
|
||||
async def get_next_and_top_level_vertices(
|
||||
|
|
@ -811,11 +815,10 @@ class Graph:
|
|||
for vertex_id in current_batch:
|
||||
vertex = self.get_vertex(vertex_id)
|
||||
lock = chat_service._cache_locks[self.run_id]
|
||||
set_cache_coro = partial(chat_service.set_cache, flow_id=self.run_id)
|
||||
task = asyncio.create_task(
|
||||
self.build_vertex(
|
||||
lock=lock,
|
||||
set_cache_coro=set_cache_coro,
|
||||
chat_service=chat_service,
|
||||
vertex_id=vertex_id,
|
||||
user_id=self.user_id,
|
||||
inputs_dict={},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class ResultData(BaseModel):
|
|||
duration: Optional[str] = None
|
||||
component_display_name: Optional[str] = None
|
||||
component_id: Optional[str] = None
|
||||
used_frozen_result: Optional[bool] = False
|
||||
|
||||
@field_serializer("results")
|
||||
def serialize_results(self, value):
|
||||
|
|
|
|||
|
|
@ -708,7 +708,8 @@ class Vertex:
|
|||
|
||||
self._finalize_build()
|
||||
|
||||
return await self.get_requester_result(requester)
|
||||
result = await self.get_requester_result(requester)
|
||||
return result
|
||||
|
||||
async def get_requester_result(self, requester: Optional["Vertex"]):
|
||||
# If the requester is None, this means that
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, Optional, Tuple, Type, Union, cast
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import Depends, HTTPException
|
||||
from pydantic.v1 import BaseModel, Field, create_model
|
||||
from sqlmodel import select
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from langflow.graph.schema import RunOutputs
|
||||
from langflow.schema.schema import INPUT_FIELD_NAME, Record
|
||||
from langflow.services.database.models.flow.model import Flow
|
||||
from langflow.services.deps import session_scope
|
||||
from langflow.services.database.models.flow import Flow
|
||||
from langflow.services.deps import get_session, session_scope
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.graph.graph.base import Graph
|
||||
|
|
@ -235,3 +236,22 @@ def get_arg_names(inputs: List["Vertex"]) -> List[dict[str, str]]:
|
|||
{"component_name": input_.display_name, "arg_name": input_.display_name.lower().replace(" ", "_")}
|
||||
for input_ in inputs
|
||||
]
|
||||
|
||||
|
||||
def get_flow_by_id_or_endpoint_name(
|
||||
flow_id_or_name: str, db: Session = Depends(get_session), user_id: Optional[UUID] = None
|
||||
) -> Flow:
|
||||
endpoint_name = None
|
||||
try:
|
||||
flow_id = UUID(flow_id_or_name)
|
||||
flow = db.get(Flow, flow_id)
|
||||
except ValueError:
|
||||
endpoint_name = flow_id_or_name
|
||||
stmt = select(Flow).where(Flow.name == endpoint_name)
|
||||
if user_id:
|
||||
stmt = stmt.where(Flow.user_id == user_id)
|
||||
flow = db.exec(stmt).first()
|
||||
if flow is None:
|
||||
raise HTTPException(status_code=404, detail=f"Flow identifier {flow_id_or_name} not found")
|
||||
|
||||
return flow
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import logging
|
||||
import os
|
||||
from collections import defaultdict
|
||||
from copy import deepcopy
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from uuid import UUID
|
||||
|
||||
import orjson
|
||||
from emoji import demojize, purely_emoji # type: ignore
|
||||
|
|
@ -10,10 +13,16 @@ from sqlmodel import select
|
|||
|
||||
from langflow.base.constants import FIELD_FORMAT_ATTRIBUTES, NODE_FORMAT_ATTRIBUTES
|
||||
from langflow.interface.types import get_all_components
|
||||
from langflow.services.auth.utils import create_super_user
|
||||
from langflow.services.database.models.flow.model import Flow, FlowCreate
|
||||
from langflow.services.database.models.folder.model import Folder, FolderCreate
|
||||
from langflow.services.database.models.user.crud import get_user_by_username
|
||||
from langflow.services.deps import get_settings_service, session_scope
|
||||
|
||||
from langflow.services.database.models.folder.utils import create_default_folder_if_it_doesnt_exist
|
||||
from langflow.services.deps import get_settings_service, session_scope, get_variable_service
|
||||
|
||||
|
||||
STARTER_FOLDER_NAME = "Starter Projects"
|
||||
STARTER_FOLDER_DESCRIPTION = "Starter projects to help you get started in Langflow."
|
||||
|
||||
|
|
@ -205,6 +214,63 @@ def create_starter_folder(session):
|
|||
return session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first()
|
||||
|
||||
|
||||
def _is_valid_uuid(val):
|
||||
try:
|
||||
uuid_obj = UUID(val)
|
||||
except ValueError:
|
||||
return False
|
||||
return str(uuid_obj) == val
|
||||
|
||||
def load_flows_from_directory():
|
||||
settings_service = get_settings_service()
|
||||
flows_path = settings_service.settings.load_flows_path
|
||||
if not flows_path:
|
||||
return
|
||||
if not settings_service.auth_settings.AUTO_LOGIN:
|
||||
logging.warning("AUTO_LOGIN is disabled, not loading flows from directory")
|
||||
return
|
||||
|
||||
with session_scope() as session:
|
||||
user_id = get_user_by_username(session, settings_service.auth_settings.SUPERUSER).id
|
||||
files = [f for f in os.listdir(flows_path) if os.path.isfile(os.path.join(flows_path, f))]
|
||||
for filename in files:
|
||||
if not filename.endswith(".json"):
|
||||
continue
|
||||
logger.info(f"Loading flow from file: {filename}")
|
||||
with open(os.path.join(flows_path, filename), "r", encoding="utf-8") as file:
|
||||
flow = orjson.loads(file.read())
|
||||
no_json_name = filename.replace(".json", "")
|
||||
flow_endpoint_name = flow.get("endpoint_name")
|
||||
if _is_valid_uuid(no_json_name):
|
||||
flow["id"] = no_json_name
|
||||
flow_id = flow.get("id")
|
||||
|
||||
existing = find_existing_flow(session, flow_id, flow_endpoint_name)
|
||||
if existing:
|
||||
logger.info(f"Updating existing flow: {flow_id} with endpoint name {flow_endpoint_name}")
|
||||
for key, value in flow.items():
|
||||
setattr(existing, key, value)
|
||||
existing.updated_at = datetime.utcnow()
|
||||
existing.user_id = user_id
|
||||
session.add(existing)
|
||||
session.commit()
|
||||
else:
|
||||
logger.info(f"Creating new flow: {flow_id} with endpoint name {flow_endpoint_name}")
|
||||
flow["user_id"] = user_id
|
||||
flow = Flow.model_validate(flow, from_attributes=True)
|
||||
flow.updated_at = datetime.utcnow()
|
||||
session.add(flow)
|
||||
session.commit()
|
||||
|
||||
def find_existing_flow(session, flow_id, flow_endpoint_name):
|
||||
if flow_endpoint_name:
|
||||
stmt = select(Flow).where(Flow.endpoint_name == flow_endpoint_name)
|
||||
if existing := session.exec(stmt).first():
|
||||
return existing
|
||||
stmt = select(Flow).where(Flow.id == flow_id)
|
||||
if existing := session.exec(stmt).first():
|
||||
return existing
|
||||
return None
|
||||
def create_or_update_starter_projects():
|
||||
components_paths = get_settings_service().settings.components_path
|
||||
try:
|
||||
|
|
@ -249,3 +315,20 @@ def create_or_update_starter_projects():
|
|||
project_icon_bg_color,
|
||||
new_folder.id,
|
||||
)
|
||||
|
||||
|
||||
def initialize_super_user_if_needed():
|
||||
settings_service = get_settings_service()
|
||||
if not settings_service.auth_settings.AUTO_LOGIN:
|
||||
return
|
||||
username = settings_service.auth_settings.SUPERUSER
|
||||
password = settings_service.auth_settings.SUPERUSER_PASSWORD
|
||||
if not username or not password:
|
||||
raise ValueError("SUPERUSER and SUPERUSER_PASSWORD must be set in the settings if AUTO_LOGIN is true.")
|
||||
|
||||
with session_scope() as session:
|
||||
super_user = create_super_user(db=session, username=username, password=password)
|
||||
get_variable_service().initialize_user_variables(super_user.id, session)
|
||||
create_default_folder_if_it_doesnt_exist(session, super_user.id)
|
||||
session.commit()
|
||||
logger.info("Super user initialized")
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@
|
|||
"name": "template",
|
||||
"display_name": "Template",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -84,14 +86,22 @@
|
|||
"is_input": null,
|
||||
"is_output": null,
|
||||
"is_composition": null,
|
||||
"base_classes": ["object", "str", "Text"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"name": "",
|
||||
"display_name": "Prompt",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"template": ["user_input"]
|
||||
"template": [
|
||||
"user_input"
|
||||
]
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"full_path": null,
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
|
|
@ -140,7 +150,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"code": {
|
||||
"type": "code",
|
||||
|
|
@ -149,7 +161,7 @@
|
|||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float = 0.1,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
|
|
@ -223,7 +235,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_base": {
|
||||
"type": "str",
|
||||
|
|
@ -242,7 +256,9 @@
|
|||
"info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_key": {
|
||||
"type": "str",
|
||||
|
|
@ -261,7 +277,9 @@
|
|||
"info": "The OpenAI API Key to use for the OpenAI model.",
|
||||
"load_from_db": true,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": "OPENAI_API_KEY"
|
||||
},
|
||||
"stream": {
|
||||
|
|
@ -300,11 +318,13 @@
|
|||
"info": "System message to pass to the model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"temperature": {
|
||||
"type": "float",
|
||||
"required": true,
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
|
|
@ -331,7 +351,11 @@
|
|||
},
|
||||
"description": "Generates text using OpenAI LLMs.",
|
||||
"icon": "OpenAI",
|
||||
"base_classes": ["object", "Text", "str"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"Text",
|
||||
"str"
|
||||
],
|
||||
"display_name": "OpenAI",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -345,7 +369,9 @@
|
|||
"stream": null,
|
||||
"system_message": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [
|
||||
|
|
@ -416,7 +442,9 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -440,7 +468,9 @@
|
|||
"info": "In case of Message being a Record, this template will be used to convert it to text.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"return_record": {
|
||||
"type": "bool",
|
||||
|
|
@ -472,7 +502,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -480,7 +513,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -500,7 +535,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -519,13 +556,20 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a chat message in the Playground.",
|
||||
"icon": "ChatOutput",
|
||||
"base_classes": ["Record", "Text", "str", "object"],
|
||||
"base_classes": [
|
||||
"Record",
|
||||
"Text",
|
||||
"str",
|
||||
"object"
|
||||
],
|
||||
"display_name": "Chat Output",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -536,7 +580,10 @@
|
|||
"return_record": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -632,7 +679,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -640,7 +690,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -660,7 +712,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -679,13 +733,20 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Get chat inputs from the Playground.",
|
||||
"icon": "ChatInput",
|
||||
"base_classes": ["object", "Record", "str", "Text"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"Record",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"display_name": "Chat Input",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -695,7 +756,10 @@
|
|||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -716,18 +780,24 @@
|
|||
"edges": [
|
||||
{
|
||||
"source": "OpenAIModel-k39HS",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-k39HSœ}",
|
||||
"target": "ChatOutput-njtka",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-njtkaœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatOutput-njtka",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "Text", "str"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"Text",
|
||||
"str"
|
||||
],
|
||||
"dataType": "OpenAIModel",
|
||||
"id": "OpenAIModel-k39HS"
|
||||
}
|
||||
|
|
@ -736,22 +806,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-OpenAIModel-k39HS{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}-ChatOutput-njtka{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-OpenAIModel-k39HS{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-k39HSœ}-ChatOutput-njtka{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-njtkaœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "Prompt-uxBqP",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-uxBqPœ}",
|
||||
"target": "OpenAIModel-k39HS",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-k39HSœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "OpenAIModel-k39HS",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "str", "Text"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-uxBqP"
|
||||
}
|
||||
|
|
@ -760,22 +836,32 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-Prompt-uxBqP{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}-OpenAIModel-k39HS{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-Prompt-uxBqP{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-uxBqPœ}-OpenAIModel-k39HS{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-k39HSœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "ChatInput-P3fgL",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œRecordœ,œstrœ,œTextœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-P3fgLœ}",
|
||||
"target": "Prompt-uxBqP",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œuser_inputœ,œidœ:œPrompt-uxBqPœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "user_input",
|
||||
"id": "Prompt-uxBqP",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "Record", "str", "Text"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"Record",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "ChatInput",
|
||||
"id": "ChatInput-P3fgL"
|
||||
}
|
||||
|
|
@ -784,7 +870,7 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-ChatInput-P3fgL{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}-Prompt-uxBqP{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-ChatInput-P3fgL{œbaseClassesœ:[œobjectœ,œRecordœ,œstrœ,œTextœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-P3fgLœ}-Prompt-uxBqP{œfieldNameœ:œuser_inputœ,œidœ:œPrompt-uxBqPœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
|
|
@ -797,4 +883,4 @@
|
|||
"name": "Basic Prompting (Hello, World)",
|
||||
"last_tested_version": "1.0.0a4",
|
||||
"is_component": false
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,9 @@
|
|||
"name": "template",
|
||||
"display_name": "Template",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -136,14 +138,24 @@
|
|||
"is_input": null,
|
||||
"is_output": null,
|
||||
"is_composition": null,
|
||||
"base_classes": ["object", "Text", "str"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"Text",
|
||||
"str"
|
||||
],
|
||||
"name": "",
|
||||
"display_name": "Prompt",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"template": ["reference_1", "reference_2", "instructions"]
|
||||
"template": [
|
||||
"reference_1",
|
||||
"reference_2",
|
||||
"instructions"
|
||||
]
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"full_path": null,
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
|
|
@ -210,7 +222,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": [
|
||||
"https://www.promptingguide.ai/techniques/prompt_chaining"
|
||||
]
|
||||
|
|
@ -219,13 +233,17 @@
|
|||
},
|
||||
"description": "Fetch content from one or more URLs.",
|
||||
"icon": "layout-template",
|
||||
"base_classes": ["Record"],
|
||||
"base_classes": [
|
||||
"Record"
|
||||
],
|
||||
"display_name": "URL",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"urls": null
|
||||
},
|
||||
"output_types": ["Record"],
|
||||
"output_types": [
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -284,7 +302,9 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -308,7 +328,9 @@
|
|||
"info": "In case of Message being a Record, this template will be used to convert it to text.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"return_record": {
|
||||
"type": "bool",
|
||||
|
|
@ -340,7 +362,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -348,7 +373,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -368,7 +395,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -387,13 +416,20 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a chat message in the Playground.",
|
||||
"icon": "ChatOutput",
|
||||
"base_classes": ["Text", "Record", "object", "str"],
|
||||
"base_classes": [
|
||||
"Text",
|
||||
"Record",
|
||||
"object",
|
||||
"str"
|
||||
],
|
||||
"display_name": "Chat Output",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -404,7 +440,10 @@
|
|||
"return_record": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -444,7 +483,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"code": {
|
||||
"type": "code",
|
||||
|
|
@ -453,7 +494,7 @@
|
|||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float = 0.1,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
|
|
@ -527,7 +568,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_base": {
|
||||
"type": "str",
|
||||
|
|
@ -546,7 +589,9 @@
|
|||
"info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_key": {
|
||||
"type": "str",
|
||||
|
|
@ -565,7 +610,9 @@
|
|||
"info": "The OpenAI API Key to use for the OpenAI model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": "OPENAI_API_KEY"
|
||||
},
|
||||
"stream": {
|
||||
|
|
@ -604,11 +651,13 @@
|
|||
"info": "System message to pass to the model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"temperature": {
|
||||
"type": "float",
|
||||
"required": true,
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
|
|
@ -635,7 +684,11 @@
|
|||
},
|
||||
"description": "Generates text using OpenAI LLMs.",
|
||||
"icon": "OpenAI",
|
||||
"base_classes": ["str", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "OpenAI",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -649,7 +702,9 @@
|
|||
"stream": null,
|
||||
"system_message": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [
|
||||
|
|
@ -722,20 +777,28 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"value": ["https://www.promptingguide.ai/introduction/basics"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": [
|
||||
"https://www.promptingguide.ai/introduction/basics"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Fetch content from one or more URLs.",
|
||||
"icon": "layout-template",
|
||||
"base_classes": ["Record"],
|
||||
"base_classes": [
|
||||
"Record"
|
||||
],
|
||||
"display_name": "URL",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"urls": null
|
||||
},
|
||||
"output_types": ["Record"],
|
||||
"output_types": [
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -795,7 +858,10 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Value",
|
||||
"advanced": false,
|
||||
"input_types": ["Record", "Text"],
|
||||
"input_types": [
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "Text or Record to be passed as input.",
|
||||
"load_from_db": false,
|
||||
|
|
@ -819,20 +885,28 @@
|
|||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Get text inputs from the Playground.",
|
||||
"icon": "type",
|
||||
"base_classes": ["object", "Text", "str"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"Text",
|
||||
"str"
|
||||
],
|
||||
"display_name": "Instructions",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"input_value": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -854,18 +928,25 @@
|
|||
{
|
||||
"source": "URL-HYPkR",
|
||||
"target": "Prompt-Rse03",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"id": "reactflow__edge-URL-HYPkR{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-HYPkRœ}",
|
||||
"targetHandle": "{œfieldNameœ:œreference_2œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"id": "reactflow__edge-URL-HYPkR{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-HYPkRœ}-Prompt-Rse03{œfieldNameœ:œreference_2œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "reference_2",
|
||||
"id": "Prompt-Rse03",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["Record"],
|
||||
"baseClasses": [
|
||||
"Record"
|
||||
],
|
||||
"dataType": "URL",
|
||||
"id": "URL-HYPkR"
|
||||
}
|
||||
|
|
@ -878,18 +959,24 @@
|
|||
},
|
||||
{
|
||||
"source": "OpenAIModel-gi29P",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-gi29Pœ}",
|
||||
"target": "ChatOutput-JPlxl",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-JPlxlœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatOutput-JPlxl",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "Text", "object"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"dataType": "OpenAIModel",
|
||||
"id": "OpenAIModel-gi29P"
|
||||
}
|
||||
|
|
@ -898,22 +985,29 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-OpenAIModel-gi29P{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}-ChatOutput-JPlxl{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-OpenAIModel-gi29P{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-gi29Pœ}-ChatOutput-JPlxl{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-JPlxlœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "URL-2cX90",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-2cX90œ}",
|
||||
"target": "Prompt-Rse03",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œreference_1œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "reference_1",
|
||||
"id": "Prompt-Rse03",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["Record"],
|
||||
"baseClasses": [
|
||||
"Record"
|
||||
],
|
||||
"dataType": "URL",
|
||||
"id": "URL-2cX90"
|
||||
}
|
||||
|
|
@ -922,22 +1016,31 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-URL-2cX90{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-URL-2cX90{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-2cX90œ}-Prompt-Rse03{œfieldNameœ:œreference_1œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "TextInput-og8Or",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-og8Orœ}",
|
||||
"target": "Prompt-Rse03",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "instructions",
|
||||
"id": "Prompt-Rse03",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "Text", "str"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"Text",
|
||||
"str"
|
||||
],
|
||||
"dataType": "TextInput",
|
||||
"id": "TextInput-og8Or"
|
||||
}
|
||||
|
|
@ -946,22 +1049,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-TextInput-og8Or{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-TextInput-og8Or{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-og8Orœ}-Prompt-Rse03{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "Prompt-Rse03",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-Rse03œ}",
|
||||
"target": "OpenAIModel-gi29P",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-gi29Pœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "OpenAIModel-gi29P",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "Text", "str"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"Text",
|
||||
"str"
|
||||
],
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-Rse03"
|
||||
}
|
||||
|
|
@ -970,7 +1079,7 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-Prompt-Rse03{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}-OpenAIModel-gi29P{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"id": "reactflow__edge-Prompt-Rse03{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-Rse03œ}-OpenAIModel-gi29P{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-gi29Pœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"selected": false
|
||||
}
|
||||
],
|
||||
|
|
@ -984,4 +1093,4 @@
|
|||
"name": "Blog Writer",
|
||||
"last_tested_version": "1.0.0a0",
|
||||
"is_component": false
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,9 @@
|
|||
"name": "template",
|
||||
"display_name": "Template",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -110,14 +112,23 @@
|
|||
"is_input": null,
|
||||
"is_output": null,
|
||||
"is_composition": null,
|
||||
"base_classes": ["object", "str", "Text"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"name": "",
|
||||
"display_name": "Prompt",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"template": ["Document", "Question"]
|
||||
"template": [
|
||||
"Document",
|
||||
"Question"
|
||||
]
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"full_path": null,
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
|
|
@ -220,14 +231,18 @@
|
|||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "A generic file loader.",
|
||||
"base_classes": ["Record"],
|
||||
"base_classes": [
|
||||
"Record"
|
||||
],
|
||||
"display_name": "Files",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"path": null,
|
||||
"silent_errors": null
|
||||
},
|
||||
"output_types": ["Record"],
|
||||
"output_types": [
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -323,7 +338,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -331,7 +349,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -351,7 +371,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -370,13 +392,20 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Get chat inputs from the Playground.",
|
||||
"icon": "ChatInput",
|
||||
"base_classes": ["str", "Record", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Record",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "Chat Input",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -386,7 +415,10 @@
|
|||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -445,7 +477,9 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -481,7 +515,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -489,7 +526,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -509,7 +548,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -528,13 +569,20 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a chat message in the Playground.",
|
||||
"icon": "ChatOutput",
|
||||
"base_classes": ["str", "Record", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Record",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "Chat Output",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -544,7 +592,10 @@
|
|||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -589,7 +640,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"code": {
|
||||
"type": "code",
|
||||
|
|
@ -598,7 +651,7 @@
|
|||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float = 0.1,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
|
|
@ -672,7 +725,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_base": {
|
||||
"type": "str",
|
||||
|
|
@ -691,7 +746,9 @@
|
|||
"info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_key": {
|
||||
"type": "str",
|
||||
|
|
@ -710,7 +767,9 @@
|
|||
"info": "The OpenAI API Key to use for the OpenAI model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": "OPENAI_API_KEY"
|
||||
},
|
||||
"stream": {
|
||||
|
|
@ -749,11 +808,13 @@
|
|||
"info": "System message to pass to the model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"temperature": {
|
||||
"type": "float",
|
||||
"required": true,
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
|
|
@ -780,7 +841,11 @@
|
|||
},
|
||||
"description": "Generates text using OpenAI LLMs.",
|
||||
"icon": "OpenAI",
|
||||
"base_classes": ["object", "str", "Text"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"display_name": "OpenAI",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -794,7 +859,9 @@
|
|||
"stream": null,
|
||||
"system_message": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [
|
||||
|
|
@ -825,18 +892,28 @@
|
|||
"edges": [
|
||||
{
|
||||
"source": "ChatInput-MsSJ9",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œRecordœ,œTextœ,œobjectœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-MsSJ9œ}",
|
||||
"target": "Prompt-tHwPf",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œQuestionœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "Question",
|
||||
"id": "Prompt-tHwPf",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "Record", "Text", "object"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"Record",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"dataType": "ChatInput",
|
||||
"id": "ChatInput-MsSJ9"
|
||||
}
|
||||
|
|
@ -845,22 +922,29 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-ChatInput-MsSJ9{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-ChatInput-MsSJ9{œbaseClassesœ:[œstrœ,œRecordœ,œTextœ,œobjectœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-MsSJ9œ}-Prompt-tHwPf{œfieldNameœ:œQuestionœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "File-6TEsD",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-6TEsDœ}",
|
||||
"target": "Prompt-tHwPf",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œDocumentœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "Document",
|
||||
"id": "Prompt-tHwPf",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["Record"],
|
||||
"baseClasses": [
|
||||
"Record"
|
||||
],
|
||||
"dataType": "File",
|
||||
"id": "File-6TEsD"
|
||||
}
|
||||
|
|
@ -869,22 +953,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-File-6TEsD{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-File-6TEsD{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-6TEsDœ}-Prompt-tHwPf{œfieldNameœ:œDocumentœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "Prompt-tHwPf",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-tHwPfœ}",
|
||||
"target": "OpenAIModel-Bt067",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Bt067œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "OpenAIModel-Bt067",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "str", "Text"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-tHwPf"
|
||||
}
|
||||
|
|
@ -893,22 +983,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-Prompt-tHwPf{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}-OpenAIModel-Bt067{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-Prompt-tHwPf{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-tHwPfœ}-OpenAIModel-Bt067{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Bt067œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "OpenAIModel-Bt067",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Bt067œ}",
|
||||
"target": "ChatOutput-F5Awj",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-F5Awjœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatOutput-F5Awj",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "str", "Text"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "OpenAIModel",
|
||||
"id": "OpenAIModel-Bt067"
|
||||
}
|
||||
|
|
@ -917,7 +1013,7 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-OpenAIModel-Bt067{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}-ChatOutput-F5Awj{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-OpenAIModel-Bt067{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Bt067œ}-ChatOutput-F5Awj{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-F5Awjœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
|
|
@ -930,4 +1026,4 @@
|
|||
"name": "Document QA",
|
||||
"last_tested_version": "1.0.0a0",
|
||||
"is_component": false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"id": "08d5cccf-d098-4367-b14b-1078429c9ed9",
|
||||
"icon": "\ud83e\udd16",
|
||||
"icon": "🤖",
|
||||
"icon_bg_color": "#FFD700",
|
||||
"data": {
|
||||
"nodes": [
|
||||
|
|
@ -83,7 +83,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -91,7 +94,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -111,7 +116,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -130,14 +137,21 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": "MySessionID"
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Get chat inputs from the Playground.",
|
||||
"icon": "ChatInput",
|
||||
"base_classes": ["Text", "object", "Record", "str"],
|
||||
"base_classes": [
|
||||
"Text",
|
||||
"object",
|
||||
"Record",
|
||||
"str"
|
||||
],
|
||||
"display_name": "Chat Input",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -147,7 +161,10 @@
|
|||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -206,7 +223,9 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -242,7 +261,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -250,7 +272,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -270,7 +294,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -289,14 +315,21 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": "MySessionID"
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a chat message in the Playground.",
|
||||
"icon": "ChatOutput",
|
||||
"base_classes": ["Text", "object", "Record", "str"],
|
||||
"base_classes": [
|
||||
"Text",
|
||||
"object",
|
||||
"Record",
|
||||
"str"
|
||||
],
|
||||
"display_name": "Chat Output",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -306,7 +339,10 @@
|
|||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -382,7 +418,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Ascending", "Descending"],
|
||||
"options": [
|
||||
"Ascending",
|
||||
"Descending"
|
||||
],
|
||||
"name": "order",
|
||||
"display_name": "Order",
|
||||
"advanced": true,
|
||||
|
|
@ -390,7 +429,9 @@
|
|||
"info": "Order of the messages.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"record_template": {
|
||||
"type": "str",
|
||||
|
|
@ -410,7 +451,9 @@
|
|||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender": {
|
||||
"type": "str",
|
||||
|
|
@ -423,7 +466,11 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User", "Machine and User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User",
|
||||
"Machine and User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": false,
|
||||
|
|
@ -431,7 +478,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -450,7 +499,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -465,7 +516,9 @@
|
|||
"name": "session_id",
|
||||
"display_name": "Session ID",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "Session ID of the chat history.",
|
||||
"load_from_db": false,
|
||||
|
|
@ -476,7 +529,11 @@
|
|||
},
|
||||
"description": "Retrieves stored chat messages given a specific Session ID.",
|
||||
"icon": "history",
|
||||
"base_classes": ["str", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "Chat Memory",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -487,7 +544,9 @@
|
|||
"order": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -549,7 +608,9 @@
|
|||
"name": "template",
|
||||
"display_name": "Template",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -614,14 +675,23 @@
|
|||
"is_input": null,
|
||||
"is_output": null,
|
||||
"is_composition": null,
|
||||
"base_classes": ["Text", "str", "object"],
|
||||
"base_classes": [
|
||||
"Text",
|
||||
"str",
|
||||
"object"
|
||||
],
|
||||
"name": "",
|
||||
"display_name": "Prompt",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"template": ["context", "user_message"]
|
||||
"template": [
|
||||
"context",
|
||||
"user_message"
|
||||
]
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"full_path": null,
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
|
|
@ -670,7 +740,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"code": {
|
||||
"type": "code",
|
||||
|
|
@ -679,7 +751,7 @@
|
|||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float = 0.1,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
|
|
@ -753,7 +825,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_base": {
|
||||
"type": "str",
|
||||
|
|
@ -772,7 +846,9 @@
|
|||
"info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_key": {
|
||||
"type": "str",
|
||||
|
|
@ -791,7 +867,9 @@
|
|||
"info": "The OpenAI API Key to use for the OpenAI model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": "OPENAI_API_KEY"
|
||||
},
|
||||
"stream": {
|
||||
|
|
@ -830,11 +908,13 @@
|
|||
"info": "System message to pass to the model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"temperature": {
|
||||
"type": "float",
|
||||
"required": true,
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
|
|
@ -861,7 +941,11 @@
|
|||
},
|
||||
"description": "Generates text using OpenAI LLMs.",
|
||||
"icon": "OpenAI",
|
||||
"base_classes": ["str", "object", "Text"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"object",
|
||||
"Text"
|
||||
],
|
||||
"display_name": "OpenAI",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -875,7 +959,9 @@
|
|||
"stream": null,
|
||||
"system_message": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [
|
||||
|
|
@ -927,7 +1013,10 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Value",
|
||||
"advanced": false,
|
||||
"input_types": ["Record", "Text"],
|
||||
"input_types": [
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "Text or Record to be passed as output.",
|
||||
"load_from_db": false,
|
||||
|
|
@ -969,20 +1058,28 @@
|
|||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a text output in the Playground.",
|
||||
"icon": "type",
|
||||
"base_classes": ["str", "object", "Text"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"object",
|
||||
"Text"
|
||||
],
|
||||
"display_name": "Inspect Memory",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"input_value": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -1003,18 +1100,27 @@
|
|||
"edges": [
|
||||
{
|
||||
"source": "MemoryComponent-cdA1J",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}",
|
||||
"target": "Prompt-ODkUx",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œcontextœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "context",
|
||||
"type": "str",
|
||||
"id": "Prompt-ODkUx",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"]
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "Text", "object"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"dataType": "MemoryComponent",
|
||||
"id": "MemoryComponent-cdA1J"
|
||||
}
|
||||
|
|
@ -1023,23 +1129,33 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-MemoryComponent-cdA1J{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"id": "reactflow__edge-MemoryComponent-cdA1J{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}-Prompt-ODkUx{œfieldNameœ:œcontextœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"source": "ChatInput-t7F8v",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œTextœ,œobjectœ,œRecordœ,œstrœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-t7F8vœ}",
|
||||
"target": "Prompt-ODkUx",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "user_message",
|
||||
"type": "str",
|
||||
"id": "Prompt-ODkUx",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"]
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["Text", "object", "Record", "str"],
|
||||
"baseClasses": [
|
||||
"Text",
|
||||
"object",
|
||||
"Record",
|
||||
"str"
|
||||
],
|
||||
"dataType": "ChatInput",
|
||||
"id": "ChatInput-t7F8v"
|
||||
}
|
||||
|
|
@ -1048,23 +1164,29 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-ChatInput-t7F8v{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"id": "reactflow__edge-ChatInput-t7F8v{œbaseClassesœ:[œTextœ,œobjectœ,œRecordœ,œstrœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-t7F8vœ}-Prompt-ODkUx{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"source": "Prompt-ODkUx",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-ODkUxœ}",
|
||||
"target": "OpenAIModel-9RykF",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-9RykFœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "OpenAIModel-9RykF",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["Text", "str", "object"],
|
||||
"baseClasses": [
|
||||
"Text",
|
||||
"str",
|
||||
"object"
|
||||
],
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-ODkUx"
|
||||
}
|
||||
|
|
@ -1073,22 +1195,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-Prompt-ODkUx{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}-OpenAIModel-9RykF{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-Prompt-ODkUx{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-ODkUxœ}-OpenAIModel-9RykF{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-9RykFœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "OpenAIModel-9RykF",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œobjectœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-9RykFœ}",
|
||||
"target": "ChatOutput-P1jEe",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-P1jEeœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatOutput-P1jEe",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "object", "Text"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"object",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "OpenAIModel",
|
||||
"id": "OpenAIModel-9RykF"
|
||||
}
|
||||
|
|
@ -1097,22 +1225,29 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-OpenAIModel-9RykF{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}-ChatOutput-P1jEe{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-OpenAIModel-9RykF{œbaseClassesœ:[œstrœ,œobjectœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-9RykFœ}-ChatOutput-P1jEe{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-P1jEeœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "MemoryComponent-cdA1J",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}",
|
||||
"target": "TextOutput-vrs6T",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-vrs6Tœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "TextOutput-vrs6T",
|
||||
"inputTypes": ["Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "Text", "object"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"dataType": "MemoryComponent",
|
||||
"id": "MemoryComponent-cdA1J"
|
||||
}
|
||||
|
|
@ -1121,7 +1256,7 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-foreground stroke-connection",
|
||||
"id": "reactflow__edge-MemoryComponent-cdA1J{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-TextOutput-vrs6T{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-MemoryComponent-cdA1J{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}-TextOutput-vrs6T{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-vrs6Tœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
|
|
@ -1134,4 +1269,4 @@
|
|||
"name": "Memory Chatbot",
|
||||
"last_tested_version": "1.0.0a0",
|
||||
"is_component": false
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,9 @@
|
|||
"name": "template",
|
||||
"display_name": "Template",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -84,14 +86,22 @@
|
|||
"is_input": null,
|
||||
"is_output": null,
|
||||
"is_composition": null,
|
||||
"base_classes": ["object", "str", "Text"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"name": "",
|
||||
"display_name": "Prompt",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"template": ["document"]
|
||||
"template": [
|
||||
"document"
|
||||
]
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"full_path": null,
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
|
|
@ -155,7 +165,9 @@
|
|||
"name": "template",
|
||||
"display_name": "Template",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -194,14 +206,22 @@
|
|||
"is_input": null,
|
||||
"is_output": null,
|
||||
"is_composition": null,
|
||||
"base_classes": ["object", "str", "Text"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"name": "",
|
||||
"display_name": "Prompt",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"template": ["summary"]
|
||||
"template": [
|
||||
"summary"
|
||||
]
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"full_path": null,
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
|
|
@ -260,7 +280,9 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -284,7 +306,9 @@
|
|||
"info": "In case of Message being a Record, this template will be used to convert it to text.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"return_record": {
|
||||
"type": "bool",
|
||||
|
|
@ -316,7 +340,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -324,7 +351,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -344,7 +373,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -363,13 +394,20 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a chat message in the Playground.",
|
||||
"icon": "ChatOutput",
|
||||
"base_classes": ["object", "Record", "Text", "str"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"Record",
|
||||
"Text",
|
||||
"str"
|
||||
],
|
||||
"display_name": "Chat Output",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -380,7 +418,10 @@
|
|||
"return_record": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -435,7 +476,9 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
|
|
@ -459,7 +502,9 @@
|
|||
"info": "In case of Message being a Record, this template will be used to convert it to text.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"return_record": {
|
||||
"type": "bool",
|
||||
|
|
@ -491,7 +536,10 @@
|
|||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"options": [
|
||||
"Machine",
|
||||
"User"
|
||||
],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": true,
|
||||
|
|
@ -499,7 +547,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
|
|
@ -519,7 +569,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
|
|
@ -538,13 +590,20 @@
|
|||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a chat message in the Playground.",
|
||||
"icon": "ChatOutput",
|
||||
"base_classes": ["object", "Record", "Text", "str"],
|
||||
"base_classes": [
|
||||
"object",
|
||||
"Record",
|
||||
"Text",
|
||||
"str"
|
||||
],
|
||||
"display_name": "Chat Output",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -555,7 +614,10 @@
|
|||
"return_record": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"output_types": [
|
||||
"Text",
|
||||
"Record"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -610,7 +672,10 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Value",
|
||||
"advanced": false,
|
||||
"input_types": ["Record", "Text"],
|
||||
"input_types": [
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "Text or Record to be passed as input.",
|
||||
"load_from_db": false,
|
||||
|
|
@ -634,20 +699,28 @@
|
|||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Get text inputs from the Playground.",
|
||||
"icon": "type",
|
||||
"base_classes": ["str", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "Text Input",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"input_value": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -689,7 +762,10 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Value",
|
||||
"advanced": false,
|
||||
"input_types": ["Record", "Text"],
|
||||
"input_types": [
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "Text or Record to be passed as output.",
|
||||
"load_from_db": false,
|
||||
|
|
@ -731,20 +807,28 @@
|
|||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a text output in the Playground.",
|
||||
"icon": "type",
|
||||
"base_classes": ["str", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "First Prompt",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"input_value": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -789,7 +873,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"code": {
|
||||
"type": "code",
|
||||
|
|
@ -798,7 +884,7 @@
|
|||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float = 0.1,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
|
|
@ -872,7 +958,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_base": {
|
||||
"type": "str",
|
||||
|
|
@ -891,7 +979,9 @@
|
|||
"info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_key": {
|
||||
"type": "str",
|
||||
|
|
@ -910,7 +1000,9 @@
|
|||
"info": "The OpenAI API Key to use for the OpenAI model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": "OPENAI_API_KEY"
|
||||
},
|
||||
"stream": {
|
||||
|
|
@ -949,11 +1041,13 @@
|
|||
"info": "System message to pass to the model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"temperature": {
|
||||
"type": "float",
|
||||
"required": true,
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
|
|
@ -980,7 +1074,11 @@
|
|||
},
|
||||
"description": "Generates text using OpenAI LLMs.",
|
||||
"icon": "OpenAI",
|
||||
"base_classes": ["str", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "OpenAI",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -994,7 +1092,9 @@
|
|||
"stream": null,
|
||||
"system_message": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [
|
||||
|
|
@ -1046,7 +1146,10 @@
|
|||
"name": "input_value",
|
||||
"display_name": "Value",
|
||||
"advanced": false,
|
||||
"input_types": ["Record", "Text"],
|
||||
"input_types": [
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"dynamic": false,
|
||||
"info": "Text or Record to be passed as output.",
|
||||
"load_from_db": false,
|
||||
|
|
@ -1088,20 +1191,28 @@
|
|||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Display a text output in the Playground.",
|
||||
"icon": "type",
|
||||
"base_classes": ["str", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "Second Prompt",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"input_value": null,
|
||||
"record_template": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
|
|
@ -1146,7 +1257,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"code": {
|
||||
"type": "code",
|
||||
|
|
@ -1155,7 +1268,7 @@
|
|||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": MODEL_NAMES,\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float = 0.1,\n model_name: str = \"gpt-4o\",\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
|
|
@ -1229,7 +1342,9 @@
|
|||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_base": {
|
||||
"type": "str",
|
||||
|
|
@ -1248,7 +1363,9 @@
|
|||
"info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"openai_api_key": {
|
||||
"type": "str",
|
||||
|
|
@ -1267,7 +1384,9 @@
|
|||
"info": "The OpenAI API Key to use for the OpenAI model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"],
|
||||
"input_types": [
|
||||
"Text"
|
||||
],
|
||||
"value": ""
|
||||
},
|
||||
"stream": {
|
||||
|
|
@ -1306,11 +1425,13 @@
|
|||
"info": "System message to pass to the model.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
"input_types": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"temperature": {
|
||||
"type": "float",
|
||||
"required": true,
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
|
|
@ -1337,7 +1458,11 @@
|
|||
},
|
||||
"description": "Generates text using OpenAI LLMs.",
|
||||
"icon": "OpenAI",
|
||||
"base_classes": ["str", "Text", "object"],
|
||||
"base_classes": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"display_name": "OpenAI",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
|
|
@ -1351,7 +1476,9 @@
|
|||
"stream": null,
|
||||
"system_message": null
|
||||
},
|
||||
"output_types": ["Text"],
|
||||
"output_types": [
|
||||
"Text"
|
||||
],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [
|
||||
|
|
@ -1382,18 +1509,27 @@
|
|||
"edges": [
|
||||
{
|
||||
"source": "TextInput-sptaH",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-sptaHœ}",
|
||||
"target": "Prompt-amqBu",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œdocumentœ,œidœ:œPrompt-amqBuœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "document",
|
||||
"id": "Prompt-amqBu",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "Text", "object"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"dataType": "TextInput",
|
||||
"id": "TextInput-sptaH"
|
||||
}
|
||||
|
|
@ -1402,22 +1538,29 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-TextInput-sptaH{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}-Prompt-amqBu{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-TextInput-sptaH{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-sptaHœ}-Prompt-amqBu{œfieldNameœ:œdocumentœ,œidœ:œPrompt-amqBuœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "Prompt-amqBu",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}",
|
||||
"target": "TextOutput-2MS4a",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-2MS4aœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "TextOutput-2MS4a",
|
||||
"inputTypes": ["Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "str", "Text"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-amqBu"
|
||||
}
|
||||
|
|
@ -1426,22 +1569,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-Prompt-amqBu{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-TextOutput-2MS4a{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-TextOutput-2MS4a{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-2MS4aœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "Prompt-amqBu",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}",
|
||||
"target": "OpenAIModel-uYXZJ",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uYXZJœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "OpenAIModel-uYXZJ",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "str", "Text"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-amqBu"
|
||||
}
|
||||
|
|
@ -1450,22 +1599,31 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-Prompt-amqBu{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-OpenAIModel-uYXZJ{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-OpenAIModel-uYXZJ{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uYXZJœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "OpenAIModel-uYXZJ",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}",
|
||||
"target": "Prompt-gTNiz",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œsummaryœ,œidœ:œPrompt-gTNizœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "summary",
|
||||
"id": "Prompt-gTNiz",
|
||||
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Document",
|
||||
"BaseOutputParser",
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "Text", "object"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"dataType": "OpenAIModel",
|
||||
"id": "OpenAIModel-uYXZJ"
|
||||
}
|
||||
|
|
@ -1474,22 +1632,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-OpenAIModel-uYXZJ{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-Prompt-gTNiz{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-Prompt-gTNiz{œfieldNameœ:œsummaryœ,œidœ:œPrompt-gTNizœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "OpenAIModel-uYXZJ",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}",
|
||||
"target": "ChatOutput-EJkG3",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EJkG3œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatOutput-EJkG3",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "Text", "object"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"dataType": "OpenAIModel",
|
||||
"id": "OpenAIModel-uYXZJ"
|
||||
}
|
||||
|
|
@ -1498,22 +1662,29 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-OpenAIModel-uYXZJ{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-ChatOutput-EJkG3{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-ChatOutput-EJkG3{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EJkG3œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "Prompt-gTNiz",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}",
|
||||
"target": "TextOutput-MUDOR",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-MUDORœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "TextOutput-MUDOR",
|
||||
"inputTypes": ["Record", "Text"],
|
||||
"inputTypes": [
|
||||
"Record",
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "str", "Text"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-gTNiz"
|
||||
}
|
||||
|
|
@ -1522,22 +1693,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-Prompt-gTNiz{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-TextOutput-MUDOR{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-TextOutput-MUDOR{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-MUDORœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "Prompt-gTNiz",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}",
|
||||
"target": "OpenAIModel-XawYB",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XawYBœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "OpenAIModel-XawYB",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["object", "str", "Text"],
|
||||
"baseClasses": [
|
||||
"object",
|
||||
"str",
|
||||
"Text"
|
||||
],
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-gTNiz"
|
||||
}
|
||||
|
|
@ -1546,22 +1723,28 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-Prompt-gTNiz{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-OpenAIModel-XawYB{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-OpenAIModel-XawYB{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XawYBœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
},
|
||||
{
|
||||
"source": "OpenAIModel-XawYB",
|
||||
"sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}",
|
||||
"sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XawYBœ}",
|
||||
"target": "ChatOutput-DNmvg",
|
||||
"targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DNmvgœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatOutput-DNmvg",
|
||||
"inputTypes": ["Text"],
|
||||
"inputTypes": [
|
||||
"Text"
|
||||
],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["str", "Text", "object"],
|
||||
"baseClasses": [
|
||||
"str",
|
||||
"Text",
|
||||
"object"
|
||||
],
|
||||
"dataType": "OpenAIModel",
|
||||
"id": "OpenAIModel-XawYB"
|
||||
}
|
||||
|
|
@ -1570,7 +1753,7 @@
|
|||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-OpenAIModel-XawYB{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}-ChatOutput-DNmvg{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}"
|
||||
"id": "reactflow__edge-OpenAIModel-XawYB{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XawYBœ}-ChatOutput-DNmvg{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DNmvgœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
|
|
@ -1583,4 +1766,4 @@
|
|||
"name": "Prompt Chaining",
|
||||
"last_tested_version": "1.0.0a0",
|
||||
"is_component": false
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -14,7 +14,11 @@ from rich import print as rprint
|
|||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
|
||||
from langflow.api import router
|
||||
from langflow.initial_setup.setup import create_or_update_starter_projects
|
||||
from langflow.initial_setup.setup import (
|
||||
create_or_update_starter_projects,
|
||||
initialize_super_user_if_needed,
|
||||
load_flows_from_directory,
|
||||
)
|
||||
from langflow.interface.utils import setup_llm_caching
|
||||
from langflow.services.plugins.langfuse_plugin import LangfuseInstance
|
||||
from langflow.services.utils import initialize_services, teardown_services
|
||||
|
|
@ -33,22 +37,22 @@ class JavaScriptMIMETypeMiddleware(BaseHTTPMiddleware):
|
|||
return response
|
||||
|
||||
|
||||
def get_lifespan(fix_migration=False, socketio_server=None):
|
||||
from langflow.version import __version__ # type: ignore
|
||||
|
||||
def get_lifespan(fix_migration=False, socketio_server=None, version=None):
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
nest_asyncio.apply()
|
||||
# Startup message
|
||||
if __version__:
|
||||
rprint(f"[bold green]Starting Langflow v{__version__}...[/bold green]")
|
||||
if version:
|
||||
rprint(f"[bold green]Starting Langflow v{version}...[/bold green]")
|
||||
else:
|
||||
rprint("[bold green]Starting Langflow...[/bold green]")
|
||||
try:
|
||||
initialize_services(fix_migration=fix_migration, socketio_server=socketio_server)
|
||||
setup_llm_caching()
|
||||
LangfuseInstance.update()
|
||||
initialize_super_user_if_needed()
|
||||
create_or_update_starter_projects()
|
||||
load_flows_from_directory()
|
||||
yield
|
||||
except Exception as exc:
|
||||
if "langflow migration --fix" not in str(exc):
|
||||
|
|
@ -63,11 +67,17 @@ def get_lifespan(fix_migration=False, socketio_server=None):
|
|||
|
||||
def create_app():
|
||||
"""Create the FastAPI app and include the router."""
|
||||
try:
|
||||
from langflow.version import __version__ # type: ignore
|
||||
except ImportError:
|
||||
from importlib.metadata import version
|
||||
|
||||
__version__ = version("langflow-base")
|
||||
|
||||
configure()
|
||||
socketio_server = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*", logger=True)
|
||||
lifespan = get_lifespan(socketio_server=socketio_server)
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
lifespan = get_lifespan(socketio_server=socketio_server, version=__version__)
|
||||
app = FastAPI(lifespan=lifespan, title="Langflow", version=__version__)
|
||||
origins = ["*"]
|
||||
|
||||
app.add_middleware(
|
||||
|
|
|
|||
|
|
@ -76,11 +76,6 @@ async def get_current_user(
|
|||
if token:
|
||||
return await get_current_user_by_jwt(token, db)
|
||||
else:
|
||||
if not query_param and not header_param:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="An API key as query or header, or a JWT token must be passed",
|
||||
)
|
||||
user = await api_key_security(query_param, header_param, db)
|
||||
if user:
|
||||
return user
|
||||
|
|
@ -216,15 +211,14 @@ def create_super_user(
|
|||
|
||||
def create_user_longterm_token(db: Session = Depends(get_session)) -> tuple[UUID, dict]:
|
||||
settings_service = get_settings_service()
|
||||
|
||||
username = settings_service.auth_settings.SUPERUSER
|
||||
password = settings_service.auth_settings.SUPERUSER_PASSWORD
|
||||
if not username or not password:
|
||||
super_user = get_user_by_username(db, username)
|
||||
if not super_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Missing first superuser credentials",
|
||||
detail="Super user hasn't been created"
|
||||
)
|
||||
super_user = create_super_user(db=db, username=username, password=password)
|
||||
|
||||
access_token_expires_longterm = timedelta(days=365)
|
||||
access_token = create_token(
|
||||
data={"sub": str(super_user.id)},
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ from loguru import logger
|
|||
|
||||
from langflow.services.base import Service
|
||||
from langflow.services.cache.base import AsyncBaseCacheService, CacheService
|
||||
from langflow.services.cache.utils import CacheMiss
|
||||
|
||||
CACHE_MISS = CacheMiss()
|
||||
|
||||
|
||||
class ThreadingInMemoryCache(CacheService, Service):
|
||||
|
|
@ -341,12 +344,14 @@ class AsyncInMemoryCache(AsyncBaseCacheService, Service):
|
|||
|
||||
async def _get(self, key):
|
||||
item = self.cache.get(key, None)
|
||||
if item and (time.time() - item["time"] < self.expiration_time):
|
||||
self.cache.move_to_end(key)
|
||||
return pickle.loads(item["value"]) if isinstance(item["value"], bytes) else item["value"]
|
||||
if item:
|
||||
await self.delete(key)
|
||||
return None
|
||||
if time.time() - item["time"] < self.expiration_time:
|
||||
self.cache.move_to_end(key)
|
||||
return pickle.loads(item["value"]) if isinstance(item["value"], bytes) else item["value"]
|
||||
else:
|
||||
logger.info(f"Cache item for key '{key}' has expired and will be deleted.")
|
||||
await self.delete(key) # Log before deleting the expired item
|
||||
return CACHE_MISS
|
||||
|
||||
async def set(self, key, value, lock: Optional[asyncio.Lock] = None):
|
||||
if not lock:
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ CACHE_DIR = user_cache_dir("langflow", "langflow")
|
|||
PREFIX = "langflow_cache"
|
||||
|
||||
|
||||
class CacheMiss:
|
||||
def __repr__(self):
|
||||
return "<CACHE_MISS>"
|
||||
|
||||
|
||||
def create_cache_folder(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
# Get the destination folder
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class ChatService(Service):
|
|||
self._cache_locks = defaultdict(asyncio.Lock)
|
||||
self.cache_service = get_cache_service()
|
||||
|
||||
async def set_cache(self, flow_id: str, data: Any, lock: Optional[asyncio.Lock] = None) -> bool:
|
||||
async def set_cache(self, key: str, data: Any, lock: Optional[asyncio.Lock] = None) -> bool:
|
||||
"""
|
||||
Set the cache for a client.
|
||||
"""
|
||||
|
|
@ -23,17 +23,17 @@ class ChatService(Service):
|
|||
"result": data,
|
||||
"type": type(data),
|
||||
}
|
||||
await self.cache_service.upsert(flow_id, result_dict, lock=lock or self._cache_locks[flow_id])
|
||||
return flow_id in self.cache_service
|
||||
await self.cache_service.upsert(key, result_dict, lock=lock or self._cache_locks[key])
|
||||
return key in self.cache_service
|
||||
|
||||
async def get_cache(self, flow_id: str, lock: Optional[asyncio.Lock] = None) -> Any:
|
||||
async def get_cache(self, key: str, lock: Optional[asyncio.Lock] = None) -> Any:
|
||||
"""
|
||||
Get the cache for a client.
|
||||
"""
|
||||
return await self.cache_service.get(flow_id, lock=lock or self._cache_locks[flow_id])
|
||||
return await self.cache_service.get(key, lock=lock or self._cache_locks[key])
|
||||
|
||||
async def clear_cache(self, flow_id: str, lock: Optional[asyncio.Lock] = None):
|
||||
async def clear_cache(self, key: str, lock: Optional[asyncio.Lock] = None):
|
||||
"""
|
||||
Clear the cache for a client.
|
||||
"""
|
||||
await self.cache_service.delete(flow_id, lock=lock or self._cache_locks[flow_id])
|
||||
await self.cache_service.delete(key, lock=lock or self._cache_locks[key])
|
||||
|
|
|
|||
|
|
@ -15,4 +15,4 @@ class DatabaseServiceFactory(ServiceFactory):
|
|||
# Here you would have logic to create and configure a DatabaseService
|
||||
if not settings_service.settings.database_url:
|
||||
raise ValueError("No database URL provided")
|
||||
return DatabaseService(settings_service.settings.database_url)
|
||||
return DatabaseService(settings_service)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# Path: src/backend/langflow/services/database/models/flow/model.py
|
||||
|
||||
import re
|
||||
import warnings
|
||||
from datetime import datetime, timezone
|
||||
from typing import TYPE_CHECKING, Dict, Optional
|
||||
|
|
@ -7,7 +8,9 @@ from uuid import UUID, uuid4
|
|||
|
||||
import emoji
|
||||
from emoji import purely_emoji # type: ignore
|
||||
from fastapi import HTTPException, status
|
||||
from pydantic import field_serializer, field_validator
|
||||
from sqlalchemy import UniqueConstraint
|
||||
from sqlmodel import JSON, Column, Field, Relationship, SQLModel
|
||||
|
||||
from langflow.schema.schema import Record
|
||||
|
|
@ -25,7 +28,26 @@ class FlowBase(SQLModel):
|
|||
data: Optional[Dict] = Field(default=None, nullable=True)
|
||||
is_component: Optional[bool] = Field(default=False, nullable=True)
|
||||
updated_at: Optional[datetime] = Field(default_factory=lambda: datetime.now(timezone.utc), nullable=True)
|
||||
webhook: Optional[bool] = Field(default=False, nullable=True, description="Can be used on the webhook endpoint")
|
||||
folder_id: Optional[UUID] = Field(default=None, nullable=True)
|
||||
endpoint_name: Optional[str] = Field(default=None, nullable=True, index=True)
|
||||
|
||||
@field_validator("endpoint_name")
|
||||
@classmethod
|
||||
def validate_endpoint_name(cls, v):
|
||||
# Endpoint name must be a string containing only letters, numbers, hyphens, and underscores
|
||||
if v is not None:
|
||||
if not isinstance(v, str):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Endpoint name must be a string",
|
||||
)
|
||||
if not re.match(r"^[a-zA-Z0-9_-]+$", v):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Endpoint name must contain only letters, numbers, hyphens, and underscores",
|
||||
)
|
||||
return v
|
||||
|
||||
@field_validator("icon_bg_color")
|
||||
def validate_icon_bg_color(cls, v):
|
||||
|
|
@ -93,10 +115,15 @@ class FlowBase(SQLModel):
|
|||
|
||||
# updated_at can be serialized to JSON
|
||||
@field_serializer("updated_at")
|
||||
def serialize_dt(self, dt: datetime, _info):
|
||||
if dt is None:
|
||||
return None
|
||||
return dt.isoformat()
|
||||
def serialize_datetime(value):
|
||||
if isinstance(value, datetime):
|
||||
# I'm getting 2024-05-29T17:57:17.631346
|
||||
# and I want 2024-05-29T17:57:17-05:00
|
||||
value = value.replace(microsecond=0)
|
||||
if value.tzinfo is None:
|
||||
value = value.replace(tzinfo=timezone.utc)
|
||||
return value.isoformat()
|
||||
return value
|
||||
|
||||
@field_validator("updated_at", mode="before")
|
||||
def validate_dt(cls, v):
|
||||
|
|
@ -128,6 +155,11 @@ class Flow(FlowBase, table=True):
|
|||
record = Record(data=data)
|
||||
return record
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("user_id", "name", name="unique_flow_name"),
|
||||
UniqueConstraint("user_id", "endpoint_name", name="unique_flow_endpoint_name"),
|
||||
)
|
||||
|
||||
|
||||
class FlowCreate(FlowBase):
|
||||
user_id: Optional[UUID] = None
|
||||
|
|
@ -145,3 +177,21 @@ class FlowUpdate(SQLModel):
|
|||
description: Optional[str] = None
|
||||
data: Optional[Dict] = None
|
||||
folder_id: Optional[UUID] = None
|
||||
endpoint_name: Optional[str] = None
|
||||
|
||||
@field_validator("endpoint_name")
|
||||
@classmethod
|
||||
def validate_endpoint_name(cls, v):
|
||||
# Endpoint name must be a string containing only letters, numbers, hyphens, and underscores
|
||||
if v is not None:
|
||||
if not isinstance(v, str):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Endpoint name must be a string",
|
||||
)
|
||||
if not re.match(r"^[a-zA-Z0-9_-]+$", v):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Endpoint name must contain only letters, numbers, hyphens, and underscores",
|
||||
)
|
||||
return v
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlmodel import Session
|
||||
|
||||
from langflow.services.deps import get_session
|
||||
|
||||
from .model import Flow
|
||||
|
||||
|
||||
def get_flow_by_id(session: Session = Depends(get_session), flow_id: Optional[str] = None) -> Flow | None:
|
||||
"""Get flow by id."""
|
||||
|
||||
if flow_id is None:
|
||||
raise ValueError("Flow id is required.")
|
||||
|
||||
return session.get(Flow, flow_id)
|
||||
|
||||
|
||||
def get_webhook_component_in_flow(flow_data: dict):
|
||||
"""Get webhook component in flow data."""
|
||||
|
||||
for node in flow_data.get("nodes", []):
|
||||
if "Webhook" in node.get("id"):
|
||||
return node
|
||||
return None
|
||||
|
||||
|
||||
def get_all_webhook_components_in_flow(flow_data: dict | None):
|
||||
"""Get all webhook components in flow data."""
|
||||
if not flow_data:
|
||||
return []
|
||||
return [node for node in flow_data.get("nodes", []) if "Webhook" in node.get("id")]
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
from typing import TYPE_CHECKING, List, Optional
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from sqlalchemy import UniqueConstraint
|
||||
from sqlmodel import Field, Relationship, SQLModel
|
||||
|
||||
from langflow.services.database.models.flow.model import FlowRead
|
||||
|
|
@ -30,6 +31,8 @@ class Folder(FolderBase, table=True):
|
|||
back_populates="folder", sa_relationship_kwargs={"cascade": "all, delete, delete-orphan"}
|
||||
)
|
||||
|
||||
__table_args__ = (UniqueConstraint("user_id", "name", name="unique_folder_name"),)
|
||||
|
||||
|
||||
class FolderCreate(FolderBase):
|
||||
components_list: Optional[List[UUID]] = None
|
||||
|
|
|
|||
|
|
@ -21,12 +21,17 @@ from langflow.services.utils import teardown_superuser
|
|||
if TYPE_CHECKING:
|
||||
from sqlalchemy.engine import Engine
|
||||
|
||||
from langflow.services.settings.service import SettingsService
|
||||
|
||||
|
||||
class DatabaseService(Service):
|
||||
name = "database_service"
|
||||
|
||||
def __init__(self, database_url: str):
|
||||
self.database_url = database_url
|
||||
def __init__(self, settings_service: "SettingsService"):
|
||||
self.settings_service = settings_service
|
||||
if settings_service.settings.database_url is None:
|
||||
raise ValueError("No database URL provided")
|
||||
self.database_url: str = settings_service.settings.database_url
|
||||
# This file is in langflow.services.database.manager.py
|
||||
# the ini is in langflow
|
||||
langflow_dir = Path(__file__).parent.parent.parent
|
||||
|
|
@ -41,7 +46,12 @@ class DatabaseService(Service):
|
|||
connect_args = {"check_same_thread": False}
|
||||
else:
|
||||
connect_args = {}
|
||||
return create_engine(self.database_url, connect_args=connect_args)
|
||||
return create_engine(
|
||||
self.database_url,
|
||||
connect_args=connect_args,
|
||||
pool_size=self.settings_service.settings.pool_size,
|
||||
max_overflow=self.settings_service.settings.max_overflow,
|
||||
)
|
||||
|
||||
def __enter__(self):
|
||||
self._session = Session(self.engine)
|
||||
|
|
@ -267,3 +277,4 @@ class DatabaseService(Service):
|
|||
logger.error(f"Error tearing down database: {exc}")
|
||||
|
||||
self.engine.dispose()
|
||||
self.engine.dispose()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from langflow.services.deps import get_monitor_service
|
|||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.api.v1.schemas import ResultDataResponse
|
||||
from langflow.graph.vertex.base import Vertex
|
||||
|
||||
|
||||
INDEX_KEY = "index"
|
||||
|
|
@ -165,3 +166,35 @@ async def log_vertex_build(
|
|||
monitor_service.add_row(table_name="vertex_builds", data=row)
|
||||
except Exception as e:
|
||||
logger.exception(f"Error logging vertex build: {e}")
|
||||
|
||||
|
||||
def build_clean_params(target: "Vertex") -> dict:
|
||||
"""
|
||||
Cleans the parameters of the target vertex.
|
||||
"""
|
||||
# Removes all keys that the values aren't python types like str, int, bool, etc.
|
||||
params = {
|
||||
key: value for key, value in target.params.items() if isinstance(value, (str, int, bool, float, list, dict))
|
||||
}
|
||||
# if it is a list we need to check if the contents are python types
|
||||
for key, value in params.items():
|
||||
if isinstance(value, list):
|
||||
params[key] = [item for item in value if isinstance(item, (str, int, bool, float, list, dict))]
|
||||
return params
|
||||
|
||||
|
||||
def log_transaction(vertex: "Vertex", status, error=None):
|
||||
try:
|
||||
monitor_service = get_monitor_service()
|
||||
clean_params = build_clean_params(vertex)
|
||||
data = {
|
||||
"vertex_id": vertex.id,
|
||||
"inputs": clean_params,
|
||||
"output": str(vertex.result),
|
||||
"timestamp": monitor_service.get_timestamp(),
|
||||
"status": status,
|
||||
"error": error,
|
||||
}
|
||||
monitor_service.add_row(table_name="transactions", data=data)
|
||||
except Exception as e:
|
||||
logger.error(f"Error logging transaction: {e}")
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ class AuthSettings(BaseSettings):
|
|||
ACCESS_HTTPONLY: bool = False
|
||||
"""The HttpOnly attribute of the access token cookie."""
|
||||
|
||||
COOKIE_DOMAIN: str | None = None
|
||||
"""The domain attribute of the cookies. If None, the domain is not set."""
|
||||
|
||||
pwd_context: CryptContext = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
class Config:
|
||||
|
|
|
|||
|
|
@ -67,10 +67,16 @@ class Settings(BaseSettings):
|
|||
|
||||
dev: bool = False
|
||||
database_url: Optional[str] = None
|
||||
"""Database URL for Langflow. If not provided, Langflow will use a SQLite database."""
|
||||
pool_size: int = 10
|
||||
"""The number of connections to keep open in the connection pool. If not provided, the default is 10."""
|
||||
max_overflow: int = 10
|
||||
"""The number of connections to allow that can be opened beyond the pool size. If not provided, the default is 10."""
|
||||
cache_type: str = "async"
|
||||
remove_api_keys: bool = False
|
||||
components_path: List[str] = []
|
||||
langchain_cache: str = "InMemoryCache"
|
||||
load_flows_path: Optional[str] = None
|
||||
|
||||
# Redis
|
||||
redis_host: str = "localhost"
|
||||
|
|
@ -146,7 +152,13 @@ class Settings(BaseSettings):
|
|||
# if there is a database in that location
|
||||
if not info.data["config_dir"]:
|
||||
raise ValueError("config_dir not set, please set it or provide a database_url")
|
||||
from langflow.version import is_pre_release # type: ignore
|
||||
try:
|
||||
from langflow.version import is_pre_release # type: ignore
|
||||
except ImportError:
|
||||
from importlib import metadata
|
||||
|
||||
version = metadata.version("langflow-base")
|
||||
is_pre_release = "a" in version or "b" in version or "rc" in version
|
||||
|
||||
if info.data["save_db_in_config_dir"]:
|
||||
database_dir = info.data["config_dir"]
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ VARIABLES_TO_GET_FROM_ENVIRONMENT = [
|
|||
"PINECONE_API_KEY",
|
||||
"SEARCHAPI_API_KEY",
|
||||
"SERPAPI_API_KEY",
|
||||
"UPSTASH_VECTOR_REST_URL",
|
||||
"UPSTASH_VECTOR_REST_TOKEN",
|
||||
"VECTARA_CUSTOMER_ID",
|
||||
"VECTARA_CORPUS_ID",
|
||||
"VECTARA_API_KEY",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
from typing import Optional
|
||||
|
||||
import yaml
|
||||
from loguru import logger
|
||||
|
|
@ -7,7 +8,6 @@ from langflow.services.base import Service
|
|||
from langflow.services.settings.auth import AuthSettings
|
||||
from langflow.services.settings.base import Settings
|
||||
|
||||
|
||||
class SettingsService(Service):
|
||||
name = "settings_service"
|
||||
|
||||
|
|
@ -27,7 +27,6 @@ class SettingsService(Service):
|
|||
|
||||
with open(file_path, "r") as f:
|
||||
settings_dict = yaml.safe_load(f)
|
||||
settings_dict = {k.upper(): v for k, v in settings_dict.items()}
|
||||
|
||||
for key in settings_dict:
|
||||
if key not in Settings.model_fields.keys():
|
||||
|
|
|
|||
65
src/backend/base/langflow/utils/migration.py
Normal file
65
src/backend/base/langflow/utils/migration.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
from sqlalchemy.engine.reflection import Inspector
|
||||
|
||||
|
||||
def table_exists(name, conn):
|
||||
"""
|
||||
Check if a table exists.
|
||||
|
||||
Parameters:
|
||||
name (str): The name of the table to check.
|
||||
conn (sqlalchemy.engine.Engine or sqlalchemy.engine.Connection): The SQLAlchemy engine or connection to use.
|
||||
|
||||
Returns:
|
||||
bool: True if the table exists, False otherwise.
|
||||
"""
|
||||
inspector = Inspector.from_engine(conn)
|
||||
return name in inspector.get_table_names()
|
||||
|
||||
|
||||
def column_exists(table_name, column_name, conn):
|
||||
"""
|
||||
Check if a column exists in a table.
|
||||
|
||||
Parameters:
|
||||
table_name (str): The name of the table to check.
|
||||
column_name (str): The name of the column to check.
|
||||
conn (sqlalchemy.engine.Engine or sqlalchemy.engine.Connection): The SQLAlchemy engine or connection to use.
|
||||
|
||||
Returns:
|
||||
bool: True if the column exists, False otherwise.
|
||||
"""
|
||||
inspector = Inspector.from_engine(conn)
|
||||
return column_name in [column["name"] for column in inspector.get_columns(table_name)]
|
||||
|
||||
|
||||
def foreign_key_exists(table_name, fk_name, conn):
|
||||
"""
|
||||
Check if a foreign key exists in a table.
|
||||
|
||||
Parameters:
|
||||
table_name (str): The name of the table to check.
|
||||
fk_name (str): The name of the foreign key to check.
|
||||
conn (sqlalchemy.engine.Engine or sqlalchemy.engine.Connection): The SQLAlchemy engine or connection to use.
|
||||
|
||||
Returns:
|
||||
bool: True if the foreign key exists, False otherwise.
|
||||
"""
|
||||
inspector = Inspector.from_engine(conn)
|
||||
return fk_name in [fk["name"] for fk in inspector.get_foreign_keys(table_name)]
|
||||
|
||||
|
||||
def constraint_exists(table_name, constraint_name, conn):
|
||||
"""
|
||||
Check if a constraint exists in a table.
|
||||
|
||||
Parameters:
|
||||
table_name (str): The name of the table to check.
|
||||
constraint_name (str): The name of the constraint to check.
|
||||
conn (sqlalchemy.engine.Engine or sqlalchemy.engine.Connection): The SQLAlchemy engine or connection to use.
|
||||
|
||||
Returns:
|
||||
bool: True if the constraint exists, False otherwise.
|
||||
"""
|
||||
inspector = Inspector.from_engine(conn)
|
||||
constraints = inspector.get_unique_constraints(table_name)
|
||||
return constraint_name in [constraint["name"] for constraint in constraints]
|
||||
243
src/backend/base/poetry.lock
generated
243
src/backend/base/poetry.lock
generated
|
|
@ -264,13 +264,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2024.2.2"
|
||||
version = "2024.6.2"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"},
|
||||
{file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"},
|
||||
{file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"},
|
||||
{file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1224,18 +1224,18 @@ extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.
|
|||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langchain_core-0.2.1-py3-none-any.whl", hash = "sha256:3521e1e573988c47399fca9739270c5d34f8ecec147253ad829eb9ff288f76d5"},
|
||||
{file = "langchain_core-0.2.1.tar.gz", hash = "sha256:49383126168d934559a543ce812c485048d9e6ac9b6798fbf3d4a72b6bba5b0c"},
|
||||
{file = "langchain_core-0.2.3-py3-none-any.whl", hash = "sha256:22189b5a3a30bfd65eb995f95e627f7c2c3acb322feb89f5f5f2fb7df21833a7"},
|
||||
{file = "langchain_core-0.2.3.tar.gz", hash = "sha256:fbc75a64b9c0b7655d96ca57a707df1e6c09efc1539c36adbd73260612549810"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
jsonpatch = ">=1.33,<2.0"
|
||||
langsmith = ">=0.1.0,<0.2.0"
|
||||
langsmith = ">=0.1.65,<0.2.0"
|
||||
packaging = ">=23.2,<24.0"
|
||||
pydantic = ">=1,<3"
|
||||
PyYAML = ">=5.3"
|
||||
|
|
@ -1281,13 +1281,13 @@ extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "langchainhub"
|
||||
version = "0.1.16"
|
||||
version = "0.1.17"
|
||||
description = "The LangChain Hub API client"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langchainhub-0.1.16-py3-none-any.whl", hash = "sha256:a4379a1879cc6b441b8d02cc65e28a54f160fba61c9d1d4b0eddc3a276dff99a"},
|
||||
{file = "langchainhub-0.1.16.tar.gz", hash = "sha256:9f11e68fddb575e70ef4b28800eedbd9eeb180ba508def04f7153ea5b246b6fc"},
|
||||
{file = "langchainhub-0.1.17-py3-none-any.whl", hash = "sha256:4c609b3948252c71670f0d98f73413b515cfd2f6701a7b40ce959203e6133e04"},
|
||||
{file = "langchainhub-0.1.17.tar.gz", hash = "sha256:af7df0cb1cebc7a6e0864e8632ae48ecad39ed96568f699c78657b9d04e50b46"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -1296,13 +1296,13 @@ types-requests = ">=2.31.0.2,<3.0.0.0"
|
|||
|
||||
[[package]]
|
||||
name = "langsmith"
|
||||
version = "0.1.63"
|
||||
version = "0.1.67"
|
||||
description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langsmith-0.1.63-py3-none-any.whl", hash = "sha256:7810afdf5e3f3b472fc581a29371fb96cd843dde2149e048d1b9610325159d1e"},
|
||||
{file = "langsmith-0.1.63.tar.gz", hash = "sha256:a609405b52f6f54df442a142cbf19ab38662d54e532f96028b4c546434d4afdf"},
|
||||
{file = "langsmith-0.1.67-py3-none-any.whl", hash = "sha256:7eb2e1c1b375925ff47700ed8071e10c15e942e9d1d634b4a449a9060364071a"},
|
||||
{file = "langsmith-0.1.67.tar.gz", hash = "sha256:149558669a2ac4f21471cd964e61072687bba23b7c1ccb51f190a8f59b595b39"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -2104,18 +2104,18 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.7.1"
|
||||
version = "2.7.2"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"},
|
||||
{file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"},
|
||||
{file = "pydantic-2.7.2-py3-none-any.whl", hash = "sha256:834ab954175f94e6e68258537dc49402c4a5e9d0409b9f1b86b7e934a8372de7"},
|
||||
{file = "pydantic-2.7.2.tar.gz", hash = "sha256:71b2945998f9c9b7919a45bde9a50397b289937d215ae141c1d0903ba7149fd7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.4.0"
|
||||
pydantic-core = "2.18.2"
|
||||
pydantic-core = "2.18.3"
|
||||
typing-extensions = ">=4.6.1"
|
||||
|
||||
[package.extras]
|
||||
|
|
@ -2123,90 +2123,90 @@ email = ["email-validator (>=2.0.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.18.2"
|
||||
version = "2.18.3"
|
||||
description = "Core functionality for Pydantic validation and serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"},
|
||||
{file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"},
|
||||
{file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"},
|
||||
{file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"},
|
||||
{file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"},
|
||||
{file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"},
|
||||
{file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"},
|
||||
{file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:744697428fcdec6be5670460b578161d1ffe34743a5c15656be7ea82b008197c"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b40c05ced1ba4218b14986fe6f283d22e1ae2ff4c8e28881a70fb81fbfcda7"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:544a9a75622357076efb6b311983ff190fbfb3c12fc3a853122b34d3d358126c"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2e253af04ceaebde8eb201eb3f3e3e7e390f2d275a88300d6a1959d710539e2"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:855ec66589c68aa367d989da5c4755bb74ee92ccad4fdb6af942c3612c067e34"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d3e42bb54e7e9d72c13ce112e02eb1b3b55681ee948d748842171201a03a98a"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6ac9ffccc9d2e69d9fba841441d4259cb668ac180e51b30d3632cd7abca2b9b"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c56eca1686539fa0c9bda992e7bd6a37583f20083c37590413381acfc5f192d6"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17954d784bf8abfc0ec2a633108207ebc4fa2df1a0e4c0c3ccbaa9bb01d2c426"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:98ed737567d8f2ecd54f7c8d4f8572ca7c7921ede93a2e52939416170d357812"},
|
||||
{file = "pydantic_core-2.18.3-cp310-none-win32.whl", hash = "sha256:9f9e04afebd3ed8c15d67a564ed0a34b54e52136c6d40d14c5547b238390e779"},
|
||||
{file = "pydantic_core-2.18.3-cp310-none-win_amd64.whl", hash = "sha256:45e4ffbae34f7ae30d0047697e724e534a7ec0a82ef9994b7913a412c21462a0"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b9ebe8231726c49518b16b237b9fe0d7d361dd221302af511a83d4ada01183ab"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b8e20e15d18bf7dbb453be78a2d858f946f5cdf06c5072453dace00ab652e2b2"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d9ff283cd3459fa0bf9b0256a2b6f01ac1ff9ffb034e24457b9035f75587cb"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f7ef5f0ebb77ba24c9970da18b771711edc5feaf00c10b18461e0f5f5949231"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73038d66614d2e5cde30435b5afdced2b473b4c77d4ca3a8624dd3e41a9c19be"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6afd5c867a74c4d314c557b5ea9520183fadfbd1df4c2d6e09fd0d990ce412cd"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd7df92f28d351bb9f12470f4c533cf03d1b52ec5a6e5c58c65b183055a60106"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:80aea0ffeb1049336043d07799eace1c9602519fb3192916ff525b0287b2b1e4"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaee40f25bba38132e655ffa3d1998a6d576ba7cf81deff8bfa189fb43fd2bbe"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9128089da8f4fe73f7a91973895ebf2502539d627891a14034e45fb9e707e26d"},
|
||||
{file = "pydantic_core-2.18.3-cp311-none-win32.whl", hash = "sha256:fec02527e1e03257aa25b1a4dcbe697b40a22f1229f5d026503e8b7ff6d2eda7"},
|
||||
{file = "pydantic_core-2.18.3-cp311-none-win_amd64.whl", hash = "sha256:58ff8631dbab6c7c982e6425da8347108449321f61fe427c52ddfadd66642af7"},
|
||||
{file = "pydantic_core-2.18.3-cp311-none-win_arm64.whl", hash = "sha256:3fc1c7f67f34c6c2ef9c213e0f2a351797cda98249d9ca56a70ce4ebcaba45f4"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f0928cde2ae416a2d1ebe6dee324709c6f73e93494d8c7aea92df99aab1fc40f"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bee9bb305a562f8b9271855afb6ce00223f545de3d68560b3c1649c7c5295e9"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e862823be114387257dacbfa7d78547165a85d7add33b446ca4f4fae92c7ff5c"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a36f78674cbddc165abab0df961b5f96b14461d05feec5e1f78da58808b97e7"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba905d184f62e7ddbb7a5a751d8a5c805463511c7b08d1aca4a3e8c11f2e5048"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fdd362f6a586e681ff86550b2379e532fee63c52def1c666887956748eaa326"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b214b7ee3bd3b865e963dbed0f8bc5375f49449d70e8d407b567af3222aae4"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:691018785779766127f531674fa82bb368df5b36b461622b12e176c18e119022"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:60e4c625e6f7155d7d0dcac151edf5858102bc61bf959d04469ca6ee4e8381bd"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4e651e47d981c1b701dcc74ab8fec5a60a5b004650416b4abbef13db23bc7be"},
|
||||
{file = "pydantic_core-2.18.3-cp312-none-win32.whl", hash = "sha256:ffecbb5edb7f5ffae13599aec33b735e9e4c7676ca1633c60f2c606beb17efc5"},
|
||||
{file = "pydantic_core-2.18.3-cp312-none-win_amd64.whl", hash = "sha256:2c8333f6e934733483c7eddffdb094c143b9463d2af7e6bd85ebcb2d4a1b82c6"},
|
||||
{file = "pydantic_core-2.18.3-cp312-none-win_arm64.whl", hash = "sha256:7a20dded653e516a4655f4c98e97ccafb13753987434fe7cf044aa25f5b7d417"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:eecf63195be644b0396f972c82598cd15693550f0ff236dcf7ab92e2eb6d3522"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c44efdd3b6125419c28821590d7ec891c9cb0dff33a7a78d9d5c8b6f66b9702"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e59fca51ffbdd1638b3856779342ed69bcecb8484c1d4b8bdb237d0eb5a45e2"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70cf099197d6b98953468461d753563b28e73cf1eade2ffe069675d2657ed1d5"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63081a49dddc6124754b32a3774331467bfc3d2bd5ff8f10df36a95602560361"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:370059b7883485c9edb9655355ff46d912f4b03b009d929220d9294c7fd9fd60"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a64faeedfd8254f05f5cf6fc755023a7e1606af3959cfc1a9285744cc711044"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19d2e725de0f90d8671f89e420d36c3dd97639b98145e42fcc0e1f6d492a46dc"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:67bc078025d70ec5aefe6200ef094576c9d86bd36982df1301c758a9fff7d7f4"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:adf952c3f4100e203cbaf8e0c907c835d3e28f9041474e52b651761dc248a3c0"},
|
||||
{file = "pydantic_core-2.18.3-cp38-none-win32.whl", hash = "sha256:9a46795b1f3beb167eaee91736d5d17ac3a994bf2215a996aed825a45f897558"},
|
||||
{file = "pydantic_core-2.18.3-cp38-none-win_amd64.whl", hash = "sha256:200ad4e3133cb99ed82342a101a5abf3d924722e71cd581cc113fe828f727fbc"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:304378b7bf92206036c8ddd83a2ba7b7d1a5b425acafff637172a3aa72ad7083"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c826870b277143e701c9ccf34ebc33ddb4d072612683a044e7cce2d52f6c3fef"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e201935d282707394f3668380e41ccf25b5794d1b131cdd96b07f615a33ca4b1"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5560dda746c44b48bf82b3d191d74fe8efc5686a9ef18e69bdabccbbb9ad9442"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b32c2a1f8032570842257e4c19288eba9a2bba4712af542327de9a1204faff8"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:929c24e9dea3990bc8bcd27c5f2d3916c0c86f5511d2caa69e0d5290115344a9"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a8376fef60790152564b0eab376b3e23dd6e54f29d84aad46f7b264ecca943"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dccf3ef1400390ddd1fb55bf0632209d39140552d068ee5ac45553b556780e06"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:41dbdcb0c7252b58fa931fec47937edb422c9cb22528f41cb8963665c372caf6"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:666e45cf071669fde468886654742fa10b0e74cd0fa0430a46ba6056b24fb0af"},
|
||||
{file = "pydantic_core-2.18.3-cp39-none-win32.whl", hash = "sha256:f9c08cabff68704a1b4667d33f534d544b8a07b8e5d039c37067fceb18789e78"},
|
||||
{file = "pydantic_core-2.18.3-cp39-none-win_amd64.whl", hash = "sha256:4afa5f5973e8572b5c0dcb4e2d4fda7890e7cd63329bd5cc3263a25c92ef0026"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:77319771a026f7c7d29c6ebc623de889e9563b7087911b46fd06c044a12aa5e9"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:df11fa992e9f576473038510d66dd305bcd51d7dd508c163a8c8fe148454e059"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d531076bdfb65af593326ffd567e6ab3da145020dafb9187a1d131064a55f97c"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33ce258e4e6e6038f2b9e8b8a631d17d017567db43483314993b3ca345dcbbb"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1f9cd7f5635b719939019be9bda47ecb56e165e51dd26c9a217a433e3d0d59a9"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cd4a032bb65cc132cae1fe3e52877daecc2097965cd3914e44fbd12b00dae7c5"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f2718430098bcdf60402136c845e4126a189959d103900ebabb6774a5d9fdb"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c0037a92cf0c580ed14e10953cdd26528e8796307bb8bb312dc65f71547df04d"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b95a0972fac2b1ff3c94629fc9081b16371dad870959f1408cc33b2f78ad347a"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a62e437d687cc148381bdd5f51e3e81f5b20a735c55f690c5be94e05da2b0d5c"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b367a73a414bbb08507da102dc2cde0fa7afe57d09b3240ce82a16d608a7679c"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ecce4b2360aa3f008da3327d652e74a0e743908eac306198b47e1c58b03dd2b"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd4435b8d83f0c9561a2a9585b1de78f1abb17cb0cef5f39bf6a4b47d19bafe3"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:616221a6d473c5b9aa83fa8982745441f6a4a62a66436be9445c65f241b86c94"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7e6382ce89a92bc1d0c0c5edd51e931432202b9080dc921d8d003e616402efd1"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff58f379345603d940e461eae474b6bbb6dab66ed9a851ecd3cb3709bf4dcf6a"},
|
||||
{file = "pydantic_core-2.18.3.tar.gz", hash = "sha256:432e999088d85c8f36b9a3f769a8e2b57aabd817bbb729a90d1fe7f18f6f1f39"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -2214,17 +2214,17 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
|||
|
||||
[[package]]
|
||||
name = "pydantic-settings"
|
||||
version = "2.2.1"
|
||||
version = "2.3.0"
|
||||
description = "Settings management using Pydantic"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"},
|
||||
{file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"},
|
||||
{file = "pydantic_settings-2.3.0-py3-none-any.whl", hash = "sha256:26eeed27370a9c5e3f64e4a7d6602573cbedf05ed940f1d5b11c3f178427af7a"},
|
||||
{file = "pydantic_settings-2.3.0.tar.gz", hash = "sha256:78db28855a71503cfe47f39500a1dece523c640afd5280edb5c5c9c9cfa534c9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = ">=2.3.0"
|
||||
pydantic = ">=2.7.0"
|
||||
python-dotenv = ">=0.21.0"
|
||||
|
||||
[package.extras]
|
||||
|
|
@ -2466,13 +2466,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.32.2"
|
||||
version = "2.32.3"
|
||||
description = "Python HTTP for Humans."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"},
|
||||
{file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"},
|
||||
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
||||
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -2720,13 +2720,13 @@ typing-extensions = ">=3.7.4.3"
|
|||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.32.0.20240523"
|
||||
version = "2.32.0.20240602"
|
||||
description = "Typing stubs for requests"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "types-requests-2.32.0.20240523.tar.gz", hash = "sha256:26b8a6de32d9f561192b9942b41c0ab2d8010df5677ca8aa146289d11d505f57"},
|
||||
{file = "types_requests-2.32.0.20240523-py3-none-any.whl", hash = "sha256:f19ed0e2daa74302069bbbbf9e82902854ffa780bc790742a810a9aaa52f65ec"},
|
||||
{file = "types-requests-2.32.0.20240602.tar.gz", hash = "sha256:3f98d7bbd0dd94ebd10ff43a7fbe20c3b8528acace6d8efafef0b6a184793f06"},
|
||||
{file = "types_requests-2.32.0.20240602-py3-none-any.whl", hash = "sha256:ed3946063ea9fbc6b5fc0c44fa279188bae42d582cb63760be6cb4b9d06c3de8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -2734,13 +2734,13 @@ urllib3 = ">=2"
|
|||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.0"
|
||||
version = "4.12.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"},
|
||||
{file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"},
|
||||
{file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"},
|
||||
{file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2856,6 +2856,21 @@ files = [
|
|||
{file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uncurl"
|
||||
version = "0.0.11"
|
||||
description = "A library to convert curl requests to python-requests."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "uncurl-0.0.11-py3-none-any.whl", hash = "sha256:5961e93f07a5c9f2ef8ae4245bd92b0a6ce503c851de980f5b70080ae74cdc59"},
|
||||
{file = "uncurl-0.0.11.tar.gz", hash = "sha256:530c9bbd4d118f4cde6194165ff484cc25b0661cd256f19e9d5fcb53fc077790"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyperclip = "*"
|
||||
six = "*"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.2.1"
|
||||
|
|
@ -2875,13 +2890,13 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.29.0"
|
||||
version = "0.30.1"
|
||||
description = "The lightning-fast ASGI server."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "uvicorn-0.29.0-py3-none-any.whl", hash = "sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de"},
|
||||
{file = "uvicorn-0.29.0.tar.gz", hash = "sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0"},
|
||||
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"},
|
||||
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -3250,4 +3265,4 @@ local = []
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.10,<3.13"
|
||||
content-hash = "31d8e5ce045ef7d94e63058559b5f8181e6b51fc923c4904f45481443d59235d"
|
||||
content-hash = "48a7355a7096e763b75315d0704bed8f4d8134a33553e62bc305a686b9e72803"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "langflow-base"
|
||||
version = "0.0.50"
|
||||
version = "0.0.55"
|
||||
description = "A Python package with a built-in web application"
|
||||
authors = ["Langflow <contact@langflow.org>"]
|
||||
maintainers = [
|
||||
|
|
@ -28,7 +28,7 @@ langflow-base = "langflow.__main__:main"
|
|||
python = ">=3.10,<3.13"
|
||||
fastapi = "^0.111.0"
|
||||
httpx = "*"
|
||||
uvicorn = "^0.29.0"
|
||||
uvicorn = "^0.30.0"
|
||||
gunicorn = "^22.0.0"
|
||||
langchain = "~0.2.0"
|
||||
langchainhub = "~0.1.15"
|
||||
|
|
@ -62,6 +62,7 @@ emoji = "^2.12.0"
|
|||
cryptography = "^42.0.5"
|
||||
asyncer = "^0.0.5"
|
||||
pyperclip = "^1.8.2"
|
||||
uncurl = "^0.0.11"
|
||||
|
||||
|
||||
[tool.poetry.extras]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue