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

release: v0.3.0 #94

Merged
merged 4 commits into from
Oct 1, 2024
Merged
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
6 changes: 4 additions & 2 deletions backend/chatsky_ui/api/api_v1/api.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from fastapi import APIRouter

from chatsky_ui.api.api_v1.endpoints import bot, config, dff_services, flows
from chatsky_ui.api.api_v1.endpoints import bot, chatsky_services, config, flows
from chatsky_ui.core.config import settings

api_router = APIRouter()

api_router.include_router(config.router, prefix="/".join([settings.API_V1_STR, "config"]), tags=["config"])
api_router.include_router(flows.router, prefix="/".join([settings.API_V1_STR, "flows"]), tags=["flows"])
api_router.include_router(dff_services.router, prefix="/".join([settings.API_V1_STR, "services"]), tags=["services"])
api_router.include_router(
chatsky_services.router, prefix="/".join([settings.API_V1_STR, "services"]), tags=["services"]
)
api_router.include_router(bot.router, prefix="/".join([settings.API_V1_STR, "bot"]), tags=["bot"])
5 changes: 3 additions & 2 deletions backend/chatsky_ui/api/api_v1/endpoints/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from chatsky_ui.api import deps
from chatsky_ui.schemas.pagination import Pagination
from chatsky_ui.schemas.preset import Preset
from chatsky_ui.schemas.process_status import Status
from chatsky_ui.services.index import Index
from chatsky_ui.services.process_manager import BuildManager, ProcessManager, RunManager
from chatsky_ui.services.websocket_manager import WebSocketManager
Expand Down Expand Up @@ -264,8 +265,6 @@ async def connect(
await websocket_manager.connect(websocket)
run_manager.logger.info("Websocket for run process '%s' has been opened", run_id)

await websocket.send_text("Start chatting")

output_task = asyncio.create_task(
websocket_manager.send_process_output_to_websocket(run_id, run_manager, websocket)
)
Expand All @@ -279,3 +278,5 @@ async def connect(
return_when=asyncio.FIRST_COMPLETED,
)
websocket_manager.disconnect(websocket)
if await run_manager.get_status(run_id) in [Status.ALIVE, Status.RUNNING]:
await run_manager.stop(run_id)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pylint.reporters.text import TextReporter

from chatsky_ui.api.deps import get_index
from chatsky_ui.clients.dff_client import get_dff_conditions
from chatsky_ui.clients.chatsky_client import get_chatsky_conditions
from chatsky_ui.core.config import settings
from chatsky_ui.schemas.code_snippet import CodeSnippet
from chatsky_ui.services.index import Index
Expand Down Expand Up @@ -56,5 +56,5 @@ async def lint_snippet(snippet: CodeSnippet) -> Dict[str, str]:

@router.get("/get_conditions", status_code=200)
async def get_conditions() -> Dict[str, Union[str, list]]:
"""Gets the dff's out-of-the-box conditions."""
return {"status": "ok", "data": get_dff_conditions()}
"""Gets the chatsky's out-of-the-box conditions."""
return {"status": "ok", "data": get_chatsky_conditions()}
4 changes: 2 additions & 2 deletions backend/chatsky_ui/api/api_v1/endpoints/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@


@router.get("/")
async def flows_get() -> Dict[str, Union[str, Dict[str, list]]]:
async def flows_get() -> Dict[str, Union[str, Dict[str, Union[list, dict]]]]:
"""Get the flows by reading the frontend_flows.yaml file."""
omega_flows = await read_conf(settings.frontend_flows_path)
dict_flows = OmegaConf.to_container(omega_flows, resolve=True)
return {"status": "ok", "data": dict_flows} # type: ignore


@router.post("/")
async def flows_post(flows: Dict[str, list]) -> Dict[str, str]:
async def flows_post(flows: Dict[str, Union[list, dict]]) -> Dict[str, str]:
"""Write the flows to the frontend_flows.yaml file."""
await write_conf(flows, settings.frontend_flows_path)
return {"status": "ok"}
2 changes: 1 addition & 1 deletion backend/chatsky_ui/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from cookiecutter.main import cookiecutter
from typing_extensions import Annotated

# Patch nest_asyncio before importing DFF
# Patch nest_asyncio before importing Chatsky
nest_asyncio.apply = lambda: None

from chatsky_ui.core.config import app_runner, settings # noqa: E402
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
from typing import List

import dff.script.conditions as cnd
from dff.pipeline.pipeline import script_parsing
import chatsky.conditions as cnd
from chatsky.core import script_parsing

AUTO_COMPLETION_MAP = {
"exact_match": 'cnd.exact_match(Message("hello"))(ctx, pipeline)',
"regexp": 'cnd.regexp(r"how are you", re.IGNORECASE)(ctx, pipeline)',
"any": 'cnd.any([hi_lower_case_condition, cnd.exact_match(Message("hello"))])(ctx, pipeline)',
"all": 'cnd.all([cnd.regexp(r"talk"), cnd.regexp(r"about.*music")])(ctx, pipeline)',
"ExactMatch": 'await cnd.ExactMatch("hello")(ctx)',
"Regexp": 'await cnd.Regexp("how are you")(ctx)',
"Any": "cnd.Any([hi_lower_case_condition, cnd.ExactMatch(hello)])(ctx)",
"All": 'cnd.All([cnd.Regexp("talk"), cnd.Regexp("about.*music")])(ctx)',
}


def get_dff_conditions() -> List[dict]:
"""Gets the DFF's out-of-the-box conditions.
def get_chatsky_conditions() -> List[dict]:
"""Gets the Chatsky's out-of-the-box conditions.

Returns:
List of conditions info with the following keys:
"label": The condition name suggestions to pop up for user.
"type": "function".
"info": Detailed info about every condition, parsed from DFF docs.
"info": Detailed info about every condition, parsed from Chatsky docs.
"apply": Autocompletion of the conditon call.
"""
native_services = script_parsing.get_dff_objects()
native_conditions = [k.split(".")[-1] for k, _ in native_services.items() if k.startswith("dff.cnd.")]
native_services = script_parsing.get_chatsky_objects()
native_conditions = [k.split(".")[-1] for k, _ in native_services.items() if k.startswith("chatsky.cnd.")]
cnd_full_info = []
for condition in native_conditions:
cnd_full_info.append(
{
"label": f"cnd.{condition}",
"type": "function",
"info": getattr(cnd, condition).__doc__,
"apply": AUTO_COMPLETION_MAP.get(condition, "cnd.<DFF_CONDITION>()(ctx, pipeline)"),
"apply": AUTO_COMPLETION_MAP.get(condition, "cnd.<CHATSKY_CONDITION>()(ctx, pipeline)"),
}
)

Expand Down
5 changes: 3 additions & 2 deletions backend/chatsky_ui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse

from chatsky_ui import __version__
from chatsky_ui.api.api_v1.api import api_router
from chatsky_ui.api.deps import get_index
from chatsky_ui.core.config import settings
Expand All @@ -20,10 +21,10 @@ async def lifespan(app: FastAPI):
await index_dict["instance"].load()
yield

settings.temp_conf.unlink(missing_ok=True)
# settings.temp_conf.unlink(missing_ok=True)


app = FastAPI(title="DF Designer", lifespan=lifespan)
app = FastAPI(title="DF Designer", version=__version__, lifespan=lifespan)


app.add_middleware(
Expand Down
48 changes: 48 additions & 0 deletions backend/chatsky_ui/services/condition_finder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import ast
from ast import NodeTransformer
from typing import Dict, List

from chatsky_ui.core.logger_config import get_logger

logger = get_logger(__name__)


class ServiceReplacer(NodeTransformer):
def __init__(self, new_services: List[str]):
self.new_services_classes = self._get_classes_def(new_services)

def _get_classes_def(self, services_code: List[str]) -> Dict[str, ast.ClassDef]:
parsed_codes = [ast.parse(service_code) for service_code in services_code]
result_nodes = {}
for idx, parsed_code in enumerate(parsed_codes):
self._extract_class_defs(parsed_code, result_nodes, services_code[idx])
return result_nodes

def _extract_class_defs(self, parsed_code: ast.Module, result_nodes: Dict[str, ast.ClassDef], service_code: str):
for node in parsed_code.body:
if isinstance(node, ast.ClassDef):
result_nodes[node.name] = node
else:
logger.error("No class definition found in new_service: %s", service_code)

def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef:
logger.debug("Visiting class '%s' and comparing with: %s", node.name, self.new_services_classes.keys())
if node.name in self.new_services_classes:
return self._get_class_def(node)
return node

def _get_class_def(self, node: ast.ClassDef) -> ast.ClassDef:
service = self.new_services_classes[node.name]
del self.new_services_classes[node.name]
return service

def generic_visit(self, node: ast.AST):
super().generic_visit(node)
if isinstance(node, ast.Module) and self.new_services_classes:
self._append_new_services(node)
return node

def _append_new_services(self, node: ast.Module):
logger.info("Services not found, appending new services: %s", list(self.new_services_classes.keys()))
for _, service in self.new_services_classes.items():
node.body.append(service)
Loading
Loading