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

Bot content api fixes. #1050

Closed
wants to merge 4 commits into from
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
39 changes: 28 additions & 11 deletions kairon/api/app/routers/bot/data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os

from fastapi import UploadFile, File, Security, APIRouter
from starlette.requests import Request
from starlette.responses import FileResponse

from kairon.api.models import Response, TextData, CognitiveDataRequest
Expand Down Expand Up @@ -50,10 +51,11 @@ async def download_faq_files(
return response


@router.post("/text/faq", response_model=Response)
def save_bot_text(
@router.post("/text/faq/{collection}", response_model=Response)
async def save_bot_text(
text: TextData,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
collection: str = None
):
"""
Saves text content into the bot
Expand All @@ -65,16 +67,18 @@ def save_bot_text(
text.data,
current_user.get_user(),
current_user.get_bot(),
collection
)
}
}


@router.put("/text/faq/{text_id}", response_model=Response)
def update_bot_text(
@router.put("/text/faq/{text_id}/{collection}", response_model=Response)
async def update_bot_text(
text_id: str,
text: TextData,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
collection: str = None,
):
"""
Updates text content into the bot
Expand All @@ -87,13 +91,14 @@ def update_bot_text(
text.data,
current_user.get_user(),
current_user.get_bot(),
collection
)
}
}


@router.delete("/text/faq/{text_id}", response_model=Response)
def delete_bot_text(
async def delete_bot_text(
text_id: str,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
Expand All @@ -107,17 +112,29 @@ def delete_bot_text(


@router.get("/text/faq", response_model=Response)
def get_text(
async def get_text(
Copy link
Contributor

Choose a reason for hiding this comment

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

dynamic filtering on collection fields?

request: Request,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
"""
Fetches text content of the bot
"""
return {"data": list(processor.get_content(current_user.get_bot()))}
kwargs = request.query_params._dict.copy()
return {"data": list(processor.get_content(current_user.get_bot(), **kwargs))}


@router.get("/text/faq/collection", response_model=Response)
async def list_collection(
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
"""
Fetches text content of the bot
"""
return {"data": processor.list_collection(current_user.get_bot())}


@router.post("/cognition", response_model=Response)
def save_cognition_data(
async def save_cognition_data(
cognition: CognitiveDataRequest,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
Expand All @@ -137,7 +154,7 @@ def save_cognition_data(


@router.put("/cognition/{cognition_id}", response_model=Response)
def update_cognition_data(
async def update_cognition_data(
cognition_id: str,
cognition: CognitiveDataRequest,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
Expand All @@ -159,7 +176,7 @@ def update_cognition_data(


@router.delete("/cognition/{cognition_id}", response_model=Response)
def delete_cognition_data(
async def delete_cognition_data(
cognition_id: str,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
Expand All @@ -173,7 +190,7 @@ def delete_cognition_data(


@router.get("/cognition", response_model=Response)
def list_cognition_data(
async def list_cognition_data(
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
"""
Expand Down
1 change: 1 addition & 0 deletions kairon/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,7 @@ class PromptActionConfigRequest(BaseModel):
hyperparameters: dict = None
llm_prompts: List[LlmPromptRequest]
instructions: List[str] = []
collection: str = None
set_slots: List[SetSlotsUsingActionResponse] = []
dispatch_response: bool = True

Expand Down
23 changes: 23 additions & 0 deletions kairon/chat/converters/channels/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ def link_transformer(self, message):
except Exception as ex:
raise Exception(f" Error in TelegramResponseConverter::link_transformer {str(ex)}")

def button_transformer(self, message):
try:
jsoniterator = ElementTransformerOps.json_generator(message)
reply_markup = {}
inline_keyboard = []
reply_markup.update({"inline_keyboard": inline_keyboard})
inline_keyboard_array = []
for item in jsoniterator:
if item.get("type") == ElementTypes.BUTTON.value:
title = ElementTransformerOps.json_generator(item.get("children"))
for titletext in title:
button_text = titletext.get("text")
btn_body = {}
btn_body.update({"text": button_text})
btn_body.update({"callback_data": item.get("value")})
inline_keyboard_array.append(btn_body)
inline_keyboard.append(inline_keyboard_array)
return reply_markup
except Exception as ex:
raise Exception(f"Exception in TelegramResponseConverter::button_transfomer: {str(ex)}")

async def messageConverter(self, message):
try:
if self.message_type == ElementTypes.IMAGE.value:
Expand All @@ -42,5 +63,7 @@ async def messageConverter(self, message):
return self.link_transformer(message)
elif self.message_type == ElementTypes.VIDEO.value:
return super().video_transformer(message)
elif self.message_type == ElementTypes.BUTTON.value:
return self.button_transformer(message)
except Exception as ex:
raise Exception(f"Error in TelegramResponseConverter::messageConverter {str(ex)}")
5 changes: 5 additions & 0 deletions kairon/chat/handlers/channels/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from kairon.chat.agent_processor import AgentProcessor
from kairon import Utility
from kairon.chat.converters.channels.response_factory import ConverterFactory
from kairon.chat.converters.channels.responseconverter import ElementTransformerOps
import json

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -159,6 +161,9 @@ async def send_custom_json(
del response["text"]
api_call = getattr(self, send_functions[("text",)])
api_call(recipient_id, *response_list, **response)
elif ops_type in ["button"]:
body_default = ElementTransformerOps.getChannelConfig(ChannelTypes.TELEGRAM.value, "body_message")
self.send_message(recipient_id, text=body_default, reply_markup=json.dumps(response))
else:
self.send_message(recipient_id, str(json_message))
except Exception as ap:
Expand Down
6 changes: 3 additions & 3 deletions kairon/shared/data/data_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
from validators import url, ValidationFailure

from kairon.exceptions import AppException
from kairon.shared.data.audit.data_objects import Auditlog
from kairon.shared.data.signals import push_notification, auditlogger
from kairon.shared.models import TemplateType, StoryStepType, StoryType, CognitionDataType, CognitionMetadataType
from kairon.shared.utils import Utility
from kairon.shared.data.audit.data_objects import Auditlog
from .constant import EVENT_STATUS, SLOT_MAPPING_TYPE, TrainingDataSourceType
from ..constants import WhatsappBSPTypes, LLMResourceProvider

Expand Down Expand Up @@ -717,7 +717,7 @@ def clean(self):

@auditlogger.log
@push_notification.apply
class CognitionData(Auditlog):
class CognitionData(Document):
vector_id = SequenceField(required=True)
data = DynamicField(required=True)
content_type = StringField(default=CognitionDataType.text.value, choices=[CognitionDataType.text.value,
Expand All @@ -728,7 +728,7 @@ class CognitionData(Auditlog):
bot = StringField(required=True)
timestamp = DateTimeField(default=datetime.utcnow)

meta = {"indexes": [{"fields": ["bot"]}]}
meta = {"indexes": [{"fields": ["$data", "bot"]}]}

def validate(self, clean=True):
if clean:
Expand Down
36 changes: 27 additions & 9 deletions kairon/shared/data/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5438,6 +5438,7 @@ def edit_prompt_action(self, prompt_action_id: str, request_data: dict, bot: Tex
action.hyperparameters = request_data.get('hyperparameters', Utility.get_llm_hyperparameters())
action.llm_prompts = [LlmPrompt(**prompt) for prompt in request_data.get('llm_prompts', [])]
action.instructions = request_data.get('instructions', [])
action.collection = request_data.get('collection')
action.set_slots = request_data.get('set_slots', [])
action.dispatch_response = request_data.get('dispatch_response', True)
action.timestamp = datetime.utcnow()
Expand Down Expand Up @@ -5754,7 +5755,7 @@ def get_razorpay_action_config(self, bot: Text, with_doc_id: bool = True):

yield action

def save_content(self, content: Text, user: Text, bot: Text):
def save_content(self, content: Text, user: Text, bot: Text, collection: Text = None):
bot_settings = self.get_bot_settings(bot=bot, user=user)
if not bot_settings["llm_settings"]['enable_faq']:
raise AppException('Faq feature is disabled for the bot! Please contact support.')
Expand All @@ -5763,14 +5764,15 @@ def save_content(self, content: Text, user: Text, bot: Text):

content_obj = CognitionData()
content_obj.data = content
content_obj.collection = collection
content_obj.user = user
content_obj.bot = bot
id = (
content_obj.save().id.__str__()
)
return id

def update_content(self, content_id: str, content: Text, user: Text, bot: Text):
def update_content(self, content_id: str, content: Text, user: Text, bot: Text, collection: Text = None):
if len(content.split()) < 10:
raise AppException("Content should contain atleast 10 words.")

Expand All @@ -5780,6 +5782,7 @@ def update_content(self, content_id: str, content: Text, user: Text, bot: Text):
try:
content_obj = CognitionData.objects(bot=bot, id=content_id).get()
content_obj.data = content
content_obj.collection = collection
content_obj.user = user
content_obj.timestamp = datetime.utcnow()
content_obj.save()
Expand All @@ -5793,20 +5796,35 @@ def delete_content(self, content_id: str, user: Text, bot: Text):
except DoesNotExist:
raise AppException("Text does not exists!")

def get_content(self, bot: Text):
def get_content(self, bot: Text, **kwargs):
"""
fetches content

:param bot: bot id
:param collection: name of the collection
:return: yield dict
"""
for value in CognitionData.objects(bot=bot):
final_data = {}
kwargs["bot"] = bot
search = kwargs.pop('data', None)
start_idx = kwargs.pop('start_idx', None)
page_size = kwargs.pop('page_size', None)
cognition_data = CognitionData.objects(**kwargs)
if search:
cognition_data = cognition_data.search_text(search)
for value in cognition_data.skip(start_idx).limit(page_size):
item = value.to_mongo().to_dict()
data = item.pop("data")
final_data["_id"] = item["_id"].__str__()
final_data['content'] = data
yield final_data
item.pop('timestamp')
item["_id"] = item["_id"].__str__()
yield item

def list_collection(self, bot: Text):
"""
Retrieve cognition data.

:param bot: bot id
"""
collections = list(CognitionData.objects(bot=bot).distinct(field='collection'))
return collections

def save_cognition_data(self, payload: Dict, user: Text, bot: Text):
bot_settings = self.get_bot_settings(bot=bot, user=user)
Expand Down
1 change: 1 addition & 0 deletions metadata/message_template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ telegram:
"disable_notification":false,
"reply_to_message_id":0}'
video: '{"text":"<data>"}'
body_message: 'Please select from quick buttons:'

msteams:
body_message: "Please select from quick buttons:"
Expand Down
Loading
Loading