PraisonAI 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- praisonai/__init__.py +54 -0
- praisonai/__main__.py +15 -0
- praisonai/acp/__init__.py +54 -0
- praisonai/acp/config.py +159 -0
- praisonai/acp/server.py +587 -0
- praisonai/acp/session.py +219 -0
- praisonai/adapters/__init__.py +50 -0
- praisonai/adapters/readers.py +395 -0
- praisonai/adapters/rerankers.py +315 -0
- praisonai/adapters/retrievers.py +394 -0
- praisonai/adapters/vector_stores.py +409 -0
- praisonai/agent_scheduler.py +337 -0
- praisonai/agents_generator.py +903 -0
- praisonai/api/call.py +292 -0
- praisonai/auto.py +1197 -0
- praisonai/capabilities/__init__.py +275 -0
- praisonai/capabilities/a2a.py +140 -0
- praisonai/capabilities/assistants.py +283 -0
- praisonai/capabilities/audio.py +320 -0
- praisonai/capabilities/batches.py +469 -0
- praisonai/capabilities/completions.py +336 -0
- praisonai/capabilities/container_files.py +155 -0
- praisonai/capabilities/containers.py +93 -0
- praisonai/capabilities/embeddings.py +158 -0
- praisonai/capabilities/files.py +467 -0
- praisonai/capabilities/fine_tuning.py +293 -0
- praisonai/capabilities/guardrails.py +182 -0
- praisonai/capabilities/images.py +330 -0
- praisonai/capabilities/mcp.py +190 -0
- praisonai/capabilities/messages.py +270 -0
- praisonai/capabilities/moderations.py +154 -0
- praisonai/capabilities/ocr.py +217 -0
- praisonai/capabilities/passthrough.py +204 -0
- praisonai/capabilities/rag.py +207 -0
- praisonai/capabilities/realtime.py +160 -0
- praisonai/capabilities/rerank.py +165 -0
- praisonai/capabilities/responses.py +266 -0
- praisonai/capabilities/search.py +109 -0
- praisonai/capabilities/skills.py +133 -0
- praisonai/capabilities/vector_store_files.py +334 -0
- praisonai/capabilities/vector_stores.py +304 -0
- praisonai/capabilities/videos.py +141 -0
- praisonai/chainlit_ui.py +304 -0
- praisonai/chat/__init__.py +106 -0
- praisonai/chat/app.py +125 -0
- praisonai/cli/__init__.py +26 -0
- praisonai/cli/app.py +213 -0
- praisonai/cli/commands/__init__.py +75 -0
- praisonai/cli/commands/acp.py +70 -0
- praisonai/cli/commands/completion.py +333 -0
- praisonai/cli/commands/config.py +166 -0
- praisonai/cli/commands/debug.py +142 -0
- praisonai/cli/commands/diag.py +55 -0
- praisonai/cli/commands/doctor.py +166 -0
- praisonai/cli/commands/environment.py +179 -0
- praisonai/cli/commands/lsp.py +112 -0
- praisonai/cli/commands/mcp.py +210 -0
- praisonai/cli/commands/profile.py +457 -0
- praisonai/cli/commands/run.py +228 -0
- praisonai/cli/commands/schedule.py +150 -0
- praisonai/cli/commands/serve.py +97 -0
- praisonai/cli/commands/session.py +212 -0
- praisonai/cli/commands/traces.py +145 -0
- praisonai/cli/commands/version.py +101 -0
- praisonai/cli/configuration/__init__.py +18 -0
- praisonai/cli/configuration/loader.py +353 -0
- praisonai/cli/configuration/paths.py +114 -0
- praisonai/cli/configuration/schema.py +164 -0
- praisonai/cli/features/__init__.py +268 -0
- praisonai/cli/features/acp.py +236 -0
- praisonai/cli/features/action_orchestrator.py +546 -0
- praisonai/cli/features/agent_scheduler.py +773 -0
- praisonai/cli/features/agent_tools.py +474 -0
- praisonai/cli/features/agents.py +375 -0
- praisonai/cli/features/at_mentions.py +471 -0
- praisonai/cli/features/auto_memory.py +182 -0
- praisonai/cli/features/autonomy_mode.py +490 -0
- praisonai/cli/features/background.py +356 -0
- praisonai/cli/features/base.py +168 -0
- praisonai/cli/features/capabilities.py +1326 -0
- praisonai/cli/features/checkpoints.py +338 -0
- praisonai/cli/features/code_intelligence.py +652 -0
- praisonai/cli/features/compaction.py +294 -0
- praisonai/cli/features/compare.py +534 -0
- praisonai/cli/features/cost_tracker.py +514 -0
- praisonai/cli/features/debug.py +810 -0
- praisonai/cli/features/deploy.py +517 -0
- praisonai/cli/features/diag.py +289 -0
- praisonai/cli/features/doctor/__init__.py +63 -0
- praisonai/cli/features/doctor/checks/__init__.py +24 -0
- praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
- praisonai/cli/features/doctor/checks/config_checks.py +366 -0
- praisonai/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai/cli/features/doctor/checks/env_checks.py +543 -0
- praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
- praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
- praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
- praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai/cli/features/doctor/engine.py +266 -0
- praisonai/cli/features/doctor/formatters.py +310 -0
- praisonai/cli/features/doctor/handler.py +397 -0
- praisonai/cli/features/doctor/models.py +264 -0
- praisonai/cli/features/doctor/registry.py +239 -0
- praisonai/cli/features/endpoints.py +1019 -0
- praisonai/cli/features/eval.py +560 -0
- praisonai/cli/features/external_agents.py +231 -0
- praisonai/cli/features/fast_context.py +410 -0
- praisonai/cli/features/flow_display.py +566 -0
- praisonai/cli/features/git_integration.py +651 -0
- praisonai/cli/features/guardrail.py +171 -0
- praisonai/cli/features/handoff.py +185 -0
- praisonai/cli/features/hooks.py +583 -0
- praisonai/cli/features/image.py +384 -0
- praisonai/cli/features/interactive_runtime.py +585 -0
- praisonai/cli/features/interactive_tools.py +380 -0
- praisonai/cli/features/interactive_tui.py +603 -0
- praisonai/cli/features/jobs.py +632 -0
- praisonai/cli/features/knowledge.py +531 -0
- praisonai/cli/features/lite.py +244 -0
- praisonai/cli/features/lsp_cli.py +225 -0
- praisonai/cli/features/mcp.py +169 -0
- praisonai/cli/features/message_queue.py +587 -0
- praisonai/cli/features/metrics.py +211 -0
- praisonai/cli/features/n8n.py +673 -0
- praisonai/cli/features/observability.py +293 -0
- praisonai/cli/features/ollama.py +361 -0
- praisonai/cli/features/output_style.py +273 -0
- praisonai/cli/features/package.py +631 -0
- praisonai/cli/features/performance.py +308 -0
- praisonai/cli/features/persistence.py +636 -0
- praisonai/cli/features/profile.py +226 -0
- praisonai/cli/features/profiler/__init__.py +81 -0
- praisonai/cli/features/profiler/core.py +558 -0
- praisonai/cli/features/profiler/optimizations.py +652 -0
- praisonai/cli/features/profiler/suite.py +386 -0
- praisonai/cli/features/profiling.py +350 -0
- praisonai/cli/features/queue/__init__.py +73 -0
- praisonai/cli/features/queue/manager.py +395 -0
- praisonai/cli/features/queue/models.py +286 -0
- praisonai/cli/features/queue/persistence.py +564 -0
- praisonai/cli/features/queue/scheduler.py +484 -0
- praisonai/cli/features/queue/worker.py +372 -0
- praisonai/cli/features/recipe.py +1723 -0
- praisonai/cli/features/recipes.py +449 -0
- praisonai/cli/features/registry.py +229 -0
- praisonai/cli/features/repo_map.py +860 -0
- praisonai/cli/features/router.py +466 -0
- praisonai/cli/features/sandbox_executor.py +515 -0
- praisonai/cli/features/serve.py +829 -0
- praisonai/cli/features/session.py +222 -0
- praisonai/cli/features/skills.py +856 -0
- praisonai/cli/features/slash_commands.py +650 -0
- praisonai/cli/features/telemetry.py +179 -0
- praisonai/cli/features/templates.py +1384 -0
- praisonai/cli/features/thinking.py +305 -0
- praisonai/cli/features/todo.py +334 -0
- praisonai/cli/features/tools.py +680 -0
- praisonai/cli/features/tui/__init__.py +83 -0
- praisonai/cli/features/tui/app.py +580 -0
- praisonai/cli/features/tui/cli.py +566 -0
- praisonai/cli/features/tui/debug.py +511 -0
- praisonai/cli/features/tui/events.py +99 -0
- praisonai/cli/features/tui/mock_provider.py +328 -0
- praisonai/cli/features/tui/orchestrator.py +652 -0
- praisonai/cli/features/tui/screens/__init__.py +50 -0
- praisonai/cli/features/tui/screens/main.py +245 -0
- praisonai/cli/features/tui/screens/queue.py +174 -0
- praisonai/cli/features/tui/screens/session.py +124 -0
- praisonai/cli/features/tui/screens/settings.py +148 -0
- praisonai/cli/features/tui/widgets/__init__.py +56 -0
- praisonai/cli/features/tui/widgets/chat.py +261 -0
- praisonai/cli/features/tui/widgets/composer.py +224 -0
- praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
- praisonai/cli/features/tui/widgets/status.py +167 -0
- praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
- praisonai/cli/features/workflow.py +720 -0
- praisonai/cli/legacy.py +236 -0
- praisonai/cli/main.py +5559 -0
- praisonai/cli/schedule_cli.py +54 -0
- praisonai/cli/state/__init__.py +31 -0
- praisonai/cli/state/identifiers.py +161 -0
- praisonai/cli/state/sessions.py +313 -0
- praisonai/code/__init__.py +93 -0
- praisonai/code/agent_tools.py +344 -0
- praisonai/code/diff/__init__.py +21 -0
- praisonai/code/diff/diff_strategy.py +432 -0
- praisonai/code/tools/__init__.py +27 -0
- praisonai/code/tools/apply_diff.py +221 -0
- praisonai/code/tools/execute_command.py +275 -0
- praisonai/code/tools/list_files.py +274 -0
- praisonai/code/tools/read_file.py +206 -0
- praisonai/code/tools/search_replace.py +248 -0
- praisonai/code/tools/write_file.py +217 -0
- praisonai/code/utils/__init__.py +46 -0
- praisonai/code/utils/file_utils.py +307 -0
- praisonai/code/utils/ignore_utils.py +308 -0
- praisonai/code/utils/text_utils.py +276 -0
- praisonai/db/__init__.py +64 -0
- praisonai/db/adapter.py +531 -0
- praisonai/deploy/__init__.py +62 -0
- praisonai/deploy/api.py +231 -0
- praisonai/deploy/docker.py +454 -0
- praisonai/deploy/doctor.py +367 -0
- praisonai/deploy/main.py +327 -0
- praisonai/deploy/models.py +179 -0
- praisonai/deploy/providers/__init__.py +33 -0
- praisonai/deploy/providers/aws.py +331 -0
- praisonai/deploy/providers/azure.py +358 -0
- praisonai/deploy/providers/base.py +101 -0
- praisonai/deploy/providers/gcp.py +314 -0
- praisonai/deploy/schema.py +208 -0
- praisonai/deploy.py +185 -0
- praisonai/endpoints/__init__.py +53 -0
- praisonai/endpoints/a2u_server.py +410 -0
- praisonai/endpoints/discovery.py +165 -0
- praisonai/endpoints/providers/__init__.py +28 -0
- praisonai/endpoints/providers/a2a.py +253 -0
- praisonai/endpoints/providers/a2u.py +208 -0
- praisonai/endpoints/providers/agents_api.py +171 -0
- praisonai/endpoints/providers/base.py +231 -0
- praisonai/endpoints/providers/mcp.py +263 -0
- praisonai/endpoints/providers/recipe.py +206 -0
- praisonai/endpoints/providers/tools_mcp.py +150 -0
- praisonai/endpoints/registry.py +131 -0
- praisonai/endpoints/server.py +161 -0
- praisonai/inbuilt_tools/__init__.py +24 -0
- praisonai/inbuilt_tools/autogen_tools.py +117 -0
- praisonai/inc/__init__.py +2 -0
- praisonai/inc/config.py +96 -0
- praisonai/inc/models.py +155 -0
- praisonai/integrations/__init__.py +56 -0
- praisonai/integrations/base.py +303 -0
- praisonai/integrations/claude_code.py +270 -0
- praisonai/integrations/codex_cli.py +255 -0
- praisonai/integrations/cursor_cli.py +195 -0
- praisonai/integrations/gemini_cli.py +222 -0
- praisonai/jobs/__init__.py +67 -0
- praisonai/jobs/executor.py +425 -0
- praisonai/jobs/models.py +230 -0
- praisonai/jobs/router.py +314 -0
- praisonai/jobs/server.py +186 -0
- praisonai/jobs/store.py +203 -0
- praisonai/llm/__init__.py +66 -0
- praisonai/llm/registry.py +382 -0
- praisonai/mcp_server/__init__.py +152 -0
- praisonai/mcp_server/adapters/__init__.py +74 -0
- praisonai/mcp_server/adapters/agents.py +128 -0
- praisonai/mcp_server/adapters/capabilities.py +168 -0
- praisonai/mcp_server/adapters/cli_tools.py +568 -0
- praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
- praisonai/mcp_server/adapters/knowledge.py +93 -0
- praisonai/mcp_server/adapters/memory.py +104 -0
- praisonai/mcp_server/adapters/prompts.py +306 -0
- praisonai/mcp_server/adapters/resources.py +124 -0
- praisonai/mcp_server/adapters/tools_bridge.py +280 -0
- praisonai/mcp_server/auth/__init__.py +48 -0
- praisonai/mcp_server/auth/api_key.py +291 -0
- praisonai/mcp_server/auth/oauth.py +460 -0
- praisonai/mcp_server/auth/oidc.py +289 -0
- praisonai/mcp_server/auth/scopes.py +260 -0
- praisonai/mcp_server/cli.py +852 -0
- praisonai/mcp_server/elicitation.py +445 -0
- praisonai/mcp_server/icons.py +302 -0
- praisonai/mcp_server/recipe_adapter.py +573 -0
- praisonai/mcp_server/recipe_cli.py +824 -0
- praisonai/mcp_server/registry.py +703 -0
- praisonai/mcp_server/sampling.py +422 -0
- praisonai/mcp_server/server.py +490 -0
- praisonai/mcp_server/tasks.py +443 -0
- praisonai/mcp_server/transports/__init__.py +18 -0
- praisonai/mcp_server/transports/http_stream.py +376 -0
- praisonai/mcp_server/transports/stdio.py +132 -0
- praisonai/persistence/__init__.py +84 -0
- praisonai/persistence/config.py +238 -0
- praisonai/persistence/conversation/__init__.py +25 -0
- praisonai/persistence/conversation/async_mysql.py +427 -0
- praisonai/persistence/conversation/async_postgres.py +410 -0
- praisonai/persistence/conversation/async_sqlite.py +371 -0
- praisonai/persistence/conversation/base.py +151 -0
- praisonai/persistence/conversation/json_store.py +250 -0
- praisonai/persistence/conversation/mysql.py +387 -0
- praisonai/persistence/conversation/postgres.py +401 -0
- praisonai/persistence/conversation/singlestore.py +240 -0
- praisonai/persistence/conversation/sqlite.py +341 -0
- praisonai/persistence/conversation/supabase.py +203 -0
- praisonai/persistence/conversation/surrealdb.py +287 -0
- praisonai/persistence/factory.py +301 -0
- praisonai/persistence/hooks/__init__.py +18 -0
- praisonai/persistence/hooks/agent_hooks.py +297 -0
- praisonai/persistence/knowledge/__init__.py +26 -0
- praisonai/persistence/knowledge/base.py +144 -0
- praisonai/persistence/knowledge/cassandra.py +232 -0
- praisonai/persistence/knowledge/chroma.py +295 -0
- praisonai/persistence/knowledge/clickhouse.py +242 -0
- praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
- praisonai/persistence/knowledge/couchbase.py +286 -0
- praisonai/persistence/knowledge/lancedb.py +216 -0
- praisonai/persistence/knowledge/langchain_adapter.py +291 -0
- praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
- praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
- praisonai/persistence/knowledge/milvus.py +277 -0
- praisonai/persistence/knowledge/mongodb_vector.py +306 -0
- praisonai/persistence/knowledge/pgvector.py +335 -0
- praisonai/persistence/knowledge/pinecone.py +253 -0
- praisonai/persistence/knowledge/qdrant.py +301 -0
- praisonai/persistence/knowledge/redis_vector.py +291 -0
- praisonai/persistence/knowledge/singlestore_vector.py +299 -0
- praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
- praisonai/persistence/knowledge/upstash_vector.py +266 -0
- praisonai/persistence/knowledge/weaviate.py +223 -0
- praisonai/persistence/migrations/__init__.py +10 -0
- praisonai/persistence/migrations/manager.py +251 -0
- praisonai/persistence/orchestrator.py +406 -0
- praisonai/persistence/state/__init__.py +21 -0
- praisonai/persistence/state/async_mongodb.py +200 -0
- praisonai/persistence/state/base.py +107 -0
- praisonai/persistence/state/dynamodb.py +226 -0
- praisonai/persistence/state/firestore.py +175 -0
- praisonai/persistence/state/gcs.py +155 -0
- praisonai/persistence/state/memory.py +245 -0
- praisonai/persistence/state/mongodb.py +158 -0
- praisonai/persistence/state/redis.py +190 -0
- praisonai/persistence/state/upstash.py +144 -0
- praisonai/persistence/tests/__init__.py +3 -0
- praisonai/persistence/tests/test_all_backends.py +633 -0
- praisonai/profiler.py +1214 -0
- praisonai/recipe/__init__.py +134 -0
- praisonai/recipe/bridge.py +278 -0
- praisonai/recipe/core.py +893 -0
- praisonai/recipe/exceptions.py +54 -0
- praisonai/recipe/history.py +402 -0
- praisonai/recipe/models.py +266 -0
- praisonai/recipe/operations.py +440 -0
- praisonai/recipe/policy.py +422 -0
- praisonai/recipe/registry.py +849 -0
- praisonai/recipe/runtime.py +214 -0
- praisonai/recipe/security.py +711 -0
- praisonai/recipe/serve.py +859 -0
- praisonai/recipe/server.py +613 -0
- praisonai/scheduler/__init__.py +45 -0
- praisonai/scheduler/agent_scheduler.py +552 -0
- praisonai/scheduler/base.py +124 -0
- praisonai/scheduler/daemon_manager.py +225 -0
- praisonai/scheduler/state_manager.py +155 -0
- praisonai/scheduler/yaml_loader.py +193 -0
- praisonai/scheduler.py +194 -0
- praisonai/setup/__init__.py +1 -0
- praisonai/setup/build.py +21 -0
- praisonai/setup/post_install.py +23 -0
- praisonai/setup/setup_conda_env.py +25 -0
- praisonai/setup.py +16 -0
- praisonai/templates/__init__.py +116 -0
- praisonai/templates/cache.py +364 -0
- praisonai/templates/dependency_checker.py +358 -0
- praisonai/templates/discovery.py +391 -0
- praisonai/templates/loader.py +564 -0
- praisonai/templates/registry.py +511 -0
- praisonai/templates/resolver.py +206 -0
- praisonai/templates/security.py +327 -0
- praisonai/templates/tool_override.py +498 -0
- praisonai/templates/tools_doctor.py +256 -0
- praisonai/test.py +105 -0
- praisonai/train.py +562 -0
- praisonai/train_vision.py +306 -0
- praisonai/ui/agents.py +824 -0
- praisonai/ui/callbacks.py +57 -0
- praisonai/ui/chainlit_compat.py +246 -0
- praisonai/ui/chat.py +532 -0
- praisonai/ui/code.py +717 -0
- praisonai/ui/colab.py +474 -0
- praisonai/ui/colab_chainlit.py +81 -0
- praisonai/ui/components/aicoder.py +284 -0
- praisonai/ui/context.py +283 -0
- praisonai/ui/database_config.py +56 -0
- praisonai/ui/db.py +294 -0
- praisonai/ui/realtime.py +488 -0
- praisonai/ui/realtimeclient/__init__.py +756 -0
- praisonai/ui/realtimeclient/tools.py +242 -0
- praisonai/ui/sql_alchemy.py +710 -0
- praisonai/upload_vision.py +140 -0
- praisonai/version.py +1 -0
- praisonai-3.0.0.dist-info/METADATA +3493 -0
- praisonai-3.0.0.dist-info/RECORD +393 -0
- praisonai-3.0.0.dist-info/WHEEL +5 -0
- praisonai-3.0.0.dist-info/entry_points.txt +4 -0
- praisonai-3.0.0.dist-info/top_level.txt +1 -0
praisonai/ui/realtime.py
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import asyncio
|
|
3
|
+
import sqlite3
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from openai import AsyncOpenAI
|
|
8
|
+
import chainlit as cl
|
|
9
|
+
from chainlit.input_widget import TextInput
|
|
10
|
+
from chainlit.types import ThreadDict
|
|
11
|
+
|
|
12
|
+
from realtimeclient import RealtimeClient
|
|
13
|
+
from realtimeclient.tools import tools
|
|
14
|
+
from sql_alchemy import SQLAlchemyDataLayer
|
|
15
|
+
import chainlit.data as cl_data
|
|
16
|
+
from literalai.helper import utc_now
|
|
17
|
+
import json
|
|
18
|
+
import logging
|
|
19
|
+
import importlib.util
|
|
20
|
+
from importlib import import_module
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
# Set up logging
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
log_level = os.getenv("LOGLEVEL", "INFO").upper()
|
|
26
|
+
logger.handlers = []
|
|
27
|
+
|
|
28
|
+
# Set up logging to console
|
|
29
|
+
console_handler = logging.StreamHandler()
|
|
30
|
+
console_handler.setLevel(log_level)
|
|
31
|
+
console_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
32
|
+
console_handler.setFormatter(console_formatter)
|
|
33
|
+
logger.addHandler(console_handler)
|
|
34
|
+
|
|
35
|
+
# Set the logging level for the logger
|
|
36
|
+
logger.setLevel(log_level)
|
|
37
|
+
|
|
38
|
+
# Set up CHAINLIT_AUTH_SECRET
|
|
39
|
+
CHAINLIT_AUTH_SECRET = os.getenv("CHAINLIT_AUTH_SECRET")
|
|
40
|
+
|
|
41
|
+
if not CHAINLIT_AUTH_SECRET:
|
|
42
|
+
os.environ["CHAINLIT_AUTH_SECRET"] = "p8BPhQChpg@J>jBz$wGxqLX2V>yTVgP*7Ky9H$aV:axW~ANNX-7_T:o@lnyCBu^U"
|
|
43
|
+
CHAINLIT_AUTH_SECRET = os.getenv("CHAINLIT_AUTH_SECRET")
|
|
44
|
+
|
|
45
|
+
# Database path
|
|
46
|
+
DB_PATH = os.path.expanduser("~/.praison/database.sqlite")
|
|
47
|
+
|
|
48
|
+
def initialize_db():
|
|
49
|
+
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
|
|
50
|
+
conn = sqlite3.connect(DB_PATH)
|
|
51
|
+
cursor = conn.cursor()
|
|
52
|
+
cursor.execute('''
|
|
53
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
54
|
+
id UUID PRIMARY KEY,
|
|
55
|
+
identifier TEXT NOT NULL UNIQUE,
|
|
56
|
+
metadata JSONB NOT NULL,
|
|
57
|
+
createdAt TEXT
|
|
58
|
+
)
|
|
59
|
+
''')
|
|
60
|
+
cursor.execute('''
|
|
61
|
+
CREATE TABLE IF NOT EXISTS threads (
|
|
62
|
+
id UUID PRIMARY KEY,
|
|
63
|
+
createdAt TEXT,
|
|
64
|
+
name TEXT,
|
|
65
|
+
userId UUID,
|
|
66
|
+
userIdentifier TEXT,
|
|
67
|
+
tags TEXT[],
|
|
68
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
69
|
+
FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
|
|
70
|
+
)
|
|
71
|
+
''')
|
|
72
|
+
cursor.execute('''
|
|
73
|
+
CREATE TABLE IF NOT EXISTS steps (
|
|
74
|
+
id UUID PRIMARY KEY,
|
|
75
|
+
name TEXT NOT NULL,
|
|
76
|
+
type TEXT NOT NULL,
|
|
77
|
+
threadId UUID NOT NULL,
|
|
78
|
+
parentId UUID,
|
|
79
|
+
disableFeedback BOOLEAN NOT NULL DEFAULT 0,
|
|
80
|
+
streaming BOOLEAN NOT NULL DEFAULT 0,
|
|
81
|
+
waitForAnswer BOOLEAN DEFAULT 0,
|
|
82
|
+
isError BOOLEAN NOT NULL DEFAULT 0,
|
|
83
|
+
metadata JSONB DEFAULT '{}',
|
|
84
|
+
tags TEXT[],
|
|
85
|
+
input TEXT,
|
|
86
|
+
output TEXT,
|
|
87
|
+
createdAt TEXT,
|
|
88
|
+
start TEXT,
|
|
89
|
+
end TEXT,
|
|
90
|
+
generation JSONB,
|
|
91
|
+
showInput TEXT,
|
|
92
|
+
language TEXT,
|
|
93
|
+
indent INT,
|
|
94
|
+
FOREIGN KEY (threadId) REFERENCES threads (id) ON DELETE CASCADE
|
|
95
|
+
)
|
|
96
|
+
''')
|
|
97
|
+
cursor.execute('''
|
|
98
|
+
CREATE TABLE IF NOT EXISTS elements (
|
|
99
|
+
id UUID PRIMARY KEY,
|
|
100
|
+
threadId UUID,
|
|
101
|
+
type TEXT,
|
|
102
|
+
url TEXT,
|
|
103
|
+
chainlitKey TEXT,
|
|
104
|
+
name TEXT NOT NULL,
|
|
105
|
+
display TEXT,
|
|
106
|
+
objectKey TEXT,
|
|
107
|
+
size TEXT,
|
|
108
|
+
page INT,
|
|
109
|
+
language TEXT,
|
|
110
|
+
forId UUID,
|
|
111
|
+
mime TEXT,
|
|
112
|
+
FOREIGN KEY (threadId) REFERENCES threads (id) ON DELETE CASCADE
|
|
113
|
+
)
|
|
114
|
+
''')
|
|
115
|
+
cursor.execute('''
|
|
116
|
+
CREATE TABLE IF NOT EXISTS feedbacks (
|
|
117
|
+
id UUID PRIMARY KEY,
|
|
118
|
+
forId UUID NOT NULL,
|
|
119
|
+
value INT NOT NULL,
|
|
120
|
+
threadId UUID,
|
|
121
|
+
comment TEXT
|
|
122
|
+
)
|
|
123
|
+
''')
|
|
124
|
+
cursor.execute('''
|
|
125
|
+
CREATE TABLE IF NOT EXISTS settings (
|
|
126
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
127
|
+
key TEXT UNIQUE,
|
|
128
|
+
value TEXT
|
|
129
|
+
)
|
|
130
|
+
''')
|
|
131
|
+
conn.commit()
|
|
132
|
+
conn.close()
|
|
133
|
+
|
|
134
|
+
def save_setting(key: str, value: str):
|
|
135
|
+
"""Saves a setting to the database."""
|
|
136
|
+
conn = sqlite3.connect(DB_PATH)
|
|
137
|
+
cursor = conn.cursor()
|
|
138
|
+
cursor.execute(
|
|
139
|
+
"""
|
|
140
|
+
INSERT OR REPLACE INTO settings (id, key, value)
|
|
141
|
+
VALUES ((SELECT id FROM settings WHERE key = ?), ?, ?)
|
|
142
|
+
""",
|
|
143
|
+
(key, key, value),
|
|
144
|
+
)
|
|
145
|
+
conn.commit()
|
|
146
|
+
conn.close()
|
|
147
|
+
|
|
148
|
+
def load_setting(key: str) -> str:
|
|
149
|
+
"""Loads a setting from the database."""
|
|
150
|
+
conn = sqlite3.connect(DB_PATH)
|
|
151
|
+
cursor = conn.cursor()
|
|
152
|
+
cursor.execute('SELECT value FROM settings WHERE key = ?', (key,))
|
|
153
|
+
result = cursor.fetchone()
|
|
154
|
+
conn.close()
|
|
155
|
+
return result[0] if result else None
|
|
156
|
+
|
|
157
|
+
# Initialize the database
|
|
158
|
+
initialize_db()
|
|
159
|
+
|
|
160
|
+
# Set up SQLAlchemy data layer
|
|
161
|
+
cl_data._data_layer = SQLAlchemyDataLayer(conninfo=f"sqlite+aiosqlite:///{DB_PATH}")
|
|
162
|
+
|
|
163
|
+
client = AsyncOpenAI()
|
|
164
|
+
|
|
165
|
+
# Try to import tools from the root directory
|
|
166
|
+
tools_path = os.path.join(os.getcwd(), 'tools.py')
|
|
167
|
+
logger.info(f"Tools path: {tools_path}")
|
|
168
|
+
|
|
169
|
+
def import_tools_from_file(file_path):
|
|
170
|
+
spec = importlib.util.spec_from_file_location("custom_tools", file_path)
|
|
171
|
+
custom_tools_module = importlib.util.module_from_spec(spec)
|
|
172
|
+
spec.loader.exec_module(custom_tools_module)
|
|
173
|
+
logger.debug(f"Imported tools from {file_path}")
|
|
174
|
+
logger.debug(f"Tools: {custom_tools_module}")
|
|
175
|
+
return custom_tools_module
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
if os.path.exists(tools_path):
|
|
179
|
+
# tools.py exists in the root directory, import from file
|
|
180
|
+
custom_tools_module = import_tools_from_file(tools_path)
|
|
181
|
+
logger.info("Successfully imported custom tools from root tools.py")
|
|
182
|
+
else:
|
|
183
|
+
logger.info("No custom tools.py file found in the root directory")
|
|
184
|
+
custom_tools_module = None
|
|
185
|
+
|
|
186
|
+
if custom_tools_module:
|
|
187
|
+
# Update the tools list with custom tools
|
|
188
|
+
if hasattr(custom_tools_module, 'tools') and isinstance(custom_tools_module.tools, list):
|
|
189
|
+
# Only add tools that have proper function definitions
|
|
190
|
+
for tool in custom_tools_module.tools:
|
|
191
|
+
if isinstance(tool, tuple) and len(tool) == 2:
|
|
192
|
+
tool_def, handler = tool
|
|
193
|
+
if isinstance(tool_def, dict) and "type" in tool_def and tool_def["type"] == "function":
|
|
194
|
+
# Convert class/function to proper tool definition
|
|
195
|
+
if "function" in tool_def:
|
|
196
|
+
func = tool_def["function"]
|
|
197
|
+
if hasattr(func, "__name__"):
|
|
198
|
+
tool_def = {
|
|
199
|
+
"name": func.__name__,
|
|
200
|
+
"description": func.__doc__ or f"Execute {func.__name__}",
|
|
201
|
+
"parameters": {
|
|
202
|
+
"type": "object",
|
|
203
|
+
"properties": {},
|
|
204
|
+
"required": []
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
tools.append((tool_def, handler))
|
|
208
|
+
else:
|
|
209
|
+
# Tool definition is already properly formatted
|
|
210
|
+
tools.append(tool)
|
|
211
|
+
else:
|
|
212
|
+
# Process individual functions/classes
|
|
213
|
+
for name, obj in custom_tools_module.__dict__.items():
|
|
214
|
+
if callable(obj) and not name.startswith("__"):
|
|
215
|
+
tool_def = {
|
|
216
|
+
"name": name,
|
|
217
|
+
"description": obj.__doc__ or f"Execute {name}",
|
|
218
|
+
"parameters": {
|
|
219
|
+
"type": "object",
|
|
220
|
+
"properties": {},
|
|
221
|
+
"required": []
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
tools.append((tool_def, obj))
|
|
225
|
+
|
|
226
|
+
except Exception as e:
|
|
227
|
+
logger.warning(f"Error importing custom tools: {str(e)}. Continuing without custom tools.")
|
|
228
|
+
|
|
229
|
+
@cl.on_chat_start
|
|
230
|
+
async def start():
|
|
231
|
+
initialize_db()
|
|
232
|
+
model_name = os.getenv("OPENAI_MODEL_NAME") or os.getenv("MODEL_NAME", "gpt-5-nano-realtime-preview-2024-12-17")
|
|
233
|
+
cl.user_session.set("model_name", model_name)
|
|
234
|
+
cl.user_session.set("message_history", []) # Initialize message history
|
|
235
|
+
logger.debug(f"Model name: {model_name}")
|
|
236
|
+
# settings = cl.ChatSettings(
|
|
237
|
+
# [
|
|
238
|
+
# TextInput(
|
|
239
|
+
# id="model_name",
|
|
240
|
+
# label="Enter the Model Name",
|
|
241
|
+
# placeholder="e.g., gpt-5-nano-realtime-preview-2024-12-17",
|
|
242
|
+
# initial=model_name
|
|
243
|
+
# )
|
|
244
|
+
# ]
|
|
245
|
+
# )
|
|
246
|
+
# cl.user_session.set("settings", settings)
|
|
247
|
+
# await settings.send()
|
|
248
|
+
await cl.Message(
|
|
249
|
+
content="Welcome to the PraisonAI realtime. Press `P` to talk!"
|
|
250
|
+
).send()
|
|
251
|
+
await setup_openai_realtime()
|
|
252
|
+
|
|
253
|
+
@cl.on_message
|
|
254
|
+
async def on_message(message: cl.Message):
|
|
255
|
+
openai_realtime: RealtimeClient = cl.user_session.get("openai_realtime")
|
|
256
|
+
message_history = cl.user_session.get("message_history", [])
|
|
257
|
+
|
|
258
|
+
if openai_realtime and openai_realtime.is_connected():
|
|
259
|
+
current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
260
|
+
prompt = f"Current time Just for reference: {current_date}\n\n{message.content}"
|
|
261
|
+
|
|
262
|
+
# Add user message to history
|
|
263
|
+
message_history.append({"role": "user", "content": prompt})
|
|
264
|
+
cl.user_session.set("message_history", message_history)
|
|
265
|
+
|
|
266
|
+
await openai_realtime.send_user_message_content([{ "type": 'input_text', "text": message.content }])
|
|
267
|
+
else:
|
|
268
|
+
await cl.Message(content="Please activate voice mode before sending messages!").send()
|
|
269
|
+
|
|
270
|
+
async def setup_openai_realtime():
|
|
271
|
+
"""Instantiate and configure the OpenAI Realtime Client"""
|
|
272
|
+
openai_realtime = RealtimeClient(api_key=os.getenv("OPENAI_API_KEY"))
|
|
273
|
+
cl.user_session.set("track_id", str(uuid4()))
|
|
274
|
+
|
|
275
|
+
async def handle_conversation_updated(event):
|
|
276
|
+
item = event.get("item")
|
|
277
|
+
delta = event.get("delta")
|
|
278
|
+
"""Currently used to stream audio back to the client."""
|
|
279
|
+
if delta:
|
|
280
|
+
if 'audio' in delta:
|
|
281
|
+
audio = delta['audio'] # Int16Array, audio added
|
|
282
|
+
await cl.context.emitter.send_audio_chunk(cl.OutputAudioChunk(mimeType="pcm16", data=audio, track=cl.user_session.get("track_id")))
|
|
283
|
+
if 'transcript' in delta:
|
|
284
|
+
transcript = delta['transcript'] # string, transcript added
|
|
285
|
+
logger.debug(f"Transcript delta: {transcript}")
|
|
286
|
+
if 'text' in delta:
|
|
287
|
+
text = delta['text'] # string, text added
|
|
288
|
+
logger.debug(f"Text delta: {text}")
|
|
289
|
+
if 'arguments' in delta:
|
|
290
|
+
arguments = delta['arguments'] # string, function arguments added
|
|
291
|
+
logger.debug(f"Function arguments delta: {arguments}")
|
|
292
|
+
|
|
293
|
+
async def handle_item_completed(event):
|
|
294
|
+
"""Used to populate the chat context with transcription once an item is completed."""
|
|
295
|
+
try:
|
|
296
|
+
item = event.get("item")
|
|
297
|
+
logger.debug(f"Item completed: {json.dumps(item, indent=2, default=str)}")
|
|
298
|
+
await openai_realtime._send_chainlit_message(item)
|
|
299
|
+
|
|
300
|
+
# Add assistant message to history
|
|
301
|
+
message_history = cl.user_session.get("message_history", [])
|
|
302
|
+
content = item.get("formatted", {}).get("text", "") or item.get("formatted", {}).get("transcript", "")
|
|
303
|
+
if content:
|
|
304
|
+
message_history.append({"role": "assistant", "content": content})
|
|
305
|
+
cl.user_session.set("message_history", message_history)
|
|
306
|
+
except Exception as e:
|
|
307
|
+
error_message = f"Error in handle_item_completed: {str(e)}"
|
|
308
|
+
logger.error(error_message)
|
|
309
|
+
debug_item = json.dumps(item, indent=2, default=str)
|
|
310
|
+
logger.error(f"Item causing error: {debug_item}")
|
|
311
|
+
|
|
312
|
+
async def handle_conversation_interrupt(event):
|
|
313
|
+
"""Used to cancel the client previous audio playback."""
|
|
314
|
+
cl.user_session.set("track_id", str(uuid4()))
|
|
315
|
+
await cl.context.emitter.send_audio_interrupt()
|
|
316
|
+
|
|
317
|
+
async def handle_error(event):
|
|
318
|
+
logger.error(event)
|
|
319
|
+
await cl.Message(content=f"Error: {event}", author="System").send()
|
|
320
|
+
|
|
321
|
+
# Register event handlers
|
|
322
|
+
openai_realtime.on('conversation.updated', handle_conversation_updated)
|
|
323
|
+
openai_realtime.on('conversation.item.completed', handle_item_completed)
|
|
324
|
+
openai_realtime.on('conversation.interrupted', handle_conversation_interrupt)
|
|
325
|
+
openai_realtime.on('error', handle_error)
|
|
326
|
+
|
|
327
|
+
cl.user_session.set("openai_realtime", openai_realtime)
|
|
328
|
+
|
|
329
|
+
# Filter out invalid tools and add valid ones
|
|
330
|
+
valid_tools = []
|
|
331
|
+
for tool_def, tool_handler in tools:
|
|
332
|
+
try:
|
|
333
|
+
if isinstance(tool_def, dict) and "name" in tool_def:
|
|
334
|
+
valid_tools.append((tool_def, tool_handler))
|
|
335
|
+
else:
|
|
336
|
+
logger.warning(f"Skipping invalid tool definition: {tool_def}")
|
|
337
|
+
except Exception as e:
|
|
338
|
+
logger.warning(f"Error processing tool: {e}")
|
|
339
|
+
|
|
340
|
+
if valid_tools:
|
|
341
|
+
coros = [openai_realtime.add_tool(tool_def, tool_handler) for tool_def, tool_handler in valid_tools]
|
|
342
|
+
await asyncio.gather(*coros)
|
|
343
|
+
else:
|
|
344
|
+
logger.warning("No valid tools found to add")
|
|
345
|
+
|
|
346
|
+
@cl.on_settings_update
|
|
347
|
+
async def setup_agent(settings):
|
|
348
|
+
logger.debug(settings)
|
|
349
|
+
cl.user_session.set("settings", settings)
|
|
350
|
+
model_name = settings["model_name"]
|
|
351
|
+
cl.user_session.set("model_name", model_name)
|
|
352
|
+
|
|
353
|
+
# Save in settings table
|
|
354
|
+
save_setting("model_name", model_name)
|
|
355
|
+
|
|
356
|
+
# Save in thread metadata
|
|
357
|
+
thread_id = cl.user_session.get("thread_id")
|
|
358
|
+
if thread_id:
|
|
359
|
+
thread = await cl_data._data_layer.get_thread(thread_id)
|
|
360
|
+
if thread:
|
|
361
|
+
metadata = thread.get("metadata", {})
|
|
362
|
+
if isinstance(metadata, str):
|
|
363
|
+
try:
|
|
364
|
+
metadata = json.loads(metadata)
|
|
365
|
+
except json.JSONDecodeError:
|
|
366
|
+
metadata = {}
|
|
367
|
+
|
|
368
|
+
metadata["model_name"] = model_name
|
|
369
|
+
|
|
370
|
+
# Always store metadata as a dictionary
|
|
371
|
+
await cl_data._data_layer.update_thread(thread_id, metadata=metadata)
|
|
372
|
+
|
|
373
|
+
# Update the user session with the new metadata
|
|
374
|
+
cl.user_session.set("metadata", metadata)
|
|
375
|
+
|
|
376
|
+
@cl.on_audio_start
|
|
377
|
+
async def on_audio_start():
|
|
378
|
+
try:
|
|
379
|
+
openai_realtime: RealtimeClient = cl.user_session.get("openai_realtime")
|
|
380
|
+
if not openai_realtime:
|
|
381
|
+
await setup_openai_realtime()
|
|
382
|
+
openai_realtime = cl.user_session.get("openai_realtime")
|
|
383
|
+
|
|
384
|
+
if not openai_realtime.is_connected():
|
|
385
|
+
model_name = cl.user_session.get("model_name") or os.getenv("OPENAI_MODEL_NAME") or os.getenv("MODEL_NAME", "gpt-5-nano-realtime-preview-2024-12-17")
|
|
386
|
+
await openai_realtime.connect(model_name)
|
|
387
|
+
|
|
388
|
+
logger.info("Connected to OpenAI realtime")
|
|
389
|
+
return True
|
|
390
|
+
except Exception as e:
|
|
391
|
+
error_msg = f"Failed to connect to OpenAI realtime: {str(e)}"
|
|
392
|
+
logger.error(error_msg)
|
|
393
|
+
await cl.ErrorMessage(content=error_msg).send()
|
|
394
|
+
return False
|
|
395
|
+
|
|
396
|
+
@cl.on_audio_chunk
|
|
397
|
+
async def on_audio_chunk(chunk: cl.InputAudioChunk):
|
|
398
|
+
openai_realtime: RealtimeClient = cl.user_session.get("openai_realtime")
|
|
399
|
+
|
|
400
|
+
if not openai_realtime:
|
|
401
|
+
logger.debug("No realtime client available")
|
|
402
|
+
return
|
|
403
|
+
|
|
404
|
+
if openai_realtime.is_connected():
|
|
405
|
+
try:
|
|
406
|
+
success = await openai_realtime.append_input_audio(chunk.data)
|
|
407
|
+
if not success:
|
|
408
|
+
logger.debug("Failed to append audio data - connection may be lost")
|
|
409
|
+
except Exception as e:
|
|
410
|
+
logger.debug(f"Error processing audio chunk: {e}")
|
|
411
|
+
# Optionally try to reconnect here if needed
|
|
412
|
+
else:
|
|
413
|
+
logger.debug("RealtimeClient is not connected - audio chunk ignored")
|
|
414
|
+
|
|
415
|
+
@cl.on_audio_end
|
|
416
|
+
@cl.on_chat_end
|
|
417
|
+
@cl.on_stop
|
|
418
|
+
async def on_end():
|
|
419
|
+
openai_realtime: RealtimeClient = cl.user_session.get("openai_realtime")
|
|
420
|
+
if openai_realtime and openai_realtime.is_connected():
|
|
421
|
+
await openai_realtime.disconnect()
|
|
422
|
+
|
|
423
|
+
@cl.password_auth_callback
|
|
424
|
+
def auth_callback(username: str, password: str):
|
|
425
|
+
# You can customize this function to use your own authentication logic
|
|
426
|
+
expected_username = os.getenv("CHAINLIT_USERNAME", "admin")
|
|
427
|
+
expected_password = os.getenv("CHAINLIT_PASSWORD", "admin")
|
|
428
|
+
if (username, password) == (expected_username, expected_password):
|
|
429
|
+
return cl.User(
|
|
430
|
+
identifier=username, metadata={"role": "ADMIN", "provider": "credentials"}
|
|
431
|
+
)
|
|
432
|
+
else:
|
|
433
|
+
return None
|
|
434
|
+
|
|
435
|
+
@cl.on_chat_resume
|
|
436
|
+
async def on_chat_resume(thread: ThreadDict):
|
|
437
|
+
logger.info(f"Resuming chat: {thread['id']}")
|
|
438
|
+
model_name = os.getenv("OPENAI_MODEL_NAME") or os.getenv("MODEL_NAME") or "gpt-5-nano-realtime-preview-2024-12-17"
|
|
439
|
+
logger.debug(f"Model name: {model_name}")
|
|
440
|
+
settings = cl.ChatSettings(
|
|
441
|
+
[
|
|
442
|
+
TextInput(
|
|
443
|
+
id="model_name",
|
|
444
|
+
label="Enter the Model Name",
|
|
445
|
+
placeholder="e.g., gpt-5-nano-realtime-preview-2024-12-17",
|
|
446
|
+
initial=model_name
|
|
447
|
+
)
|
|
448
|
+
]
|
|
449
|
+
)
|
|
450
|
+
await settings.send()
|
|
451
|
+
thread_id = thread["id"]
|
|
452
|
+
cl.user_session.set("thread_id", thread["id"])
|
|
453
|
+
|
|
454
|
+
# Ensure metadata is a dictionary
|
|
455
|
+
metadata = thread.get("metadata", {})
|
|
456
|
+
if isinstance(metadata, str):
|
|
457
|
+
try:
|
|
458
|
+
metadata = json.loads(metadata)
|
|
459
|
+
except json.JSONDecodeError:
|
|
460
|
+
metadata = {}
|
|
461
|
+
|
|
462
|
+
cl.user_session.set("metadata", metadata)
|
|
463
|
+
|
|
464
|
+
message_history = []
|
|
465
|
+
steps = thread["steps"]
|
|
466
|
+
|
|
467
|
+
for message in steps:
|
|
468
|
+
msg_type = message.get("type")
|
|
469
|
+
if msg_type == "user_message":
|
|
470
|
+
message_history.append({"role": "user", "content": message.get("output", "")})
|
|
471
|
+
elif msg_type == "assistant_message":
|
|
472
|
+
message_history.append({"role": "assistant", "content": message.get("output", "")})
|
|
473
|
+
elif msg_type == "run":
|
|
474
|
+
# Handle 'run' type messages
|
|
475
|
+
if message.get("isError"):
|
|
476
|
+
message_history.append({"role": "system", "content": f"Error: {message.get('output', '')}"})
|
|
477
|
+
else:
|
|
478
|
+
# You might want to handle non-error 'run' messages differently
|
|
479
|
+
pass
|
|
480
|
+
else:
|
|
481
|
+
logger.warning(f"Message without recognized type: {message}")
|
|
482
|
+
|
|
483
|
+
cl.user_session.set("message_history", message_history)
|
|
484
|
+
|
|
485
|
+
# Reconnect to OpenAI realtime
|
|
486
|
+
await setup_openai_realtime()
|
|
487
|
+
|
|
488
|
+
|