mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-28 08:49:42 +02:00
feat: Update Dograh's UI Design (#67)
* feat: create app sidebar and update layout * fix: fix loading errors * fix: fix stack auth hydration issue * fix: fix design for create-workflow * fix: fix service configuration page design * Add header for workflow detail * feat: fix workflow editor design * Fix css classes * Fix callback status parsing for Vobiz * Fix filter and remove gender service
This commit is contained in:
parent
8342cd1dda
commit
a7f2238044
90 changed files with 4398 additions and 2312 deletions
|
|
@ -5,15 +5,15 @@ Revises: e02f387b7538
|
|||
Create Date: 2025-11-27 21:24:34.072030
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from alembic_postgresql_enum import TableReference
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'a188ff90e76f'
|
||||
down_revision: Union[str, None] = 'e02f387b7538'
|
||||
revision: str = "a188ff90e76f"
|
||||
down_revision: Union[str, None] = "e02f387b7538"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
|
@ -21,10 +21,23 @@ depends_on: Union[str, Sequence[str], None] = None
|
|||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.sync_enum_values(
|
||||
enum_schema='public',
|
||||
enum_name='workflow_run_mode',
|
||||
new_values=['twilio', 'vonage', 'vobiz', 'stasis', 'webrtc', 'smallwebrtc', 'VOICE', 'CHAT'],
|
||||
affected_columns=[TableReference(table_schema='public', table_name='workflow_runs', column_name='mode')],
|
||||
enum_schema="public",
|
||||
enum_name="workflow_run_mode",
|
||||
new_values=[
|
||||
"twilio",
|
||||
"vonage",
|
||||
"vobiz",
|
||||
"stasis",
|
||||
"webrtc",
|
||||
"smallwebrtc",
|
||||
"VOICE",
|
||||
"CHAT",
|
||||
],
|
||||
affected_columns=[
|
||||
TableReference(
|
||||
table_schema="public", table_name="workflow_runs", column_name="mode"
|
||||
)
|
||||
],
|
||||
enum_values_to_rename=[],
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -33,10 +46,22 @@ def upgrade() -> None:
|
|||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.sync_enum_values(
|
||||
enum_schema='public',
|
||||
enum_name='workflow_run_mode',
|
||||
new_values=['twilio', 'vonage', 'stasis', 'webrtc', 'smallwebrtc', 'VOICE', 'CHAT'],
|
||||
affected_columns=[TableReference(table_schema='public', table_name='workflow_runs', column_name='mode')],
|
||||
enum_schema="public",
|
||||
enum_name="workflow_run_mode",
|
||||
new_values=[
|
||||
"twilio",
|
||||
"vonage",
|
||||
"stasis",
|
||||
"webrtc",
|
||||
"smallwebrtc",
|
||||
"VOICE",
|
||||
"CHAT",
|
||||
],
|
||||
affected_columns=[
|
||||
TableReference(
|
||||
table_schema="public", table_name="workflow_runs", column_name="mode"
|
||||
)
|
||||
],
|
||||
enum_values_to_rename=[],
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from sqlalchemy import Integer, and_, cast
|
||||
from sqlalchemy import Integer, and_, cast, func
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
|
||||
from api.db.models import WorkflowRunModel
|
||||
|
|
@ -128,10 +128,16 @@ def apply_workflow_run_filters(
|
|||
):
|
||||
tags = value.get("codes", [])
|
||||
if tags:
|
||||
# The gathered_context column is JSON type (not JSONB)
|
||||
# JSON type doesn't support subscripting, so we must cast to JSONB first
|
||||
# Then extract call_tags and check containment with @>
|
||||
gathered_context_jsonb = cast(
|
||||
WorkflowRunModel.gathered_context, JSONB
|
||||
)
|
||||
# Use -> operator with literal text key to get call_tags as JSONB
|
||||
call_tags = gathered_context_jsonb.op("->")("call_tags")
|
||||
filter_conditions.append(
|
||||
cast(WorkflowRunModel.gathered_context, JSONB)[
|
||||
"call_tags"
|
||||
].contains(tags)
|
||||
call_tags.op("@>")(func.cast(tags, JSONB))
|
||||
)
|
||||
|
||||
elif filter_type == "text" and field == "initial_context.phone":
|
||||
|
|
|
|||
|
|
@ -277,7 +277,6 @@ async def handle_twilio_status_callback(
|
|||
# Parse form data
|
||||
form_data = await request.form()
|
||||
callback_data = dict(form_data)
|
||||
|
||||
logger.info(
|
||||
f"[run {workflow_run_id}] Received status callback: {json.dumps(callback_data)}"
|
||||
)
|
||||
|
|
@ -519,20 +518,11 @@ async def handle_vobiz_hangup_callback(
|
|||
This includes call duration, status, and billing information.
|
||||
"""
|
||||
# Parse the callback data (Vobiz sends form data or JSON)
|
||||
try:
|
||||
callback_data = await request.json()
|
||||
logger.info(
|
||||
f"[run {workflow_run_id}] Received Vobiz hangup callback (JSON): "
|
||||
f"{json.dumps(callback_data)}"
|
||||
)
|
||||
except Exception:
|
||||
# Fallback to form data if JSON fails
|
||||
form_data = await request.form()
|
||||
callback_data = dict(form_data)
|
||||
logger.info(
|
||||
f"[run {workflow_run_id}] Received Vobiz hangup callback (form): "
|
||||
f"{json.dumps(callback_data)}"
|
||||
)
|
||||
form_data = await request.form()
|
||||
callback_data = dict(form_data)
|
||||
logger.info(
|
||||
f"[run {workflow_run_id}] Received Vobiz hangup callback {json.dumps(callback_data)}"
|
||||
)
|
||||
|
||||
# Get workflow run for processing
|
||||
workflow_run = await db_client.get_workflow_run_by_id(workflow_run_id)
|
||||
|
|
@ -591,19 +581,11 @@ async def handle_vobiz_ring_callback(
|
|||
This is optional and used for tracking ringing status.
|
||||
"""
|
||||
# Parse the callback data
|
||||
try:
|
||||
callback_data = await request.json()
|
||||
logger.info(
|
||||
f"[run {workflow_run_id}] Received Vobiz ring callback (JSON): "
|
||||
f"{json.dumps(callback_data)}"
|
||||
)
|
||||
except Exception:
|
||||
form_data = await request.form()
|
||||
callback_data = dict(form_data)
|
||||
logger.info(
|
||||
f"[run {workflow_run_id}] Received Vobiz ring callback (form): "
|
||||
f"{json.dumps(callback_data)}"
|
||||
)
|
||||
form_data = await request.form()
|
||||
callback_data = dict(form_data)
|
||||
logger.info(
|
||||
f"[run {workflow_run_id}] Received Vobiz ring callback {json.dumps(callback_data)}"
|
||||
)
|
||||
|
||||
# Get workflow run for processing
|
||||
workflow_run = await db_client.get_workflow_run_by_id(workflow_run_id)
|
||||
|
|
|
|||
|
|
@ -275,13 +275,13 @@ class VobizProvider(TelephonyProvider):
|
|||
- status, from, to, duration, etc.
|
||||
"""
|
||||
return {
|
||||
"call_id": data.get("call_uuid", data.get("CallUUID", "")),
|
||||
"status": data.get("status", data.get("Status", "")),
|
||||
"from_number": data.get("from", data.get("From")),
|
||||
"to_number": data.get("to", data.get("To")),
|
||||
"direction": data.get("direction", data.get("Direction")),
|
||||
"duration": data.get("duration", data.get("Duration")),
|
||||
"extra": data, # Include all original data
|
||||
"call_id": data.get("CallUUID", ""),
|
||||
"status": data.get("CallStatus", ""),
|
||||
"from_number": data.get("From"),
|
||||
"to_number": data.get("To"),
|
||||
"direction": data.get("Direction"),
|
||||
"duration": data.get("Duration"),
|
||||
"extra": data,
|
||||
}
|
||||
|
||||
async def handle_websocket(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Optional, Union
|
||||
|
||||
from api.constants import DEPLOYMENT_MODE, ENABLE_TRACING, VOICEMAIL_RECORDING_DURATION
|
||||
from api.services.gender.gender_service import GenderService
|
||||
from api.services.workflow.disposition_mapper import (
|
||||
apply_disposition_mapping,
|
||||
get_organization_id_from_workflow_run,
|
||||
|
|
@ -94,8 +93,6 @@ class PipecatEngine:
|
|||
# access to _context
|
||||
self._variable_extraction_manager = None
|
||||
|
||||
self._gender_service = GenderService(confidence_threshold=0.5)
|
||||
|
||||
# Voicemail detection state
|
||||
self._detect_voicemail = False
|
||||
self._voicemail_detector = None
|
||||
|
|
@ -160,13 +157,6 @@ class PipecatEngine:
|
|||
# Register built-in functions with the LLM
|
||||
await self._register_builtin_functions()
|
||||
|
||||
# Set gender in initial context predicted from first name
|
||||
if "first_name" in self._call_context_vars:
|
||||
salutation = await self._gender_service.get_salutation(
|
||||
self._call_context_vars["first_name"]
|
||||
)
|
||||
self._call_context_vars["salutation"] = salutation
|
||||
|
||||
await self.set_node(self.workflow.start_node_id)
|
||||
logger.debug(f"{self.__class__.__name__} initialized")
|
||||
except Exception as e:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue