Skip to content
This repository has been archived by the owner on Nov 13, 2024. It is now read-only.

Commit

Permalink
canopy server documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
miararoy committed Nov 2, 2023
1 parent d58b238 commit 7ed9291
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 78 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,5 @@ cython_debug/
# Mac OS
**/.DS_Store

datafiles/*
datafiles/*
canopy-api-docs.html
2 changes: 1 addition & 1 deletion src/canopy/models/api_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def calc_total_tokens(cls, v, values, **kwargs):


class ChatResponse(BaseModel):
id: str
id: str = Field(description="Canopy session Id.")
object: str
created: int
model: str
Expand Down
53 changes: 36 additions & 17 deletions src/canopy/models/data_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,52 @@


class Query(BaseModel):
text: str
namespace: str = ""
metadata_filter: Optional[dict] = None
top_k: Optional[int] = None
query_params: dict = Field(default_factory=dict)
text: str = Field(description="The query text.")
namespace: str = Field(
default="",
description="The namespace of the query, to learn more about namespaces, see https://docs.pinecone.io/docs/namespaces", # noqa: E501
)
metadata_filter: Optional[dict] = Field(
default=None,
description="A pinecone metadata filter, to learn more about metadata filters, see https://docs.pinecone.io/docs/metadata-filtering", # noqa: E501
)
top_k: Optional[int] = Field(
default=None,
description="[soon deprecated] The number of results to return."
)
query_params: dict = Field(
default_factory=dict,
description="Pinecone Client additional query parameters."
)


class Document(BaseModel):
id: str
text: str
source: str = ""
metadata: Metadata = Field(default_factory=dict)
id: str = Field(description="The document id.")
text: str = Field(description="The document text.")
source: str = Field(
default="",
description="The source of the document: a URL, a file path, etc."
)
metadata: Metadata = Field(
default_factory=dict,
description="The document metadata, to learn more about metadata, see https://docs.pinecone.io/docs/manage-data", # noqa: E501
)

class Config:
extra = Extra.forbid

@validator('metadata')
@validator("metadata")
def metadata_reseved_fields(cls, v):
if 'text' in v:
if "text" in v:
raise ValueError('Metadata cannot contain reserved field "text"')
if 'document_id' in v:
if "document_id" in v:
raise ValueError('Metadata cannot contain reserved field "document_id"')
if 'source' in v:
if "source" in v:
raise ValueError('Metadata cannot contain reserved field "source"')
return v


class ContextContent(BaseModel, ABC):

# Any context should be able to be represented as well formatted text.
# In the most minimal case, that could simply be a call to `.json()`.
@abstractmethod
Expand All @@ -59,6 +76,8 @@ def to_text(self, **kwargs) -> str:
return "\n".join([c.to_text(**kwargs) for c in self.content])


ContextContentResponse = Union[ContextContent, Sequence[ContextContent]]

# --------------------- LLM models ------------------------


Expand All @@ -69,12 +88,12 @@ class Role(Enum):


class MessageBase(BaseModel):
role: Role
content: str
role: Role = Field(description="The role of the messages author.")
content: str = Field(description="The contents of the message.")

def dict(self, *args, **kwargs):
d = super().dict(*args, **kwargs)
d['role'] = d['role'].value
d["role"] = d["role"].value
return d


Expand Down
27 changes: 27 additions & 0 deletions src/canopy_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
HTML_TEMPLATE = """<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Canopy API Spec</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="https://polybit-apps.s3.amazonaws.com/stdlib/users/pinecone/profile/image.png">
<style>
body {
margin: 0;
padding: 0;
}
</style>
<style data-styled="" data-styled-version="4.4.1"></style>
</head>
<body>
<div id="redoc-container"></div>
<title>Redoc</title>
<script src="https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js"> </script>
<script>
var spec = %s;
Redoc.init(spec, {}, document.getElementById("redoc-container"));
</script>
</body>
</html>
""" # noqa: E501
24 changes: 24 additions & 0 deletions src/canopy_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,5 +551,29 @@ def stop(url):
raise CLIError(msg)


@cli.command(
help=(
"""
\b
Open the Canopy Server docs
"""
)
)
def docs():
import json
from canopy_cli import HTML_TEMPLATE
from canopy_server.app import app
# generate docs

filename = "canopy-api-docs.html"

with open(filename, "w") as fd:
print(HTML_TEMPLATE % json.dumps(app.openapi()), file=fd)

import webbrowser

webbrowser.open('file://' + os.path.realpath(filename))


if __name__ == "__main__":
cli()
13 changes: 13 additions & 0 deletions src/canopy_server/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
description = """
Canopy is an open-source Retrieval Augmented Generation (RAG) framework and context engine built on top of the Pinecone vector database. Canopy enables you to quickly and easily experiment with and build applications using RAG. Start chatting with your documents or text data with a few simple commands.
Canopy provides a configurable built-in server so you can effortlessly deploy a RAG-powered chat application to your existing chat UI or interface. Or you can build your own, custom RAG application using the Canopy lirbary.
## Prerequisites
### Pinecone API key
To get Pinecone free trial API key and environment register or log into your Pinecone account in the console (https://app.pinecone.io/). You can access your API key from the "API Keys" section in the sidebar of your dashboard, and find the environment name next to it.
### OpenAI API key
You can find your free trial OpenAI API key https://platform.openai.com/account/api-keys. You might need to login or register to OpenAI services.
""" # noqa: E501
52 changes: 44 additions & 8 deletions src/canopy_server/api_models.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
from typing import Optional, List

from pydantic import BaseModel
from pydantic import BaseModel, Field

from canopy.models.data_models import Messages, Query, Document


class ChatRequest(BaseModel):
model: str = ""
messages: Messages
stream: bool = False
user: Optional[str] = None
model: str = Field(
default="",
description="ID of the model to use. If empty, the default model will be used.", # noqa: E501
)
messages: Messages = Field(
description="A list of messages comprising the conversation so far."
)
stream: bool = Field(
default=False,
description="""If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message.""", # noqa: E501
)
user: Optional[str] = Field(
default=None,
description="A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.", # noqa: E501
)


class ContextQueryRequest(BaseModel):
Expand All @@ -19,11 +30,13 @@ class ContextQueryRequest(BaseModel):

class ContextUpsertRequest(BaseModel):
documents: List[Document]
batch_size: int = 200
batch_size: int = Field(
default=200, description="Batch size for upserting documents to Pinecone."
)


class ContextDeleteRequest(BaseModel):
document_ids: List[str]
document_ids: List[str] = Field(description="List of document ids to delete.")


class HealthStatus(BaseModel):
Expand All @@ -38,5 +51,28 @@ class ChatDebugInfo(BaseModel):
prompt_tokens: Optional[int] = None
generated_tokens: Optional[int] = None

def to_text(self,):
def to_text(
self,
):
return self.json()


class ShutdownResponse(BaseModel):
message: str = Field(
default="Shutting down",
description="Message indicating the server is shutting down.",
)


class SuccessUpsertResponse(BaseModel):
message: str = Field(
default="Success",
description="Message indicating the upsert was successful.",
)


class SuccessDeleteResponse(BaseModel):
message: str = Field(
default="Success",
description="Message indicating the delete was successful.",
)
Loading

0 comments on commit 7ed9291

Please sign in to comment.