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

Database action changes. #1062

Closed
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
2 changes: 1 addition & 1 deletion kairon/actions/definitions/vector_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ async def execute(self, dispatcher: CollectingDispatcher, tracker: Tracker, doma
else payload_type.get('value')
msg_logger.append(request_body)
tracker_data = ActionUtility.build_context(tracker, True)
response = vector_db.perform_operation(operation_type.get('value'), request_body)
response = vector_db.perform_operation(operation_type, request_body)
logger.info("response: " + str(response))
response_context = self.__add_user_context_to_http_response(response, tracker_data)
bot_response, bot_resp_log = ActionUtility.compose_response(vector_action_config['response'], response_context)
Expand Down
106 changes: 57 additions & 49 deletions kairon/api/app/routers/bot/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@
from starlette.requests import Request
from starlette.responses import FileResponse

from kairon.api.models import Response, TextData, CognitiveDataRequest
from kairon.api.models import Response, CognitiveDataRequest, CognitionSchemaRequest
from kairon.events.definitions.faq_importer import FaqDataImporterEvent
from kairon.shared.auth import Authentication
from kairon.shared.cognition.processor import CognitionDataProcessor
from kairon.shared.constants import DESIGNER_ACCESS
from kairon.shared.data.processor import MongoProcessor
from kairon.shared.models import User
from kairon.shared.utils import Utility

router = APIRouter()
processor = MongoProcessor()
cognition_processor = CognitionDataProcessor()


@router.post("/faq/upload", response_model=Response)
Expand Down Expand Up @@ -51,86 +53,92 @@ async def download_faq_files(
return response


@router.post("/text/faq", response_model=Response)
async def save_bot_text(
text: TextData,
@router.get("/text/faq", response_model=Response)
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.

is this not already covered by list_cognition_data api?

request: Request,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
"""
Fetches text content of the bot
"""
kwargs = request.query_params._dict.copy()
return {"data": list(cognition_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),
Copy link
Contributor

Choose a reason for hiding this comment

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

whats the use when we already have list_cognition_schema ?

):
"""
Fetches text content of the bot
"""
return {"data": cognition_processor.list_cognition_collections(current_user.get_bot())}


@router.post("/cognition/schema", response_model=Response)
async def save_cognition_schema(
metadata: CognitionSchemaRequest,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
collection: str = None
):
"""
Saves text content into the bot
Saves and updates cognition metadata into the bot
"""
return {
"message": "Text saved!",
"message": "Schema saved!",
"data": {
"_id": processor.save_content(
text.data,
"_id": cognition_processor.save_cognition_schema(
metadata.dict(),
current_user.get_user(),
current_user.get_bot(),
collection
)
}
}


@router.put("/text/faq/{text_id}", response_model=Response)
async def update_bot_text(
text_id: str,
text: TextData,
@router.put("/cognition/schema/{metadata_id}", response_model=Response)
async def update_cognition_schema(
metadata_id: str,
metadata: CognitionSchemaRequest,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
collection: str = None,
):
"""
Updates text content into the bot
Saves and updates cognition metadata into the bot
"""
return {
"message": "Text updated!",
"message": "Schema updated!",
"data": {
"_id": processor.update_content(
text_id,
text.data,
current_user.get_user(),
current_user.get_bot(),
collection
"_id": cognition_processor.update_cognition_schema(
metadata_id,
metadata.dict(),
current_user.get_user(),
current_user.get_bot(),
)
}
}


@router.delete("/text/faq/{text_id}", response_model=Response)
async def delete_bot_text(
text_id: str,
@router.delete("/cognition/schema/{metadata_id}", response_model=Response)
async def delete_cognition_schema(
metadata_id: str,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
"""
Deletes text content of the bot
Deletes cognition content of the bot
"""
processor.delete_content(text_id, current_user.get_user(), current_user.get_bot())
cognition_processor.delete_cognition_schema(metadata_id, current_user.get_bot())
return {
"message": "Text deleted!"
"message": "Schema deleted!"
}


@router.get("/text/faq", response_model=Response)
async def get_text(
request: Request,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
"""
Fetches text content of the 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(
@router.get("/cognition/schema", response_model=Response)
async def list_cognition_schema(
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS),
):
"""
Fetches text content of the bot
Fetches cognition content of the bot
"""
return {"data": processor.list_collection(current_user.get_bot())}
return {"data": list(cognition_processor.list_cognition_schema(current_user.get_bot()))}


@router.post("/cognition", response_model=Response)
Expand All @@ -144,7 +152,7 @@ async def save_cognition_data(
return {
"message": "Record saved!",
"data": {
"_id": processor.save_cognition_data(
"_id": cognition_processor.save_cognition_data(
cognition.dict(),
current_user.get_user(),
current_user.get_bot(),
Expand All @@ -165,7 +173,7 @@ async def update_cognition_data(
return {
"message": "Record updated!",
"data": {
"_id": processor.update_cognition_data(
"_id": cognition_processor.update_cognition_data(
cognition_id,
cognition.dict(),
current_user.get_user(),
Expand All @@ -183,7 +191,7 @@ async def delete_cognition_data(
"""
Deletes cognition content of the bot
"""
processor.delete_cognition_data(cognition_id, current_user.get_bot())
cognition_processor.delete_cognition_data(cognition_id, current_user.get_bot())
return {
"message": "Record deleted!"
}
Expand All @@ -196,4 +204,4 @@ async def list_cognition_data(
"""
Fetches cognition content of the bot
"""
return {"data": list(processor.list_cognition_data(current_user.get_bot()))}
return {"data": list(cognition_processor.list_cognition_data(current_user.get_bot()))}
47 changes: 21 additions & 26 deletions kairon/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import validators
from fastapi.param_functions import Form
from fastapi.security import OAuth2PasswordRequestForm
from rasa.shared.constants import DEFAULT_NLU_FALLBACK_INTENT_NAME

from kairon.exceptions import AppException
from rasa.shared.constants import DEFAULT_NLU_FALLBACK_INTENT_NAME
from kairon.shared.data.constant import EVENT_STATUS, SLOT_MAPPING_TYPE, SLOT_TYPE, ACCESS_ROLES, ACTIVITY_STATUS, \
INTEGRATION_STATUS, FALLBACK_MESSAGE, DEFAULT_NLU_FALLBACK_RESPONSE
from ..shared.actions.models import ActionParameterType, EvaluationType, DispatchType, DbQueryValueType, \
Expand Down Expand Up @@ -364,23 +364,6 @@ def validate_request_method(cls, v, values, **kwargs):
return v.upper()


class QueryConfig(BaseModel):
type: DbQueryValueType
value: DbActionOperationType

@root_validator
def check(cls, values):
from kairon.shared.utils import Utility

if Utility.check_empty_string(values.get('type')):
raise ValueError("type cannot be empty")

if Utility.check_empty_string(values.get('value')):
raise ValueError("value cannot be empty")

return values


class PayloadConfig(BaseModel):
type: DbQueryValueType
value: Any
Expand Down Expand Up @@ -422,7 +405,7 @@ def validate_source_code(cls, v, values, **kwargs):

class DatabaseActionRequest(BaseModel):
name: constr(to_lower=True, strip_whitespace=True)
query: QueryConfig
query: DbActionOperationType
payload: PayloadConfig
response: ActionResponseEvaluation = None
set_slots: List[SetSlotsUsingActionResponse] = []
Expand Down Expand Up @@ -947,28 +930,40 @@ def check(cls, values):
return values


class Metadata(BaseModel):
class ColumnMetadata(BaseModel):
column_name: str
data_type: CognitionMetadataType
enable_search: bool = True
create_embeddings: bool = True

@root_validator
def check(cls, values):
from kairon.shared.utils import Utility

if values.get('data_type') not in [CognitionMetadataType.str.value, CognitionMetadataType.int.value]:
raise ValueError("Only str and int data types are supported")
if Utility.check_empty_string(values.get('column_name')):
raise ValueError("Column name cannot be empty")
return values


class CognitionSchemaRequest(BaseModel):
metadata: List[ColumnMetadata] = None
collection_name: str


class CognitiveDataRequest(BaseModel):
data: Any
content_type: CognitionDataType
metadata: List[Metadata] = None
content_type: CognitionDataType = CognitionDataType.text.value
collection: str = None

@root_validator
def check(cls, values):
from kairon.shared.utils import Utility

data = values.get("data")
metadata = values.get("metadata", [])
if metadata:
for metadata_item in metadata:
Utility.retrieve_data(data, metadata_item.dict())
if not data or (isinstance(data, str) and Utility.check_empty_string(data)):
raise ValueError("data cannot be empty")
return values


Expand Down
23 changes: 12 additions & 11 deletions kairon/shared/actions/data_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,15 @@ def pre_save_post_validation(cls, sender, document, **kwargs):
param.value = Utility.encrypt_message(param.value)


class DbOperation(EmbeddedDocument):
type = StringField(required=True, choices=[op_type.value for op_type in DbQueryValueType])
value = StringField(required=True, choices=[payload.value for payload in DbActionOperationType])

def validate(self, clean=True):
if Utility.check_empty_string(self.type):
raise ValidationError("query type is required")
if not self.value or self.value is None:
raise ValidationError("query value is required")
# class DbOperation(EmbeddedDocument):
Copy link
Contributor

Choose a reason for hiding this comment

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

??

# type = StringField(required=True, choices=[op_type.value for op_type in DbQueryValueType])
# value = StringField(required=True, choices=[payload.value for payload in DbActionOperationType])
#
# def validate(self, clean=True):
# if Utility.check_empty_string(self.type):
# raise ValidationError("query type is required")
# if not self.value or self.value is None:
# raise ValidationError("query value is required")


class DbQuery(EmbeddedDocument):
Expand All @@ -189,7 +189,7 @@ def validate(self, clean=True):
class DatabaseAction(Auditlog):
name = StringField(required=True)
collection = StringField(required=True)
query = EmbeddedDocumentField(DbOperation, required=True)
query = StringField(required=True, choices=[payload.value for payload in DbActionOperationType])
Copy link
Contributor

Choose a reason for hiding this comment

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

rename to query type

payload = EmbeddedDocumentField(DbQuery, default=DbQuery())
response = EmbeddedDocumentField(HttpActionResponse, default=HttpActionResponse())
set_slots = ListField(EmbeddedDocumentField(SetSlotsFromResponse))
Expand All @@ -206,9 +206,10 @@ def validate(self, clean=True):

if self.name is None or not self.name.strip():
raise ValidationError("Action name cannot be empty")
if not self.query or self.query is None:
raise ValidationError("query value is required")
self.response.validate()
self.payload.validate()
self.query.validate()

def clean(self):
self.name = self.name.strip().lower()
Expand Down
Empty file.
Loading
Loading