packages/blueprints/gen-ai-chatbot/static-assets/chatbot-genai-components/backend/python/app/routes/bot.py (160 lines of code) (raw):
from typing import Literal
from app.dependencies import check_creating_bot_allowed
from app.repositories.custom_bot import (
find_private_bot_by_id,
find_private_bots_by_user_id,
update_bot_visibility,
)
from app.routes.schemas.bot import (
Agent,
AgentTool,
BotInput,
BotMetaOutput,
BotModifyInput,
BotOutput,
BotPinnedInput,
BotPresignedUrlOutput,
BotSummaryOutput,
BotSwitchVisibilityInput,
EmbeddingParams,
GenerationParams,
Knowledge,
SearchParams,
)
from app.usecases.bot import (
create_new_bot,
fetch_all_bots_by_user_id,
fetch_available_agent_tools,
fetch_bot_summary,
issue_presigned_url,
modify_owned_bot,
modify_pin_status,
remove_bot_by_id,
remove_uploaded_file,
)
from app.user import User
from fastapi import APIRouter, Depends, Request
router = APIRouter(tags=["bot"])
@router.post("/bot", response_model=BotOutput)
def post_bot(
request: Request,
bot_input: BotInput,
create_bot_check=Depends(check_creating_bot_allowed),
):
"""Create new private owned bot."""
current_user: User = request.state.current_user
return create_new_bot(current_user.id, bot_input)
@router.patch("/bot/{bot_id}")
def patch_bot(request: Request, bot_id: str, modify_input: BotModifyInput):
"""Modify owned bot title, instruction and description."""
return modify_owned_bot(request.state.current_user.id, bot_id, modify_input)
@router.patch("/bot/{bot_id}/pinned")
def patch_bot_pin_status(request: Request, bot_id: str, pinned_input: BotPinnedInput):
"""Modify owned bot pin status."""
current_user: User = request.state.current_user
return modify_pin_status(current_user.id, bot_id, pinned=pinned_input.pinned)
@router.patch("/bot/{bot_id}/visibility")
def patch_bot_visibility(
request: Request, bot_id: str, visibility_input: BotSwitchVisibilityInput
):
"""Switch bot visibility"""
current_user: User = request.state.current_user
update_bot_visibility(current_user.id, bot_id, visibility_input.to_public)
@router.get("/bot", response_model=list[BotMetaOutput])
def get_all_bots(
request: Request,
kind: Literal["private", "mixed"] = "private",
pinned: bool = False,
limit: int | None = None,
):
"""Get all bots. The order is descending by `last_used_time`.
- If `kind` is `private`, only private bots will be returned.
- If `mixed` must give either `pinned` or `limit`.
- If `pinned` is True, only pinned bots will be returned.
- When kind is `private`, this will be ignored.
- If `limit` is specified, only the first n bots will be returned.
- Cannot specify both `pinned` and `limit`.
"""
current_user: User = request.state.current_user
bots = []
if kind == "private":
bots = find_private_bots_by_user_id(current_user.id, limit=limit)
elif kind == "mixed":
bots = fetch_all_bots_by_user_id(
current_user.id, limit=limit, only_pinned=pinned
)
else:
raise ValueError(f"Invalid kind: {kind}")
output = [
BotMetaOutput(
id=bot.id,
title=bot.title,
create_time=bot.create_time,
last_used_time=bot.last_used_time,
is_pinned=bot.is_pinned,
owned=bot.owned,
available=bot.available,
description=bot.description,
is_public=bot.is_public,
sync_status=bot.sync_status,
)
for bot in bots
]
return output
@router.get("/bot/private/{bot_id}", response_model=BotOutput)
def get_private_bot(request: Request, bot_id: str):
"""Get private bot by id."""
current_user: User = request.state.current_user
bot = find_private_bot_by_id(current_user.id, bot_id)
output = BotOutput(
id=bot.id,
title=bot.title,
instruction=bot.instruction,
description=bot.description,
create_time=bot.create_time,
last_used_time=bot.last_used_time,
is_public=True if bot.public_bot_id else False,
is_pinned=bot.is_pinned,
owned=True,
embedding_params=EmbeddingParams(
chunk_size=bot.embedding_params.chunk_size,
chunk_overlap=bot.embedding_params.chunk_overlap,
enable_partition_pdf=bot.embedding_params.enable_partition_pdf,
),
agent=Agent(
tools=[
AgentTool(name=tool.name, description=tool.description)
for tool in bot.agent.tools
]
),
knowledge=Knowledge(
source_urls=bot.knowledge.source_urls,
sitemap_urls=bot.knowledge.sitemap_urls,
filenames=bot.knowledge.filenames,
),
generation_params=GenerationParams(
max_tokens=bot.generation_params.max_tokens,
top_k=bot.generation_params.top_k,
top_p=bot.generation_params.top_p,
temperature=bot.generation_params.temperature,
stop_sequences=bot.generation_params.stop_sequences,
),
search_params=SearchParams(
max_results=bot.search_params.max_results,
),
sync_status=bot.sync_status,
sync_status_reason=bot.sync_status_reason,
sync_last_exec_id=bot.sync_last_exec_id,
display_retrieved_chunks=bot.display_retrieved_chunks,
)
return output
@router.get("/bot/summary/{bot_id}", response_model=BotSummaryOutput)
def get_bot_summary(request: Request, bot_id: str):
"""Get bot summary by id."""
current_user: User = request.state.current_user
return fetch_bot_summary(current_user.id, bot_id)
@router.delete("/bot/{bot_id}")
def delete_bot(request: Request, bot_id: str):
"""Delete bot by id. This can be used for both owned and shared bots.
If the bot is shared, just remove the alias.
"""
current_user: User = request.state.current_user
remove_bot_by_id(current_user.id, bot_id)
@router.get("/bot/{bot_id}/presigned-url", response_model=BotPresignedUrlOutput)
def get_bot_presigned_url(
request: Request, bot_id: str, filename: str, contentType: str
):
"""Get presigned url for bot"""
current_user: User = request.state.current_user
url = issue_presigned_url(current_user.id, bot_id, filename, contentType)
return BotPresignedUrlOutput(url=url)
@router.delete("/bot/{bot_id}/uploaded-file")
def delete_bot_uploaded_file(request: Request, bot_id: str, filename: str):
"""Delete uploaded file for bot"""
current_user: User = request.state.current_user
remove_uploaded_file(current_user.id, bot_id, filename)
@router.get("/bot/{bot_id}/agent/available-tools", response_model=list[AgentTool])
def get_bot_available_tools(request: Request, bot_id: str):
"""Get available tools for bot"""
tools = fetch_available_agent_tools()
return [AgentTool(name=tool.name, description=tool.description) for tool in tools]