Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nc/playground #19

Merged
merged 62 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
e5dd755
Add /playground endpoint that serves an playground UI with support fo…
nfcampos Oct 5, 2023
b315ed7
Update lock file
nfcampos Oct 5, 2023
8c3aba7
Lint
nfcampos Oct 5, 2023
7d4bcdc
Lint
nfcampos Oct 5, 2023
a150be3
Try to fix reload on error
nfcampos Oct 9, 2023
e3d2c5f
Fix types for schema
dqbd Oct 13, 2023
ae51653
Force every input to be multiline
dqbd Oct 14, 2023
30a0f70
Remove unused asset
dqbd Oct 14, 2023
44e8d7b
Move playground to langserve folder
dqbd Oct 14, 2023
8c91429
Add makefile command
dqbd Oct 14, 2023
5f1b9c8
Use 8000 for every example, resolve playground from every path
dqbd Oct 14, 2023
fd8cfc3
Rough draft of styles
dqbd Oct 17, 2023
d2b9570
Fix dark mode
dqbd Oct 17, 2023
2d9e756
Add share button
dqbd Oct 17, 2023
ce9161d
Copy to clipboard, parse the contents
dqbd Oct 17, 2023
85320dc
hide from schema
nfcampos Oct 17, 2023
4b2c893
Lock
nfcampos Oct 17, 2023
eb0e97f
Lint
nfcampos Oct 17, 2023
786b7e3
Update path and api docs
nfcampos Oct 17, 2023
5b2ee13
Merge branch 'main' into nc/playground
nfcampos Oct 17, 2023
dfab212
Temporary change
dqbd Oct 17, 2023
e47494c
Further style changes
dqbd Oct 17, 2023
c0ade47
Update url, fix defaults
nfcampos Oct 17, 2023
9b5fe14
Add built files
nfcampos Oct 17, 2023
bd88473
apply config in schemas endpoints
nfcampos Oct 18, 2023
43a0de0
Replace icon, use share button
dqbd Oct 18, 2023
0a8538c
Cleanup styles
dqbd Oct 18, 2023
1bf88e8
Cleanup share
dqbd Oct 18, 2023
cc6484d
Add code snippets
dqbd Oct 18, 2023
fd01b78
Pointer events, use correct color
dqbd Oct 18, 2023
73ff692
Hack the overdrag
dqbd Oct 18, 2023
9d4d56a
Fix serving of non-text files
nfcampos Oct 18, 2023
4208e5d
Add new built files
nfcampos Oct 18, 2023
acef4d7
Add iframe handling
dqbd Oct 18, 2023
dc23a3c
Add initial version of embeddable SDK
dqbd Oct 18, 2023
ee451b1
Handle value sync
dqbd Oct 18, 2023
c4e1a31
New build
dqbd Oct 18, 2023
a211178
New build
nfcampos Oct 18, 2023
7225efe
Use input type
nfcampos Oct 18, 2023
20f2f01
oops
nfcampos Oct 18, 2023
cc8d69e
Now in playground too
nfcampos Oct 18, 2023
6210639
Do not apply defaults for input schema
nfcampos Oct 18, 2023
d37fce3
Add separator
dqbd Oct 19, 2023
3df9fe8
Add better validation error styles
dqbd Oct 19, 2023
ca06ab2
Refresh check icon
dqbd Oct 19, 2023
bd5d8cd
Fix dark theme for errors, move validation stuff to the top-right
dqbd Oct 19, 2023
144eb07
Version 0.0.10 bump (#50)
eyurtsev Oct 17, 2023
05f11af
Update default to match langchain (#51)
nfcampos Oct 18, 2023
24d96b7
Add CONTRIBUTING.md guidelines (#54)
eyurtsev Oct 18, 2023
4878d83
Minor fix in contribution guidelines (#55)
eyurtsev Oct 18, 2023
a54d7df
Adds custom array and text controls
jacoblee93 Oct 19, 2023
37f4f3c
Update test case
jacoblee93 Oct 19, 2023
001c924
Cleanup styles
dqbd Oct 19, 2023
063e10f
Resolve maximum call stack size exceeded for schemas with root $ref
nfcampos Oct 19, 2023
d800c10
Copy changes
nfcampos Oct 19, 2023
33cf1f3
Resolve all refs before passing to jsonforms
nfcampos Oct 19, 2023
020f4e7
Add json cell
nfcampos Oct 19, 2023
14b9c5f
Lint
nfcampos Oct 19, 2023
5ee72a5
Initial work on cleaning up styles
dqbd Oct 19, 2023
20f0458
Fix dark mode for icons
dqbd Oct 19, 2023
6ef8a25
Update built files
nfcampos Oct 19, 2023
174f47f
Update built files
nfcampos Oct 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,5 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

.envrc
51 changes: 51 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Contributing

## Contributor License Agreement

We are grateful to the contributors who help evolve LangServe and dedicate their time to the project. As the primary sponsor of LangServe, LangChain, Inc. aims to build products in the open that benefit thousands of developers while allowing us to build a sustainable business. For all code contributions to LangServe, we ask that contributors complete and sign a Contributor License Agreement (“CLA”). The agreement between contributors and the project is explicit, so LangServe users can be confident in the legal status of the source code and their right to use it.The CLA does not change the terms of the underlying license, LangServe License, used by our software.

Before you can contribute to LangServe, a bot will comment on the PR asking you to agree to the CLA if you haven't already. Agreeing to the CLA is required before code can be merged and only needs to happen on the first contribution to the project. All subsequent contributions will fall under the same CLA.

## 🗺️ Guidelines

### Dependency Management: Poetry and other env/dependency managers

This project uses [Poetry](https://python-poetry.org/) v1.6.1+ as a dependency manager.

### Local Development Dependencies

Install langserve development requirements (for running langchain, running examples, linting, formatting, tests, and coverage):

```sh
poetry install --with test,dev
```

Then verify that tests pass:

```sh
make test
```

### Formatting and Linting

Run these locally before submitting a PR; the CI system will check also.

#### Code Formatting

Formatting for this project is done via a combination of [Black](https://black.readthedocs.io/en/stable/) and [ruff](https://docs.astral.sh/ruff/rules/).

To run formatting for this project:

```sh
make format
```

#### Linting

Linting for this project is done via a combination of [Black](https://black.readthedocs.io/en/stable/), [ruff](https://docs.astral.sh/ruff/rules/), and [mypy](http://mypy-lang.org/).

To run linting for this project:

```sh
make lint
```
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
# Default target executed when no arguments are given to make.
all: help

build-playground:
cd ./langserve/playground && yarn build

build: build-playground
poetry build

######################
# TESTING AND COVERAGE
######################
Expand Down
53 changes: 46 additions & 7 deletions examples/chain/server.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,73 @@
#!/usr/bin/env python
"""Example LangChain server exposes a chain composed of a prompt and an LLM."""
from typing import Any, Dict, List, Optional, Tuple

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from typing_extensions import TypedDict
from langchain.prompts import PromptTemplate

# from typing_extensions import TypedDict
from langchain.pydantic_v1 import BaseModel
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import ConfigurableField, RunnablePassthrough

from langserve import add_routes

model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
chain = prompt | model
model = ChatOpenAI(temperature=0.5).configurable_alternatives(
ConfigurableField(id="llm", name="LLM"),
high_temp=ChatOpenAI(temperature=0.9),
low_temp=ChatOpenAI(temperature=0.1, max_tokens=1),
default_key="medium_temp",
)
prompt = PromptTemplate.from_template(
"tell me a joke about {topic}.\nChat history: {chat_history}"
).configurable_fields(
template=ConfigurableField(
id="prompt",
name="Prompt",
description="The prompt to use. Must contain {topic}",
)
)
chain = (
RunnablePassthrough.assign(chat_history=(lambda x: "\n".join(x)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an issue atm

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah it's fine didn't notice the custom input type

| prompt
| model
| StrOutputParser()
)

app = FastAPI(
title="LangChain Server",
version="1.0",
description="Spin up a simple api server using Langchain's Runnable interfaces",
)

# Set all CORS enabled origins
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"],
)


# The input type is automatically inferred from the runnable
# interface; however, if you want to override it, you can do so
# by passing in the input_type argument to add_routes.
class ChainInput(TypedDict):
class ChainInput(BaseModel):
"""The input to the chain."""

topic: str
"""The topic of the joke."""
chat_history: List[str]
chat_history_tuples: List[Tuple[str, str]]
chat_history_object_list: List[Dict[str, str]]
tester: Optional[Dict[str, Any]] = None


add_routes(app, chain, input_type=ChainInput)
add_routes(app, chain, input_type=ChainInput, config_keys=["configurable"])

# Alternatively, you can rely on langchain's type inference
# to infer the input type from the runnable interface.
Expand Down
19 changes: 6 additions & 13 deletions langserve/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import httpx
from httpx._types import AuthTypes, CertTypes, CookieTypes, HeaderTypes, VerifyTypes
from langchain.callbacks.tracers.log_stream import RunLog, RunLogPatch
from langchain.callbacks.tracers.log_stream import RunLogPatch
from langchain.load.dump import dumpd
from langchain.schema.runnable import Runnable
from langchain.schema.runnable.config import (
Expand Down Expand Up @@ -401,15 +401,14 @@ async def astream_log(
input: Input,
config: Optional[RunnableConfig] = None,
*,
diff: bool = False,
include_names: Optional[Sequence[str]] = None,
include_types: Optional[Sequence[str]] = None,
include_tags: Optional[Sequence[str]] = None,
exclude_names: Optional[Sequence[str]] = None,
exclude_types: Optional[Sequence[str]] = None,
exclude_tags: Optional[Sequence[str]] = None,
**kwargs: Optional[Any],
) -> Union[AsyncIterator[RunLogPatch], AsyncIterator[RunLog]]:
) -> AsyncIterator[RunLogPatch]:
"""Stream all output from a runnable, as reported to the callback system.

This includes all inner runs of LLMs, Retrievers, Tools, etc.
Expand All @@ -436,7 +435,7 @@ async def astream_log(
"input": simple_dumpd(input),
"config": _without_callbacks(config),
"kwargs": kwargs,
"diff": diff,
"diff": True,
"include_names": include_names,
"include_types": include_types,
"include_tags": include_tags,
Expand All @@ -458,18 +457,12 @@ async def astream_log(
async for sse in event_source.aiter_sse():
if sse.event == "data":
data = simple_loads(sse.data)
if diff:
chunk = RunLogPatch(*data["ops"])
else:
chunk = RunLog(*data["ops"], state=data["state"])
chunk = RunLogPatch(*data["ops"])

yield chunk

if diff:
if final_output:
final_output += chunk
else:
final_output = chunk
if final_output:
final_output += chunk
else:
final_output = chunk
elif sse.event == "end":
Expand Down
47 changes: 47 additions & 0 deletions langserve/playground.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import json
import mimetypes
import os
from string import Template
from typing import List, Type

from fastapi.responses import Response
from langchain.schema.runnable import Runnable

try:
from pydantic.v1 import BaseModel
except ImportError:
from pydantic import BaseModel


class PlaygroundTemplate(Template):
delimiter = "____"


async def serve_playground(
runnable: Runnable,
input_schema: Type[BaseModel],
config_keys: List[str],
base_url: str,
file_path: str,
) -> Response:
local_file_path = os.path.join(
os.path.dirname(__file__),
"./playground/dist",
file_path or "index.html",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is file path configurable to prototype with different variations of the UX?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is file path an input?

)
with open(local_file_path) as f:
mime_type = mimetypes.guess_type(local_file_path)[0]
if mime_type in ("text/html", "text/css", "application/javascript"):
res = PlaygroundTemplate(f.read()).substitute(
LANGSERVE_BASE_URL=base_url[1:]
if base_url.startswith("/")
else base_url,
LANGSERVE_CONFIG_SCHEMA=json.dumps(
runnable.config_schema(include=config_keys).schema()
),
LANGSERVE_INPUT_SCHEMA=json.dumps(input_schema.schema()),
)
else:
res = f.buffer.read()

return Response(res, media_type=mime_type)
18 changes: 18 additions & 0 deletions langserve/playground/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
26 changes: 26 additions & 0 deletions langserve/playground/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

.yarn
27 changes: 27 additions & 0 deletions langserve/playground/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
```

- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
Loading