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

Endpoints for LLM, Embedder and Plugin settings #399

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions core/cat/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from cat.routes.static import public, admin, static
from cat.api_auth import check_api_key
from cat.routes.openapi import get_openapi_configuration_function
from cat.routes.setting import general_setting, prompt_setting, llm_setting, embedder_setting
from cat.routes import settings, prompt, llm, embedder
from cat.looking_glass.cheshire_cat import CheshireCat


Expand Down Expand Up @@ -55,10 +55,10 @@ def custom_generate_unique_id(route: APIRoute):

# Add routers to the middleware stack.
cheshire_cat_api.include_router(base.router, tags=["Status"])
cheshire_cat_api.include_router(general_setting.router, tags=["Settings - General"], prefix="/settings")
cheshire_cat_api.include_router(prompt_setting.router, tags=["Settings - Prompt"], prefix="/settings/prompt")
cheshire_cat_api.include_router(llm_setting.router, tags=["Settings - Large Language Model"], prefix="/settings/llm")
cheshire_cat_api.include_router(embedder_setting.router, tags=["Settings - Embedder"], prefix="/settings/embedder")
cheshire_cat_api.include_router(settings.router, tags=["Settings"], prefix="/settings")
cheshire_cat_api.include_router(prompt.router, tags=["Prompt"], prefix="/prompt")
cheshire_cat_api.include_router(llm.router, tags=["Large Language Model"], prefix="/llm")
cheshire_cat_api.include_router(embedder.router, tags=["Embedder"], prefix="/embedder")
cheshire_cat_api.include_router(plugins.router, tags=["Plugins"], prefix="/plugins")
cheshire_cat_api.include_router(memory.router, tags=["Memory"], prefix="/memory")
cheshire_cat_api.include_router(upload.router, tags=["Rabbit Hole"], prefix="/rabbithole")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@


# get configured Embedders and configuration schemas
@router.get("/")
def get_embedder_settings():
@router.get("/settings/")
def get_embedders_settings() -> Dict:
"""Get the list of the Embedders"""
settings = crud.get_settings_by_category(category=EMBEDDER_CATEGORY)
selected = crud.get_setting_by_name(name=EMBEDDER_SELECTED_NAME)
Expand All @@ -39,12 +39,39 @@ def get_embedder_settings():
"selected_configuration": selected_configuration,
}

@router.put("/{languageEmbedderName}")

# get Embedder settings and its schema
@router.get("/settings/{languageEmbedderName}")
def get_embedder_settings(request: Request, languageEmbedderName: str) -> Dict:
"""Get settings and schema of the specified Embedder"""

# check that languageEmbedderName is a valid name
allowed_configurations = list(EMBEDDER_SCHEMAS.keys())
if languageEmbedderName not in allowed_configurations:
raise HTTPException(
status_code=400,
detail=f"{languageEmbedderName} not supported. Must be one of {allowed_configurations}",
)

settings = crud.get_setting_by_name(name=languageEmbedderName)
schema = EMBEDDER_SCHEMAS[languageEmbedderName]

if settings is None:
settings = {}

return {
"status": "success",
"settings": settings,
"schema": schema
}


@router.put("/settings/{languageEmbedderName}")
def upsert_embedder_setting(
request: Request,
languageEmbedderName: str,
payload: Dict = Body(example={"openai_api_key": "your-key-here"}),
):
) -> Dict:
"""Upsert the Embedder setting"""

# check that languageModelName is a valid name
Expand Down
34 changes: 30 additions & 4 deletions core/cat/routes/setting/llm_setting.py → core/cat/routes/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@


# get configured LLMs and configuration schemas
@router.get("/")
def get_llm_settings():
@router.get("/settings/")
def get_llms_settings() -> Dict:
"""Get the list of the Large Language Models"""

settings = crud.get_settings_by_category(category=LLM_CATEGORY)
Expand All @@ -41,12 +41,38 @@ def get_llm_settings():
}


@router.put("/{languageModelName}")
# get LLM settings and its schema
@router.get("/settings/{languageModelName}")
def get_llm_settings(request: Request, languageModelName: str) -> Dict:
"""Get settings and schema of the specified Large Language Model"""

# check that languageModelName is a valid name
allowed_configurations = list(LLM_SCHEMAS.keys())
if languageModelName not in allowed_configurations:
raise HTTPException(
status_code=400,
detail=f"{languageModelName} not supported. Must be one of {allowed_configurations}",
)

settings = crud.get_setting_by_name(name=languageModelName)
schema = LLM_SCHEMAS[languageModelName]

if settings is None:
settings = {}

return {
"status": "success",
"settings": settings,
"schema": schema
}


@router.put("/settings/{languageModelName}")
def upsert_llm_setting(
request: Request,
languageModelName: str,
payload: Dict = Body(example={"openai_api_key": "your-key-here"}),
):
) -> Dict:
"""Upsert the Large Language Model setting"""

# check that languageModelName is a valid name
Expand Down
127 changes: 64 additions & 63 deletions core/cat/routes/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,6 @@
router = APIRouter()


# DELETE memories
@router.delete("/point/{collection_id}/{memory_id}/")
async def delete_element_in_memory(
request: Request,
collection_id: str,
memory_id: str
) -> Dict:
"""Delete specific element in memory."""

ccat = request.app.state.ccat
vector_memory = ccat.memory.vectors

# check if collection exists
collections = list(vector_memory.collections.keys())
if collection_id not in collections:
raise HTTPException(
status_code=400,
detail={"error": "Collection does not exist."}
)

# check if point exists
points = vector_memory.vector_db.retrieve(
collection_name=collection_id,
ids=[memory_id],
)
if points == []:
raise HTTPException(
status_code=400,
detail={"error": "Point does not exist."}
)

# delete point
vector_memory.collections[collection_id].delete_points([memory_id])

return {
"status": "success",
"deleted": memory_id
}


# GET memories from recall
@router.get("/recall/")
async def recall_memories_from_text(
Expand Down Expand Up @@ -127,6 +87,32 @@ async def get_collections(request: Request) -> Dict:
}


# DELETE all collections
@router.delete("/collections/")
async def wipe_collections(
request: Request,
) -> Dict:
"""Delete and create all collections"""

ccat = request.app.state.ccat
collections = list(ccat.memory.vectors.collections.keys())
vector_memory = ccat.memory.vectors

to_return = {}
for c in collections:
ret = vector_memory.vector_db.delete_collection(collection_name=c)
to_return[c] = ret

ccat.load_memory() # recreate the long term memories
ccat.mad_hatter.find_plugins()
ccat.mad_hatter.embed_tools()

return {
"status": "success",
"deleted": to_return,
}


# DELETE one collection
@router.delete("/collections/{collection_id}")
async def wipe_single_collection(request: Request, collection_id: str = "") -> Dict:
Expand All @@ -151,42 +137,57 @@ async def wipe_single_collection(request: Request, collection_id: str = "") -> D
}


# DELETE all collections
@router.delete("/wipe-collections/")
async def wipe_collections(
# DELETE conversation history from working memory
@router.delete("/conversation_history/")
async def wipe_conversation_history(
request: Request,
) -> Dict:
"""Delete and create all collections"""
"""Delete conversation history from working memory"""

ccat = request.app.state.ccat
collections = list(ccat.memory.vectors.collections.keys())
vector_memory = ccat.memory.vectors

to_return = {}
for c in collections:
ret = vector_memory.vector_db.delete_collection(collection_name=c)
to_return[c] = ret

ccat.load_memory() # recreate the long term memories
ccat.mad_hatter.find_plugins()
ccat.mad_hatter.embed_tools()
ccat.working_memory["history"] = []

return {
"status": "success",
"deleted": to_return,
"deleted": True,
}

#DELETE conversation history from working memory
@router.delete("/working-memory/conversation-history/")
async def wipe_conversation_history(

# DELETE memories
@router.delete("/{collection_id}/point/{memory_id}/")
Copy link
Member Author

Choose a reason for hiding this comment

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

@pieroit would you prefer like that or directly /{collection_id}/{memory_id}/ ?

Copy link
Member

Choose a reason for hiding this comment

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

let's leave point, in the future we may consider other aspects of a collection as a resource

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, perfect!

Copy link
Member

Choose a reason for hiding this comment

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

thanks for fixing the tests!!!
Going for /collections/{collection_id}/points/{memory_id}/ which should be the most RESTful

async def wipe_memory_point(
request: Request,
collection_id: str,
memory_id: str
) -> Dict:
"""Delete conversation history from working memory"""
"""Delete a specific point in memory"""

ccat = request.app.state.ccat
ccat.working_memory["history"] = []
vector_memory = ccat.memory.vectors

# check if collection exists
collections = list(vector_memory.collections.keys())
if collection_id not in collections:
raise HTTPException(
status_code=400,
detail={"error": "Collection does not exist."}
)

# check if point exists
points = vector_memory.vector_db.retrieve(
collection_name=collection_id,
ids=[memory_id],
)
if points == []:
raise HTTPException(
status_code=400,
detail={"error": "Point does not exist."}
)

# delete point
vector_memory.collections[collection_id].delete_points([memory_id])

return {
"status": "success",
"deleted": True,
}
"deleted": memory_id
}
40 changes: 34 additions & 6 deletions core/cat/routes/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


# GET plugins
@router.get("/", status_code=200)
@router.get("/")
async def list_available_plugins(request: Request) -> Dict:
"""List available plugins"""

Expand Down Expand Up @@ -73,7 +73,7 @@ async def install_plugin(
}


@router.put("/toggle/{plugin_id}", status_code=200)
@router.put("/toggle/{plugin_id}")
async def toggle_plugin(plugin_id: str, request: Request) -> Dict:
"""Enable or disable a single plugin"""

Expand All @@ -96,7 +96,7 @@ async def toggle_plugin(plugin_id: str, request: Request) -> Dict:
}


@router.get("/{plugin_id}", status_code=200)
@router.get("/{plugin_id}")
async def get_plugin_details(plugin_id: str, request: Request) -> Dict:
"""Returns information on a single plugin"""

Expand All @@ -119,7 +119,35 @@ async def get_plugin_details(plugin_id: str, request: Request) -> Dict:
}


@router.get("/settings/{plugin_id}", status_code=200)
@router.get("/settings/")
async def get_plugins_settings(request: Request) -> Dict:
"""Returns the settings of all the plugins"""

# access cat instance
ccat = request.app.state.ccat

settings = []
schema = {}

# plugins are managed by the MadHatter class
for plugin in ccat.mad_hatter.plugins.values():
plugin_settings = plugin.load_settings()
plugin_schema = plugin.get_settings_schema()
if len(plugin_schema['properties']) == 0:
continue
schema[plugin.id] = plugin_schema
plugin_settings["id"] = plugin.id
settings.append(plugin_settings)

return {
"status": "success",
"results": len(settings),
"settings": settings,
"schemas": schema
}


@router.get("/settings/{plugin_id}")
async def get_plugin_settings(request: Request, plugin_id: str) -> Dict:
"""Returns the settings of a specific plugin"""

Expand All @@ -143,7 +171,7 @@ async def get_plugin_settings(request: Request, plugin_id: str) -> Dict:
}


@router.put("/settings/{plugin_id}", status_code=200)
@router.put("/settings/{plugin_id}")
async def upsert_plugin_settings(
request: Request,
plugin_id: str,
Expand All @@ -168,7 +196,7 @@ async def upsert_plugin_settings(
}


@router.delete("/{plugin_id}", status_code=200)
@router.delete("/{plugin_id}")
async def delete_plugin(plugin_id: str, request: Request) -> Dict:
"""Physically remove plugin."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
router = APIRouter()

# get default prompt settings
@router.get("/")
@router.get("/settings/")
def get_default_prompt_settings(request: Request):
ccat = request.app.state.ccat

Expand Down
Empty file.
File renamed without changes.
2 changes: 1 addition & 1 deletion core/tests/routes/memory/test_memory_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def test_memory_collections_wipe(client):
assert collections_n_points["declarative"] > 1 # several chunks

# wipe out all memories
response = client.delete("/memory/wipe-collections/")
response = client.delete("/memory/collections/")
json = response.json()
assert response.status_code == 200

Expand Down
Loading
Loading