Skip to content

Commit

Permalink
Show AI function messages in editable input, fix empty initial message (
Browse files Browse the repository at this point in the history
  • Loading branch information
dqbd authored Nov 6, 2023
1 parent cfafce1 commit 77f1741
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 87 deletions.
27 changes: 22 additions & 5 deletions examples/widgets/server.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
#!/usr/bin/env python
"""Endpoint shows off available playground widgets."""
import base64
from json import dumps
from typing import Any, Dict, List, Tuple

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from langchain.document_loaders.blob_loaders import Blob
from langchain.document_loaders.parsers.pdf import PDFMinerParser
from langchain.schema.messages import BaseMessage, ChatMessage
from langchain.schema.messages import (
AIMessage,
BaseMessage,
FunctionMessage,
)
from langchain.schema.runnable import RunnableLambda
from pydantic import BaseModel, Field

Expand Down Expand Up @@ -43,9 +48,9 @@ class ChatHistory(BaseModel):
class ChatHistoryMessage(BaseModel):
chat_history: List[BaseMessage] = Field(
...,
extra={"widget": {"type": "chat", "input": "question"}},
extra={"widget": {"type": "chat", "input": "location", "output": "output"}},
)
question: str
location: str


class FileProcessingRequest(BaseModel):
Expand All @@ -61,9 +66,21 @@ def chat_with_bot(input: Dict[str, Any]) -> Dict[str, Any]:
}


def chat_message_bot(input: Dict[str, Any]) -> BaseMessage:
def chat_message_bot(input: Dict[str, Any]) -> List[BaseMessage]:
"""Bot that repeats the question twice."""
return ChatMessage(content=f"Hello: {input['question']}", role="example")
return [
AIMessage(
content="",
additional_kwargs={
"function_call": {
"name": "get_weather",
"arguments": dumps({"location": input["location"]}),
}
},
),
FunctionMessage(name="get_weather", content='{"value": 32}'),
AIMessage(content=f"Weather in {input['location']}: 32"),
]


def process_file(input: Dict[str, Any]) -> str:
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions langserve/playground/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<link rel="icon" href="/____LANGSERVE_BASE_URL/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Playground</title>
<script type="module" crossorigin src="/____LANGSERVE_BASE_URL/assets/index-5c0eb2c8.js"></script>
<link rel="stylesheet" href="/____LANGSERVE_BASE_URL/assets/index-50d7dbe4.css">
<script type="module" crossorigin src="/____LANGSERVE_BASE_URL/assets/index-7c3e1e1d.js"></script>
<link rel="stylesheet" href="/____LANGSERVE_BASE_URL/assets/index-c6cde0dd.css">
</head>
<body>
<div id="root"></div>
Expand Down
1 change: 1 addition & 0 deletions langserve/playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@mui/icons-material": "^5.14.11",
"@mui/material": "^5.14.11",
"@mui/x-date-pickers": "^6.16.0",
"@radix-ui/react-toggle-group": "^1.0.4",
"clsx": "^2.0.0",
"dayjs": "^1.11.10",
"fast-json-patch": "^3.1.1",
Expand Down
6 changes: 6 additions & 0 deletions langserve/playground/src/assets/ChatIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions langserve/playground/src/assets/CodeIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
154 changes: 134 additions & 20 deletions langserve/playground/src/components/ChatMessagesControlRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { withJsonFormsControlProps } from "@jsonforms/react";
import PlusIcon from "../assets/PlusIcon.svg?react";
import TrashIcon from "../assets/TrashIcon.svg?react";
import CodeIcon from "../assets/CodeIcon.svg?react";
import ChatIcon from "../assets/ChatIcon.svg?react";
import {
rankWith,
and,
Expand All @@ -12,6 +14,7 @@ import { AutosizeTextarea } from "./AutosizeTextarea";
import { useStreamCallback } from "../useStreamCallback";
import { traverseNaiveJsonPath } from "../utils/path";
import { isJsonSchemaExtra } from "../utils/schema";
import * as ToggleGroup from "@radix-ui/react-toggle-group";

export const chatMessagesTester = rankWith(
12,
Expand Down Expand Up @@ -101,6 +104,15 @@ function constructMessage(
return null;
}

function isOpenAiFunctionCall(
x: unknown
): x is { name: string; arguments: string } {
if (typeof x !== "object" || x == null) return false;
if (!("name" in x) || typeof x.name !== "string") return false;
if (!("arguments" in x) || typeof x.arguments !== "string") return false;
return true;
}

export const ChatMessagesControlRenderer = withJsonFormsControlProps(
(props) => {
const data: Array<MessageFields> = props.data ?? [];
Expand Down Expand Up @@ -155,6 +167,11 @@ export const ChatMessagesControlRenderer = withJsonFormsControlProps(
{data.map((message, index) => {
const msgPath = Paths.compose(props.path, `${index}`);
const type = message.type ?? "chat";

const isAiFunctionCall = isOpenAiFunctionCall(
message.additional_kwargs?.function_call
);

return (
<div className="control group" key={index}>
<div className="flex items-start justify-between gap-2">
Expand All @@ -175,17 +192,68 @@ export const ChatMessagesControlRenderer = withJsonFormsControlProps(

<option value="chat">Chat</option>
</select>
<button
className="p-1 border rounded opacity-0 transition-opacity border-divider-700 group-focus-within:opacity-100 group-hover:opacity-100"
onClick={() => {
props.handleChange(
props.path,
data.filter((_, i) => i !== index)
);
}}
>
<TrashIcon className="w-4 h-4" />
</button>
<div className="flex items-center gap-2">
{message.type === "ai" && (
<ToggleGroup.Root
type="single"
aria-label="Message Type"
className="opacity-0 transition-opacity group-focus-within:opacity-100 group-hover:opacity-100"
value={isAiFunctionCall ? "function" : "text"}
onValueChange={(value) => {
switch (value) {
case "function": {
props.handleChange(
Paths.compose(msgPath, "additional_kwargs"),
{
function_call: {
name: "",
arguments: "{}",
},
}
);

break;
}
case "text": {
props.handleChange(
Paths.compose(msgPath, "additional_kwargs"),
{}
);

break;
}
}
}}
>
<ToggleGroup.Item
className="rounded-s border border-divider-700 px-2.5 py-1 data-[state=on]:bg-divider-500/50"
value="text"
aria-label="Text message"
>
<ChatIcon className="w-4 h-4" />
</ToggleGroup.Item>
<ToggleGroup.Item
className="rounded-e border border-l-0 border-divider-700 px-2.5 py-1 data-[state=on]:bg-divider-500/50"
value="function"
aria-label="Function call"
>
<CodeIcon className="w-4 h-4" />
</ToggleGroup.Item>
</ToggleGroup.Root>
)}

<button
className="p-1 border rounded opacity-0 transition-opacity border-divider-700 group-focus-within:opacity-100 group-hover:opacity-100"
onClick={() => {
props.handleChange(
props.path,
data.filter((_, i) => i !== index)
);
}}
>
<TrashIcon className="w-4 h-4" />
</button>
</div>
</div>

{type === "chat" && (
Expand Down Expand Up @@ -216,15 +284,61 @@ export const ChatMessagesControlRenderer = withJsonFormsControlProps(
/>
)}

<AutosizeTextarea
value={message.content}
onChange={(content) => {
props.handleChange(
Paths.compose(msgPath, "content"),
content
);
}}
/>
{type === "ai" &&
isOpenAiFunctionCall(
message.additional_kwargs?.function_call
) ? (
<>
<input
className="mb-1"
placeholder="Function Name"
value={
message.additional_kwargs?.function_call.name ?? ""
}
onChange={(e) => {
console.log(
Paths.compose(
msgPath,
"additional_kwargs.function_call.name"
)
);
props.handleChange(
Paths.compose(
msgPath,
"additional_kwargs.function_call.name"
),
e.target.value
);
}}
/>

<AutosizeTextarea
value={
message.additional_kwargs?.function_call?.arguments ??
""
}
onChange={(content) => {
props.handleChange(
Paths.compose(
msgPath,
"additional_kwargs.function_call.arguments"
),
content
);
}}
/>
</>
) : (
<AutosizeTextarea
value={message.content}
onChange={(content) => {
props.handleChange(
Paths.compose(msgPath, "content"),
content
);
}}
/>
)}
</div>
);
})}
Expand Down
2 changes: 1 addition & 1 deletion langserve/playground/src/components/ShareDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ const result = await chain.invoke({ ... });
<div className="flex flex-col gap-2 p-3 rounded-2xl dark:bg-[#2C2C2E] bg-gray-100">
<div className="flex items-center gap-3">
<div className="w-10 h-10 flex items-center justify-center text-center text-sm bg-background rounded-xl">
<CodeIcon />
<CodeIcon className="w-4 h-4" />
</div>
<span className="font-semibold">Get the code</span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion langserve/playground/src/utils/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ const defaults = (schema: any, definitions: Record<string, any>): unknown => {
return [];
} else {
const values = [];
for (let i = 0; i < Math.max(1, ct); i++) {
for (let i = 0; i < Math.max(0, ct); i++) {
values.push(cloneJSON(value));
}
return values;
Expand Down
58 changes: 58 additions & 0 deletions langserve/playground/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,17 @@
dependencies:
"@babel/runtime" "^7.13.10"

"@radix-ui/[email protected]":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159"
integrity sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-slot" "1.0.2"

"@radix-ui/[email protected]":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989"
Expand Down Expand Up @@ -771,6 +782,13 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.5"

"@radix-ui/[email protected]":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b"
integrity sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==
dependencies:
"@babel/runtime" "^7.13.10"

"@radix-ui/[email protected]":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4"
Expand Down Expand Up @@ -833,6 +851,22 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-slot" "1.0.2"

"@radix-ui/[email protected]":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz#e90c4a6a5f6ac09d3b8c1f5b5e81aab2f0db1974"
integrity sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-collection" "1.0.3"
"@radix-ui/react-compose-refs" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-direction" "1.0.1"
"@radix-ui/react-id" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-callback-ref" "1.0.1"
"@radix-ui/react-use-controllable-state" "1.0.1"

"@radix-ui/[email protected]":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
Expand All @@ -841,6 +875,30 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.1"

"@radix-ui/react-toggle-group@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz#f5b5c8c477831b013bec3580c55e20a68179d6ec"
integrity sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-direction" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-roving-focus" "1.0.4"
"@radix-ui/react-toggle" "1.0.3"
"@radix-ui/react-use-controllable-state" "1.0.1"

"@radix-ui/[email protected]":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz#aecb2945630d1dc5c512997556c57aba894e539e"
integrity sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-controllable-state" "1.0.1"

"@radix-ui/[email protected]":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"
Expand Down

0 comments on commit 77f1741

Please sign in to comment.