Merge branch 'better_io' into state_theories

This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-03-03 22:26:39 -03:00
commit e8d047239e
46 changed files with 593 additions and 327 deletions

View file

@ -22,10 +22,10 @@ from langflow.services.auth.utils import get_current_active_user
from langflow.services.chat.service import ChatService
from langflow.services.deps import get_chat_service, get_session, get_session_service
from langflow.services.monitor.utils import log_vertex_build
from langflow.services.session.service import SessionService
if TYPE_CHECKING:
from langflow.graph.vertex.types import ChatVertex
from langflow.services.session.service import SessionService
router = APIRouter(tags=["Chat"])
@ -49,7 +49,8 @@ async def try_running_celery_task(vertex, user_id):
@router.get("/build/{flow_id}/vertices", response_model=VerticesOrderResponse)
async def get_vertices(
flow_id: str,
component_id: Optional[str] = None,
stop_component_id: Optional[str] = None,
start_component_id: Optional[str] = None,
chat_service: "ChatService" = Depends(get_chat_service),
session=Depends(get_session),
):
@ -60,9 +61,9 @@ async def get_vertices(
if cache := chat_service.get_cache(flow_id):
graph = cache.get("result")
graph = build_and_cache_graph(flow_id, session, chat_service, graph)
if component_id:
if stop_component_id or start_component_id:
try:
vertices = graph.sort_vertices(component_id)
vertices = graph.sort_vertices(stop_component_id, start_component_id)
except Exception as exc:
logger.error(exc)
vertices = graph.sort_vertices()
@ -94,6 +95,7 @@ async def build_vertex(
"""Build a vertex instead of the entire graph."""
{"inputs": {"input_value": "some value"}}
start_time = time.perf_counter()
next_vertices_ids = []
try:
start_time = time.perf_counter()
cache = chat_service.get_cache(flow_id)
@ -123,6 +125,10 @@ async def build_vertex(
artifacts = vertex.artifacts
else:
raise ValueError(f"No result found for vertex {vertex_id}")
next_vertices_ids = vertex.successors_ids
next_vertices_ids = [
v for v in next_vertices_ids if graph.should_run_vertex(v)
]
result_data_response = ResultDataResponse(**result_dict.model_dump())
@ -160,9 +166,16 @@ async def build_vertex(
graph.reset_activated_vertices()
chat_service.set_cache(flow_id, graph)
# graph.stop_vertex tells us if the user asked
# to stop the build of the graph at a certain vertex
# if it is in next_vertices_ids, we need to remove other
# vertices from next_vertices_ids
if graph.stop_vertex and graph.stop_vertex in next_vertices_ids:
next_vertices_ids = [graph.stop_vertex]
build_response = VertexBuildResponse(
inactivated_vertices=inactivated_vertices,
activated_layers=activated_layers,
next_vertices_ids=next_vertices_ids,
valid=valid,
params=params,
id=vertex.id,

View file

@ -216,7 +216,7 @@ class ApiKeyCreateRequest(BaseModel):
class VerticesOrderResponse(BaseModel):
ids: List[List[str]]
ids: List[str]
run_id: UUID
@ -230,7 +230,7 @@ class ResultDataResponse(BaseModel):
class VertexBuildResponse(BaseModel):
id: Optional[str] = None
inactivated_vertices: Optional[List[str]] = None
activated_layers: Optional[List[List[str]]] = None
next_vertices_ids: Optional[List[str]] = None
valid: bool
params: Optional[str]
"""JSON string of the params."""

View file

@ -31,16 +31,12 @@ class ConversationChainComponent(CustomComponent):
chain = ConversationChain(llm=llm)
else:
chain = ConversationChain(llm=llm, memory=memory)
result = chain.invoke({chain.input_key: input_value})
# result is an AIMessage which is a subclass of BaseMessage
# We need to check if it is a string or a BaseMessage
result_str: Text = ""
result = chain.invoke(inputs)
if hasattr(result, "content") and isinstance(result.content, str):
result_str = result.content
result = result.content
elif isinstance(result, str):
result_str = result
result = result
else:
# is dict
result_str = Text(result.get("response"))
self.status = result_str
return result_str
result = result.get("response")
self.status = result
return result

View file

@ -0,0 +1,48 @@
# Implement ShouldRunNext component
from langchain_core.prompts import PromptTemplate
from langflow import CustomComponent
from langflow.field_typing import BaseLanguageModel, Prompt
class ShouldRunNext(CustomComponent):
display_name = "Should Run Next"
description = "Decides whether to run the next component."
def build_config(self):
return {
"prompt": {
"display_name": "Prompt",
"info": "The prompt to use for the decision. It should generate a boolean response (True or False).",
},
"llm": {
"display_name": "LLM",
"info": "The language model to use for the decision.",
},
}
def build(self, template: Prompt, llm: BaseLanguageModel, **kwargs) -> bool:
# This is a simple component that always returns True
prompt_template = PromptTemplate.from_template(template)
attributes_to_check = ["text", "page_content"]
for key, value in kwargs.items():
for attribute in attributes_to_check:
if hasattr(value, attribute):
kwargs[key] = getattr(value, attribute)
chain = prompt_template | llm
result = chain.invoke(kwargs)
if hasattr(result, "content") and isinstance(result.content, str):
result = result.content
elif isinstance(result, str):
result = result
else:
result = result.get("response")
if result.lower() not in ["true", "false"]:
raise ValueError("The prompt should generate a boolean response (True or False).")
# The string should be the words true or false
# if not raise an error
bool_result = result.lower() == "true"
return bool_result

View file

@ -1,5 +1,6 @@
import asyncio
from collections import defaultdict, deque
from itertools import chain
from typing import TYPE_CHECKING, Dict, Generator, List, Optional, Type, Union
from langchain.chains.base import Chain
@ -59,6 +60,11 @@ class Graph:
self._edges = self._graph_data["edges"]
self.inactivated_vertices: set = set()
self.activated_layers: List[List[str]] = []
self.vertices_layers = []
self.vertices_to_run = set()
self.stop_vertex = None
self.inactive_vertices: set = set()
self.edges: List[ContractEdge] = []
self.vertices: List[Vertex] = []
self._build_graph()
@ -191,6 +197,14 @@ class Graph:
outputs.extend(run_outputs)
return outputs
# vertices_layers is a list of lists ordered by the order the vertices
# should be built.
# We need to create a new method that will take the vertices_layers
# and return the next vertex to be built.
def next_vertex_to_build(self):
"""Returns the next vertex to be built."""
yield from chain.from_iterable(self.vertices_layers)
@property
def metadata(self):
return {
@ -336,9 +350,14 @@ class Graph:
# Add new vertices
for vertex_id in new_vertex_ids:
new_vertex = other.get_vertex(vertex_id)
new_vertex.graph = self
self._add_vertex(new_vertex)
# Now update the edges
for vertex_id in new_vertex_ids:
new_vertex = other.get_vertex(vertex_id)
self._update_edges(new_vertex)
new_vertex.graph = self
# Update existing vertices that have changed
for vertex_id in existing_vertex_ids.intersection(other_vertex_ids):
self_vertex = self.get_vertex(vertex_id)
@ -385,12 +404,24 @@ class Graph:
_vertex._build_params()
def _add_vertex(self, vertex: Vertex) -> None:
"""Adds a new vertex to the graph."""
"""Adds a vertex to the graph."""
self.vertices.append(vertex)
self.vertex_map[vertex.id] = vertex
def add_vertex(self, vertex: Vertex) -> None:
"""Adds a new vertex to the graph."""
self._add_vertex(vertex)
self._update_edges(vertex)
def _update_edges(self, vertex: Vertex) -> None:
"""Updates the edges of a vertex."""
# Vertex has edges, so we need to update the edges
for edge in vertex.edges:
if edge.source_id in self.vertex_map and edge.target_id in self.vertex_map:
if (
edge not in self.edges
and edge.source_id in self.vertex_map
and edge.target_id in self.vertex_map
):
self.edges.append(edge)
def _build_graph(self) -> None:
@ -722,7 +753,7 @@ class Graph:
)
return f"Graph:\nNodes: {vertex_ids}\nConnections:\n{edges_repr}"
def sort_up_to_vertex(self, vertex_id: str) -> List[Vertex]:
def sort_up_to_vertex(self, vertex_id: str, is_start: bool = False) -> List[Vertex]:
"""Cuts the graph up to a given vertex and sorts the resulting subgraph."""
# Initial setup
visited = set() # To keep track of visited vertices
@ -756,11 +787,19 @@ class Graph:
if current_id == vertex_id:
# We should add to visited all the vertices that are successors of the current vertex
# and their successors and so on
# if the vertex is a start, it means we are starting from the beginning
# and getting successors
for successor in current_vertex.successors:
excluded.add(successor.id)
if is_start:
stack.append(successor.id)
else:
excluded.add(successor.id)
all_successors = get_successors(successor)
for successor in all_successors:
excluded.add(successor.id)
if is_start:
stack.append(successor.id)
else:
excluded.add(successor.id)
# Filter the original graph's vertices and edges to keep only those in `visited`
vertices_to_keep = [self.get_vertex(vid) for vid in visited]
@ -871,12 +910,19 @@ class Graph:
return vertices_layers
def sort_vertices(self, component_id: Optional[str] = None) -> List[List[str]]:
def sort_vertices(
self,
stop_component_id: Optional[str] = None,
start_component_id: Optional[str] = None,
) -> List[str]:
"""Sorts the vertices in the graph."""
self.mark_all_vertices("ACTIVE")
if component_id:
vertices = self.sort_up_to_vertex(component_id)
vertices_layers = self.layered_topological_sort(vertices)
if stop_component_id:
self.stop_vertex = stop_component_id
vertices = self.sort_up_to_vertex(stop_component_id)
elif start_component_id:
vertices = self.sort_up_to_vertex(start_component_id, is_start=True)
else:
vertices = self.vertices
# without component_id we are probably running in the chat
@ -886,10 +932,23 @@ class Graph:
vertices, filter_graphs=True
)
vertices_layers = self.sort_by_avg_build_time(vertices_layers)
vertices_layers = self.sort_chat_inputs_first(vertices_layers)
# vertices_layers = self.sort_chat_inputs_first(vertices_layers)
self.increment_run_count()
self._sorted_vertices_layers = vertices_layers
return vertices_layers
first_layer = vertices_layers[0]
# save the only the rest
self.vertices_layers = vertices_layers[1:]
self.vertices_to_run = {
vertex for vertex in chain.from_iterable(vertices_layers)
}
# Return just the first layer
return first_layer
def should_run_vertex(self, vertex_id: str) -> bool:
"""Returns whether a component should be run."""
should_run = vertex_id in self.vertices_to_run
if should_run:
self.vertices_to_run.remove(vertex_id)
return should_run
def sort_interface_components_first(
self, vertices_layers: List[List[str]]

View file

@ -47,7 +47,10 @@ class VertexTypesDict(LazyLoadDictBase):
**{t: types.DocumentLoaderVertex for t in documentloader_creator.to_list()},
**{t: types.TextSplitterVertex for t in textsplitter_creator.to_list()},
**{t: types.OutputParserVertex for t in output_parser_creator.to_list()},
**{t: types.CustomComponentVertex for t in custom_component_creator.to_list()},
**{
t: types.CustomComponentVertex
for t in custom_component_creator.to_list()
},
**{t: types.RetrieverVertex for t in retriever_creator.to_list()},
**{t: types.ChatVertex for t in CHAT_COMPONENTS},
**{t: types.RoutingVertex for t in ROUTING_COMPONENTS},

View file

@ -2,13 +2,26 @@ import ast
import inspect
import types
from enum import Enum
from typing import (TYPE_CHECKING, Any, AsyncIterator, Callable, Coroutine,
Dict, Iterator, List, Optional)
from typing import (
TYPE_CHECKING,
Any,
AsyncIterator,
Callable,
Coroutine,
Dict,
Iterator,
List,
Optional,
)
from loguru import logger
from langflow.graph.schema import (INPUT_COMPONENTS, OUTPUT_COMPONENTS,
InterfaceComponentTypes, ResultData)
from langflow.graph.schema import (
INPUT_COMPONENTS,
OUTPUT_COMPONENTS,
InterfaceComponentTypes,
ResultData,
)
from langflow.graph.utils import UnbuiltObject, UnbuiltResult
from langflow.graph.vertex.utils import generate_result
from langflow.interface.initialize import loading
@ -152,6 +165,10 @@ class Vertex:
def successors(self) -> List["Vertex"]:
return self.graph.get_successors(self)
@property
def successors_ids(self) -> List[str]:
return self.graph.successor_map.get(self.id, [])
def __getstate__(self):
return {
"_data": self._data,
@ -594,9 +611,6 @@ class Vertex:
raise ValueError(
f"You are trying to stream to a {self.display_name}. Try using a Chat Output instead."
)
raise ValueError(
f"{self.display_name}: You are trying to stream to a non-streamable component."
)
def _reset(self, params_update: Optional[Dict[str, Any]] = None):
self._built = False
@ -606,6 +620,9 @@ class Vertex:
self.steps_ran = []
self._build_params()
def _is_chat_input(self):
return False
def build_inactive(self):
# Just set the results to None
self._built = True
@ -632,7 +649,7 @@ class Vertex:
return await self.get_requester_result(requester)
self._reset()
if self.is_input and inputs is not None:
if self._is_chat_input() and inputs is not None:
self.update_raw_params(inputs)
# Run steps

View file

@ -6,7 +6,7 @@ import yaml
from langchain_core.messages import AIMessage
from loguru import logger
from langflow.graph.schema import INPUT_FIELD_NAME
from langflow.graph.schema import INPUT_FIELD_NAME, InterfaceComponentTypes
from langflow.graph.utils import UnbuiltObject, flatten_list, serialize_field
from langflow.graph.vertex.base import Vertex
from langflow.interface.utils import extract_input_variables_from_prompt
@ -455,18 +455,30 @@ class ChatVertex(Vertex):
async for _ in self.stream():
pass
def _is_chat_input(self):
return self.vertex_type == InterfaceComponentTypes.ChatInput and self.is_input
class RoutingVertex(Vertex):
def __init__(self, data: Dict, graph):
super().__init__(data, graph=graph, base_type="custom_components")
self.use_result = True
self.steps = [self._build, self._run]
self.steps = [self._build]
def _built_object_repr(self):
if self.artifacts and "repr" in self.artifacts:
return self.artifacts["repr"] or super()._built_object_repr()
return super()._built_object_repr()
@property
def successors_ids(self):
if isinstance(self._built_object, bool):
ids = super().successors_ids
if self._built_object:
return ids
return []
raise ValueError("RoutingVertex should return a boolean value.")
def _run(self, *args, **kwargs):
if self._built_object:
condition = self._built_object.get("condition")

View file

@ -17,10 +17,10 @@ import TextAreaComponent from "../../../../components/textAreaComponent";
import ToggleShadComponent from "../../../../components/toggleShadComponent";
import { Button } from "../../../../components/ui/button";
import {
INPUT_HANDLER_HOVER,
LANGFLOW_SUPPORTED_TYPES,
OUTPUT_HANDLER_HOVER,
TOOLTIP_EMPTY,
inputHandleHover,
outputHandleHover,
} from "../../../../constants/constants";
import { postCustomComponentUpdate } from "../../../../controllers/API";
import useAlertStore from "../../../../stores/alertStore";
@ -182,7 +182,7 @@ export default function ParameterComponent({
return (
<div key={index}>
{index === 0 && (
<span>{left ? inputHandleHover : outputHandleHover}</span>
<span>{left ? INPUT_HANDLER_HOVER : OUTPUT_HANDLER_HOVER}</span>
)}
<span
key={index}
@ -304,7 +304,10 @@ export default function ParameterComponent({
ref={ref}
className={
"relative mt-1 flex w-full flex-wrap items-center justify-between bg-muted px-5 py-2" +
(name === "code" ? " hidden " : "")
((name === "code" && type === "code") ||
(name.includes("code") && proxy)
? " hidden "
: "")
}
>
<>

View file

@ -9,9 +9,9 @@ import Loading from "../../components/ui/loading";
import { Textarea } from "../../components/ui/textarea";
import Xmark from "../../components/ui/xmark";
import {
STATUS_BUILD,
STATUS_BUILDING,
priorityFields,
statusBuild,
statusBuilding,
} from "../../constants/constants";
import { BuildStatus } from "../../constants/enums";
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
@ -49,7 +49,12 @@ export default function GenericNode({
const [nodeDescription, setNodeDescription] = useState(
data.node?.description!
);
const buildStatus = useFlowStore((state) => state.flowBuildStatus[data.id]);
const buildStatus = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.status
);
const lastRunTime = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.timestamp
);
const [validationStatus, setValidationStatus] =
useState<validationStatusType | null>(null);
const [handles, setHandles] = useState<number>(0);
@ -332,8 +337,8 @@ export default function GenericNode({
/>
</div>
) : (
<div className="group flex items-center gap-2.5">
<ShadTooltip content={data.id}>
<div className="group flex items-start gap-1.5">
<ShadTooltip content={data.node?.display_name}>
<div
onDoubleClick={(event) => {
if (nameEditable) {
@ -359,8 +364,8 @@ export default function GenericNode({
}}
>
<IconComponent
name="Pencil"
className="hidden h-4 w-4 animate-pulse text-status-blue group-hover:block"
name="PencilLine"
className="hidden h-3 w-3 text-status-blue group-hover:block"
/>
</div>
)}
@ -390,13 +395,34 @@ export default function GenericNode({
})}
data={data}
color={
nodeColors[
types[data.node?.template[templateField].type!]
] ??
nodeColors[
data.node?.template[templateField].type!
] ??
nodeColors.unknown
data.node?.template[templateField].input_types &&
data.node?.template[templateField].input_types!
.length > 0
? nodeColors[
data.node?.template[templateField]
.input_types![
data.node?.template[templateField]
.input_types!.length - 1
]
] ??
nodeColors[
types[
data.node?.template[templateField]
.input_types![
data.node?.template[templateField]
.input_types!.length - 1
]
]
]
: nodeColors[
data.node?.template[templateField].type!
] ??
nodeColors[
types[
data.node?.template[templateField].type!
]
] ??
nodeColors.unknown
}
title={getFieldTitle(
data.node?.template!,
@ -458,23 +484,14 @@ export default function GenericNode({
)}
</div>
{showNode && (
<Button
variant="secondary"
className={"group h-9 px-1.5"}
onClick={() => {
if (buildStatus === BuildStatus.BUILDING || isBuilding)
return;
setValidationStatus(null);
buildFlow({ nodeId: data.id });
}}
>
<Button variant="secondary" className={"group h-9 px-1.5"}>
<div>
<ShadTooltip
content={
buildStatus === BuildStatus.BUILDING ? (
<span> {statusBuilding} </span>
<span> {STATUS_BUILDING} </span>
) : !validationStatus ? (
<span className="flex">{statusBuild}</span>
<span className="flex">{STATUS_BUILD}</span>
) : (
<div className="max-h-96 overflow-auto">
{typeof validationStatus.params === "string"
@ -489,7 +506,15 @@ export default function GenericNode({
}
side="bottom"
>
<div className="generic-node-status-position flex items-center justify-center">
<div
onClick={() => {
if (buildStatus === BuildStatus.BUILDING || isBuilding)
return;
setValidationStatus(null);
buildFlow({ stopNodeId: data.id });
}}
className="generic-node-status-position flex items-center justify-center"
>
{renderIconStatus(buildStatus, validationStatus)}
</div>
</ShadTooltip>
@ -607,13 +632,18 @@ export default function GenericNode({
data.node?.template[templateField].input_types!
.length > 0
? nodeColors[
data.node?.template[templateField]
.input_types![0]
data.node?.template[templateField].input_types![
data.node?.template[templateField]
.input_types!.length - 1
]
] ??
nodeColors[
types[
data.node?.template[templateField]
.input_types![0]
.input_types![
data.node?.template[templateField]
.input_types!.length - 1
]
]
]
: nodeColors[
@ -695,6 +725,15 @@ export default function GenericNode({
showNode={showNode}
/>
)}
<div>
{lastRunTime && (
<div className="flex justify-center text-muted-foreground">
{lastRunTime.split("\n").map((line, index) => (
<div key={index}>{line}</div>
))}
</div>
)}
</div>
</>
</div>
)}

View file

@ -6,7 +6,7 @@ import {
PopoverContent,
PopoverTrigger,
} from "../../components/ui/popover";
import { zeroNotifications } from "../../constants/constants";
import { ZERO_NOTIFICATIONS } from "../../constants/constants";
import useAlertStore from "../../stores/alertStore";
import { AlertDropdownType } from "../../types/alerts";
import SingleAlert from "./components/singleAlertComponent";
@ -70,7 +70,7 @@ export default function AlertDropdown({
))
) : (
<div className="flex h-full w-full items-center justify-center pb-16 text-ring">
{zeroNotifications}
{ZERO_NOTIFICATIONS}
</div>
)}
</div>

View file

@ -17,7 +17,7 @@ export default function IOOutputView({
case "TextOutput":
return (
<Textarea
className="w-full h-full custom-scroll"
className="w-full custom-scroll"
placeholder={"Empty"}
// update to real value on flowPool
value={
@ -31,7 +31,7 @@ export default function IOOutputView({
default:
return (
<Textarea
className="w-full h-full custom-scroll"
className="w-full custom-scroll"
placeholder={"Enter text..."}
value={node.data.node!.template["input_value"]}
onChange={(e) => {

View file

@ -1,12 +1,13 @@
import { useEffect, useState } from "react";
import {
CHAT_FORM_DIALOG_SUBTITLE,
outputsModalTitle,
textInputModalTitle,
OUTPUTS_MODAL_TITLE,
TEXT_INPUT_MODAL_TITLE,
} from "../../constants/constants";
import BaseModal from "../../modals/baseModal";
import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { NodeType } from "../../types/flow";
import { updateVerticesOrder } from "../../utils/buildUtils";
import { cn } from "../../utils/utils";
import AccordionComponent from "../AccordionComponent";
@ -51,6 +52,7 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
const [chatValue, setChatValue] = useState("");
const isBuilding = useFlowStore((state) => state.isBuilding);
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
const setNode = useFlowStore((state) => state.setNode);
async function updateVertices() {
return updateVerticesOrder(currentFlow!.id, null);
@ -68,12 +70,22 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
setLockChat(true);
setChatValue("");
for (let i = 0; i < count; i++) {
await buildFlow({ input_value: chatValue }).catch((err) => {
await buildFlow({
input_value: chatValue,
startNodeId: chatInput?.id,
}).catch((err) => {
console.error(err);
setLockChat(false);
});
}
setLockChat(false);
if (chatInput) {
setNode(chatInput.id, (node: NodeType) => {
const newNode = { ...node };
newNode.data.node!.template["input_value"].value = chatValue;
return newNode;
});
}
}
useEffect(() => {
@ -135,7 +147,7 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
>
<div className="mx-2 mb-2 flex items-center gap-2 text-sm font-bold">
<IconComponent className="h-4 w-4" name={"Type"} />
{textInputModalTitle}
{TEXT_INPUT_MODAL_TITLE}
</div>
{nodes
.filter((node) =>
@ -196,7 +208,7 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
>
<div className="mx-2 mb-2 flex items-center gap-2 text-sm font-bold">
<IconComponent className="h-4 w-4" name={"FileType2"} />
{outputsModalTitle}
{OUTPUTS_MODAL_TITLE}
</div>
{nodes
.filter((node) =>
@ -220,7 +232,7 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
>
<div>
<Badge variant="gray" size="md">
{output.displayName}
{node.data.node.display_name}
</Badge>
</div>
</ShadTooltip>
@ -263,7 +275,7 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
)}
{haveChat ? (
<div className="flex h-full w-full">
<div className="flex h-full min-w-96 flex-grow">
{selectedViewField && (
<div
className={cn(

View file

@ -14,7 +14,8 @@ export default function CodeAreaComponent({
setNodeClass,
id = "",
readonly = false,
openModal,
open,
setOpen,
}: CodeAreaComponentType) {
const [myValue, setMyValue] = useState(
typeof value == "string" ? value : JSON.stringify(value)
@ -33,7 +34,8 @@ export default function CodeAreaComponent({
return (
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
<CodeAreaModal
openModal={openModal}
open={open}
setOpen={setOpen}
readonly={readonly}
dynamic={dynamic}
value={myValue}

View file

@ -193,9 +193,9 @@ export default function CodeTabsComponent({
></div>
)}
<SyntaxHighlighter
className="mt-0 h-full w-full overflow-auto custom-scroll"
language={tab.mode}
language={tab.language}
style={oneDark}
className="mt-0 h-full overflow-auto custom-scroll rounded-sm text-left"
>
{tab.code}
</SyntaxHighlighter>

View file

@ -9,7 +9,7 @@ import {
import { useNavigate } from "react-router-dom";
import { Node } from "reactflow";
import { savedHover } from "../../../../constants/constants";
import { SAVED_HOVER } from "../../../../constants/constants";
import FlowSettingsModal from "../../../../modals/flowSettingsModal";
import useAlertStore from "../../../../stores/alertStore";
import useFlowStore from "../../../../stores/flowStore";
@ -128,7 +128,7 @@ export const MenuBar = ({
</div>
<ShadTooltip
content={
savedHover +
SAVED_HOVER +
new Date(currentFlow.updated_at ?? "").toLocaleString("en-US", {
hour: "numeric",
minute: "numeric",

View file

@ -2,8 +2,8 @@ import { useEffect, useState } from "react";
import IconComponent from "../../../components/genericIconComponent";
import { Textarea } from "../../../components/ui/textarea";
import {
chatInputPlaceholder,
chatInputPlaceholderSend,
CHAT_INPUT_PLACEHOLDER,
CHAT_INPUT_PLACEHOLDER_SEND,
} from "../../../constants/constants";
import useFlowsManagerStore from "../../../stores/flowsManagerStore";
import { chatInputType } from "../../../types/components";
@ -84,7 +84,7 @@ export default function ChatInput({
"form-modal-lockchat"
)}
placeholder={
noInput ? chatInputPlaceholder : chatInputPlaceholderSend
noInput ? CHAT_INPUT_PLACEHOLDER : CHAT_INPUT_PLACEHOLDER_SEND
}
/>
<div className="form-modal-send-icon-position">

View file

@ -108,7 +108,7 @@ export default function ChatMessage({
chat.isSend ? "" : " "
)}
>
<div className={classNames("form-modal-chatbot-icon ")}>
<div className={classNames("form-modal-chatbot-icon")}>
{!chat.isSend ? (
<div className="form-modal-chat-image">
<div className="form-modal-chat-bot-icon ">
@ -134,7 +134,7 @@ export default function ChatMessage({
)}
</div>
{!chat.isSend ? (
<div className="form-modal-chat-text-position">
<div className="form-modal-chat-text-position flex-grow min-w-96">
<div className="form-modal-chat-text">
{hidden && chat.thought && chat.thought !== "" && (
<div
@ -155,9 +155,9 @@ export default function ChatMessage({
/>
)}
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
<div className="w-full">
<div className="w-full dark:text-white">
<div className="w-full">
<div className="w-full flex flex-col">
<div className="w-full flex flex-col dark:text-white">
<div className="w-full flex flex-col">
{useMemo(
() =>
chatMessage === "" && lockChat ? (
@ -169,7 +169,7 @@ export default function ChatMessage({
<Markdown
remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeMathjax]}
className="markdown prose min-w-full text-primary word-break-break-word
className="markdown flex flex-col prose text-primary word-break-break-word
dark:prose-invert"
components={{
pre({ node, ...props }) {

View file

@ -2,8 +2,8 @@ import { useEffect, useRef, useState } from "react";
import IconComponent from "../../components/genericIconComponent";
import { NOCHATOUTPUT_NOTICE_ALERT } from "../../constants/alerts_constants";
import {
chatFirstInitialText,
chatSecondInitialText,
CHAT_FIRST_INITIAL_TEXT,
CHAT_SECOND_INITIAL_TEXT,
} from "../../constants/constants";
import { deleteFlowPool } from "../../controllers/API";
import useAlertStore from "../../stores/alertStore";
@ -182,14 +182,14 @@ export default function NewChatView({
<br />
<div className="langflow-chat-desc">
<span className="langflow-chat-desc-span">
{chatFirstInitialText}{" "}
{CHAT_FIRST_INITIAL_TEXT}{" "}
<span>
<IconComponent
name="MessageSquare"
className="mx-1 inline h-5 w-5 animate-bounce "
/>
</span>{" "}
{chatSecondInitialText}
{CHAT_SECOND_INITIAL_TEXT}
</span>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show more