mirror of
https://github.com/MervinPraison/PraisonAI.git
synced 2026-11-08 08:11:07 -10:00
Adding OpenAI Realtime API and multiple tools
This commit is contained in:
1 parent
1efea38d88
commit
9b4b987dfa
3 files changed
+318
-136
No files matched your search
+1
-7
@@ -426,16 +426,10 @@ class PraisonAI:
|
||||
def create_realtime_interface(self):
|
||||
"""
|
||||
Create a Chainlit interface for the realtime voice interaction application.
|
||||
|
||||
This function sets up a Chainlit application for real-time voice interaction with AI.
|
||||
It uses the OpenAI Realtime Client for processing audio input and generating responses.
|
||||
|
||||
Returns:
|
||||
None: This function does not return any value. It starts the Chainlit application.
|
||||
"""
|
||||
if CHAINLIT_AVAILABLE:
|
||||
import praisonai
|
||||
os.environ["CHAINLIT_PORT"] = "8088"
|
||||
os.environ["CHAINLIT_PORT"] = "8088" # Ensure this port is not in use by another service
|
||||
root_path = os.path.join(os.path.expanduser("~"), ".praison")
|
||||
os.environ["CHAINLIT_APP_ROOT"] = root_path
|
||||
public_folder = os.path.join(os.path.dirname(praisonai.__file__), 'public')
|
||||
|
||||
+303
-109
@@ -1,92 +1,156 @@
|
||||
import os
|
||||
import asyncio
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
import chainlit as cl
|
||||
from uuid import uuid4
|
||||
from chainlit.logger import logger
|
||||
from chainlit.input_widget import TextInput
|
||||
from chainlit.types import ThreadDict
|
||||
|
||||
from realtimeclient import RealtimeClient
|
||||
from realtimeclient.tools import tools
|
||||
from sql_alchemy import SQLAlchemyDataLayer
|
||||
import chainlit.data as cl_data
|
||||
from literalai.helper import utc_now
|
||||
import json
|
||||
from dotenv import load_dotenv
|
||||
from chainlit.input_widget import TextInput
|
||||
import logging
|
||||
from PIL import Image
|
||||
import io
|
||||
import base64
|
||||
|
||||
load_dotenv()
|
||||
# Set up CHAINLIT_AUTH_SECRET
|
||||
CHAINLIT_AUTH_SECRET = os.getenv("CHAINLIT_AUTH_SECRET")
|
||||
|
||||
# Set up logging
|
||||
logger = logging.getLogger(__name__)
|
||||
log_level = os.getenv("LOGLEVEL", "DEBUG").upper()
|
||||
logger.setLevel(log_level)
|
||||
if not CHAINLIT_AUTH_SECRET:
|
||||
os.environ["CHAINLIT_AUTH_SECRET"] = "p8BPhQChpg@J>jBz$wGxqLX2V>yTVgP*7Ky9H$aV:axW~ANNX-7_T:o@lnyCBu^U"
|
||||
CHAINLIT_AUTH_SECRET = os.getenv("CHAINLIT_AUTH_SECRET")
|
||||
|
||||
# Database path
|
||||
DB_PATH = os.path.expanduser("~/.praison/database.sqlite")
|
||||
|
||||
def initialize_db():
|
||||
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY,
|
||||
identifier TEXT NOT NULL UNIQUE,
|
||||
metadata JSONB NOT NULL,
|
||||
createdAt TEXT
|
||||
)
|
||||
''')
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS threads (
|
||||
id UUID PRIMARY KEY,
|
||||
createdAt TEXT,
|
||||
name TEXT,
|
||||
userId UUID,
|
||||
userIdentifier TEXT,
|
||||
tags TEXT[],
|
||||
metadata JSONB NOT NULL DEFAULT '{}',
|
||||
FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
|
||||
)
|
||||
''')
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS steps (
|
||||
id UUID PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
threadId UUID NOT NULL,
|
||||
parentId UUID,
|
||||
disableFeedback BOOLEAN NOT NULL DEFAULT 0,
|
||||
streaming BOOLEAN NOT NULL DEFAULT 0,
|
||||
waitForAnswer BOOLEAN DEFAULT 0,
|
||||
isError BOOLEAN NOT NULL DEFAULT 0,
|
||||
metadata JSONB DEFAULT '{}',
|
||||
tags TEXT[],
|
||||
input TEXT,
|
||||
output TEXT,
|
||||
createdAt TEXT,
|
||||
start TEXT,
|
||||
end TEXT,
|
||||
generation JSONB,
|
||||
showInput TEXT,
|
||||
language TEXT,
|
||||
indent INT,
|
||||
FOREIGN KEY (threadId) REFERENCES threads (id) ON DELETE CASCADE
|
||||
)
|
||||
''')
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS elements (
|
||||
id UUID PRIMARY KEY,
|
||||
threadId UUID,
|
||||
type TEXT,
|
||||
url TEXT,
|
||||
chainlitKey TEXT,
|
||||
name TEXT NOT NULL,
|
||||
display TEXT,
|
||||
objectKey TEXT,
|
||||
size TEXT,
|
||||
page INT,
|
||||
language TEXT,
|
||||
forId UUID,
|
||||
mime TEXT,
|
||||
FOREIGN KEY (threadId) REFERENCES threads (id) ON DELETE CASCADE
|
||||
)
|
||||
''')
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS feedbacks (
|
||||
id UUID PRIMARY KEY,
|
||||
forId UUID NOT NULL,
|
||||
value INT NOT NULL,
|
||||
threadId UUID,
|
||||
comment TEXT
|
||||
)
|
||||
''')
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
key TEXT UNIQUE,
|
||||
value TEXT
|
||||
)
|
||||
''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def save_setting(key: str, value: str):
|
||||
"""Saves a setting to the database."""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT OR REPLACE INTO settings (id, key, value)
|
||||
VALUES ((SELECT id FROM settings WHERE key = ?), ?, ?)
|
||||
""",
|
||||
(key, key, value),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def load_setting(key: str) -> str:
|
||||
"""Loads a setting from the database."""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('SELECT value FROM settings WHERE key = ?', (key,))
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
return result[0] if result else None
|
||||
|
||||
# Initialize the database
|
||||
initialize_db()
|
||||
|
||||
# Set up SQLAlchemy data layer
|
||||
cl_data._data_layer = SQLAlchemyDataLayer(conninfo=f"sqlite+aiosqlite:///{DB_PATH}")
|
||||
|
||||
client = AsyncOpenAI()
|
||||
|
||||
async def setup_openai_realtime():
|
||||
"""Instantiate and configure the OpenAI Realtime Client"""
|
||||
openai_realtime = RealtimeClient(api_key=os.getenv("OPENAI_API_KEY"))
|
||||
cl.user_session.set("track_id", str(uuid4()))
|
||||
|
||||
async def handle_conversation_updated(event):
|
||||
item = event.get("item")
|
||||
delta = event.get("delta")
|
||||
"""Currently used to stream audio back to the client."""
|
||||
if delta:
|
||||
# Debug logging
|
||||
# debug_delta = {k: f"<{type(v).__name__} of length {len(v)}>" if isinstance(v, (bytes, bytearray)) else v for k, v in delta.items()}
|
||||
# logger.debug(f"Delta received: {json.dumps(debug_delta, indent=2)}")
|
||||
|
||||
# Only one of the following will be populated for any given event
|
||||
if 'audio' in delta:
|
||||
audio = delta['audio'] # Int16Array, audio added
|
||||
await cl.context.emitter.send_audio_chunk(cl.OutputAudioChunk(mimeType="pcm16", data=audio, track=cl.user_session.get("track_id")))
|
||||
if 'transcript' in delta:
|
||||
transcript = delta['transcript'] # string, transcript added
|
||||
# logger.debug(f"Transcript delta: {transcript}")
|
||||
if 'text' in delta:
|
||||
text = delta['text'] # string, text added
|
||||
# logger.debug(f"Text delta: {text}")
|
||||
if 'arguments' in delta:
|
||||
arguments = delta['arguments'] # string, function arguments added
|
||||
# logger.debug(f"Function arguments delta: {arguments}")
|
||||
|
||||
async def handle_item_completed(event):
|
||||
"""Used to populate the chat context with transcription once an item is completed."""
|
||||
try:
|
||||
item = event.get("item")
|
||||
# logger.debug(f"Item completed: {json.dumps(item, indent=2, default=str)}")
|
||||
openai_realtime = cl.user_session.get("openai_realtime")
|
||||
await openai_realtime._send_chainlit_message(item)
|
||||
except Exception as e:
|
||||
error_message = f"Error in handle_item_completed: {str(e)}"
|
||||
logger.error(error_message)
|
||||
|
||||
debug_item = json.dumps(item, indent=2, default=str)
|
||||
logger.error(f"Item causing error: {debug_item}")
|
||||
|
||||
async def handle_conversation_interrupt(event):
|
||||
"""Used to cancel the client previous audio playback."""
|
||||
cl.user_session.set("track_id", str(uuid4()))
|
||||
await cl.context.emitter.send_audio_interrupt()
|
||||
|
||||
async def handle_error(event):
|
||||
logger.error(event)
|
||||
await cl.Message(content=f"Error: {event}", author="System").send()
|
||||
|
||||
openai_realtime.on('conversation.updated', handle_conversation_updated)
|
||||
openai_realtime.on('conversation.item.completed', handle_item_completed)
|
||||
openai_realtime.on('conversation.interrupted', handle_conversation_interrupt)
|
||||
openai_realtime.on('error', handle_error)
|
||||
|
||||
cl.user_session.set("openai_realtime", openai_realtime)
|
||||
coros = [openai_realtime.add_tool(tool_def, tool_handler) for tool_def, tool_handler in tools]
|
||||
await asyncio.gather(*coros)
|
||||
|
||||
@cl.on_chat_start
|
||||
async def start():
|
||||
model_name = os.getenv("MODEL_NAME", "gpt-4o-mini")
|
||||
initialize_db()
|
||||
model_name = load_setting("model_name") or os.getenv("MODEL_NAME", "gpt-4o-mini")
|
||||
cl.user_session.set("model_name", model_name)
|
||||
cl.user_session.set("message_history", []) # Initialize message history
|
||||
logger.debug(f"Model name: {model_name}")
|
||||
settings = cl.ChatSettings(
|
||||
[
|
||||
TextInput(
|
||||
@@ -99,57 +163,122 @@ async def start():
|
||||
)
|
||||
cl.user_session.set("settings", settings)
|
||||
await settings.send()
|
||||
|
||||
await cl.Message(
|
||||
content="Welcome to the Chainlit x OpenAI realtime example. Press `P` to talk!"
|
||||
).send()
|
||||
await setup_openai_realtime()
|
||||
|
||||
@cl.on_message
|
||||
async def on_message(message: cl.Message):
|
||||
openai_realtime: RealtimeClient = cl.user_session.get("openai_realtime")
|
||||
message_history = cl.user_session.get("message_history", [])
|
||||
|
||||
if openai_realtime and openai_realtime.is_connected():
|
||||
current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
prompt = f"Current time Just for reference: {current_date}\n\n{message.content}"
|
||||
|
||||
# Add user message to history
|
||||
message_history.append({"role": "user", "content": prompt})
|
||||
cl.user_session.set("message_history", message_history)
|
||||
|
||||
await openai_realtime.send_user_message_content([{ "type": 'input_text', "text": message.content }])
|
||||
else:
|
||||
await cl.Message(content="Please activate voice mode before sending messages!").send()
|
||||
|
||||
async def setup_openai_realtime():
|
||||
"""Instantiate and configure the OpenAI Realtime Client"""
|
||||
openai_realtime = RealtimeClient(api_key=os.getenv("OPENAI_API_KEY"))
|
||||
cl.user_session.set("track_id", str(uuid4()))
|
||||
|
||||
async def handle_conversation_updated(event):
|
||||
item = event.get("item")
|
||||
delta = event.get("delta")
|
||||
"""Currently used to stream audio back to the client."""
|
||||
if delta:
|
||||
if 'audio' in delta:
|
||||
audio = delta['audio'] # Int16Array, audio added
|
||||
await cl.context.emitter.send_audio_chunk(cl.OutputAudioChunk(mimeType="pcm16", data=audio, track=cl.user_session.get("track_id")))
|
||||
if 'transcript' in delta:
|
||||
transcript = delta['transcript'] # string, transcript added
|
||||
logger.debug(f"Transcript delta: {transcript}")
|
||||
if 'text' in delta:
|
||||
text = delta['text'] # string, text added
|
||||
logger.debug(f"Text delta: {text}")
|
||||
if 'arguments' in delta:
|
||||
arguments = delta['arguments'] # string, function arguments added
|
||||
logger.debug(f"Function arguments delta: {arguments}")
|
||||
|
||||
async def handle_item_completed(event):
|
||||
"""Used to populate the chat context with transcription once an item is completed."""
|
||||
try:
|
||||
item = event.get("item")
|
||||
logger.debug(f"Item completed: {json.dumps(item, indent=2, default=str)}")
|
||||
await openai_realtime._send_chainlit_message(item)
|
||||
|
||||
# Add assistant message to history
|
||||
message_history = cl.user_session.get("message_history", [])
|
||||
content = item.get("formatted", {}).get("text", "") or item.get("formatted", {}).get("transcript", "")
|
||||
if content:
|
||||
message_history.append({"role": "assistant", "content": content})
|
||||
cl.user_session.set("message_history", message_history)
|
||||
except Exception as e:
|
||||
error_message = f"Error in handle_item_completed: {str(e)}"
|
||||
logger.error(error_message)
|
||||
debug_item = json.dumps(item, indent=2, default=str)
|
||||
logger.error(f"Item causing error: {debug_item}")
|
||||
|
||||
async def handle_conversation_interrupt(event):
|
||||
"""Used to cancel the client previous audio playback."""
|
||||
cl.user_session.set("track_id", str(uuid4()))
|
||||
await cl.context.emitter.send_audio_interrupt()
|
||||
|
||||
async def handle_error(event):
|
||||
logger.error(event)
|
||||
await cl.Message(content=f"Error: {event}", author="System").send()
|
||||
|
||||
openai_realtime.on('conversation.updated', handle_conversation_updated)
|
||||
openai_realtime.on('conversation.item.completed', handle_item_completed)
|
||||
openai_realtime.on('conversation.interrupted', handle_conversation_interrupt)
|
||||
openai_realtime.on('error', handle_error)
|
||||
|
||||
cl.user_session.set("openai_realtime", openai_realtime)
|
||||
coros = [openai_realtime.add_tool(tool_def, tool_handler) for tool_def, tool_handler in tools]
|
||||
await asyncio.gather(*coros)
|
||||
|
||||
@cl.on_settings_update
|
||||
async def setup_agent(settings):
|
||||
logger.debug(settings)
|
||||
cl.user_session.set("settings", settings)
|
||||
model_name = settings["model_name"]
|
||||
cl.user_session.set("model_name", model_name)
|
||||
|
||||
@cl.on_message
|
||||
async def on_message(message: cl.Message):
|
||||
openai_realtime: RealtimeClient = cl.user_session.get("openai_realtime")
|
||||
if openai_realtime and openai_realtime.is_connected():
|
||||
# Check if an image was uploaded with this message
|
||||
image = None
|
||||
if message.elements and isinstance(message.elements[0], cl.Image):
|
||||
image_element = message.elements[0]
|
||||
try:
|
||||
# Open the image and keep it in memory
|
||||
image = Image.open(image_element.path)
|
||||
image.load() # This ensures the file is fully loaded into memory
|
||||
cl.user_session.set("image", image)
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing image: {str(e)}")
|
||||
await cl.Message(content="There was an error processing the uploaded image. Please try again.").send()
|
||||
return
|
||||
|
||||
# Prepare user message
|
||||
user_message = [{ "type": 'input_text', "text": message.content }]
|
||||
|
||||
# If an image is uploaded, include it in the message
|
||||
if image:
|
||||
buffered = io.BytesIO()
|
||||
image.save(buffered, format="PNG")
|
||||
img_str = base64.b64encode(buffered.getvalue()).decode()
|
||||
user_message.append({ "type": 'image', "image_url": f"data:image/png;base64,{img_str}" })
|
||||
|
||||
await openai_realtime.send_user_message_content(user_message)
|
||||
else:
|
||||
await cl.Message(content="Please activate voice mode before sending messages!").send()
|
||||
|
||||
# Save in settings table
|
||||
save_setting("model_name", model_name)
|
||||
|
||||
# Save in thread metadata
|
||||
thread_id = cl.user_session.get("thread_id")
|
||||
if thread_id:
|
||||
thread = await cl_data._data_layer.get_thread(thread_id)
|
||||
if thread:
|
||||
metadata = thread.get("metadata", {})
|
||||
if isinstance(metadata, str):
|
||||
try:
|
||||
metadata = json.loads(metadata)
|
||||
except json.JSONDecodeError:
|
||||
metadata = {}
|
||||
|
||||
metadata["model_name"] = model_name
|
||||
|
||||
# Always store metadata as a dictionary
|
||||
await cl_data._data_layer.update_thread(thread_id, metadata=metadata)
|
||||
|
||||
# Update the user session with the new metadata
|
||||
cl.user_session.set("metadata", metadata)
|
||||
|
||||
@cl.on_audio_start
|
||||
async def on_audio_start():
|
||||
try:
|
||||
openai_realtime: RealtimeClient = cl.user_session.get("openai_realtime")
|
||||
# TODO: might want to recreate items to restore context
|
||||
# openai_realtime.create_conversation_item(item)
|
||||
await openai_realtime.connect()
|
||||
logger.info("Connected to OpenAI realtime")
|
||||
return True
|
||||
@@ -171,4 +300,69 @@ async def on_audio_chunk(chunk: cl.InputAudioChunk):
|
||||
async def on_end():
|
||||
openai_realtime: RealtimeClient = cl.user_session.get("openai_realtime")
|
||||
if openai_realtime and openai_realtime.is_connected():
|
||||
await openai_realtime.disconnect()
|
||||
await openai_realtime.disconnect()
|
||||
|
||||
@cl.password_auth_callback
|
||||
def auth_callback(username: str, password: str):
|
||||
# You can customize this function to use your own authentication logic
|
||||
expected_username = os.getenv("CHAINLIT_USERNAME", "admin")
|
||||
expected_password = os.getenv("CHAINLIT_PASSWORD", "admin")
|
||||
if (username, password) == (expected_username, expected_password):
|
||||
return cl.User(
|
||||
identifier=username, metadata={"role": "ADMIN", "provider": "credentials"}
|
||||
)
|
||||
else:
|
||||
return None
|
||||
|
||||
@cl.on_chat_resume
|
||||
async def on_chat_resume(thread: ThreadDict):
|
||||
logger.info(f"Resuming chat: {thread['id']}")
|
||||
model_name = load_setting("model_name") or os.getenv("MODEL_NAME") or "gpt-4o-mini"
|
||||
logger.debug(f"Model name: {model_name}")
|
||||
settings = cl.ChatSettings(
|
||||
[
|
||||
TextInput(
|
||||
id="model_name",
|
||||
label="Enter the Model Name",
|
||||
placeholder="e.g., gpt-4o-mini",
|
||||
initial=model_name
|
||||
)
|
||||
]
|
||||
)
|
||||
await settings.send()
|
||||
thread_id = thread["id"]
|
||||
cl.user_session.set("thread_id", thread["id"])
|
||||
|
||||
# Ensure metadata is a dictionary
|
||||
metadata = thread.get("metadata", {})
|
||||
if isinstance(metadata, str):
|
||||
try:
|
||||
metadata = json.loads(metadata)
|
||||
except json.JSONDecodeError:
|
||||
metadata = {}
|
||||
|
||||
cl.user_session.set("metadata", metadata)
|
||||
|
||||
message_history = []
|
||||
steps = thread["steps"]
|
||||
|
||||
for message in steps:
|
||||
msg_type = message.get("type")
|
||||
if msg_type == "user_message":
|
||||
message_history.append({"role": "user", "content": message.get("output", "")})
|
||||
elif msg_type == "assistant_message":
|
||||
message_history.append({"role": "assistant", "content": message.get("output", "")})
|
||||
elif msg_type == "run":
|
||||
# Handle 'run' type messages
|
||||
if message.get("isError"):
|
||||
message_history.append({"role": "system", "content": f"Error: {message.get('output', '')}"})
|
||||
else:
|
||||
# You might want to handle non-error 'run' messages differently
|
||||
pass
|
||||
else:
|
||||
logger.warning(f"Message without recognized type: {message}")
|
||||
|
||||
cl.user_session.set("message_history", message_history)
|
||||
|
||||
# Reconnect to OpenAI realtime
|
||||
await setup_openai_realtime()
|
||||
@@ -451,24 +451,13 @@ class RealtimeClient(RealtimeEventHandler):
|
||||
self.dispatch("conversation.item.appended", {"item": item})
|
||||
if item and item["status"] == "completed":
|
||||
self.dispatch("conversation.item.completed", {"item": item})
|
||||
|
||||
# Send Chainlit message
|
||||
asyncio.create_task(self._send_chainlit_message(item))
|
||||
|
||||
async def _on_output_item_done(self, event):
|
||||
item, delta = self._process_event(event)
|
||||
if item:
|
||||
if item.get("status") == "completed":
|
||||
self.dispatch("conversation.item.completed", {"item": item})
|
||||
try:
|
||||
await self._send_chainlit_message(item)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in _on_output_item_done when sending message: {str(e)}")
|
||||
logger.error(f"Item causing error: {json.dumps(item, indent=2)}")
|
||||
if item.get("formatted", {}).get("tool"):
|
||||
await self._call_tool(item["formatted"]["tool"])
|
||||
else:
|
||||
logger.warning("_on_output_item_done received an empty item")
|
||||
if item and item["status"] == "completed":
|
||||
self.dispatch("conversation.item.completed", {"item": item})
|
||||
if item and item.get("formatted", {}).get("tool"):
|
||||
await self._call_tool(item["formatted"]["tool"])
|
||||
|
||||
async def _call_tool(self, tool):
|
||||
try:
|
||||
@@ -485,12 +474,13 @@ class RealtimeClient(RealtimeEventHandler):
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Tool call error: {json.dumps({'error': str(e)})}")
|
||||
error_message = json.dumps({"error": str(e)})
|
||||
logger.error(f"Tool call error: {error_message}")
|
||||
await self.realtime.send("conversation.item.create", {
|
||||
"item": {
|
||||
"type": "function_call_output",
|
||||
"call_id": tool["call_id"],
|
||||
"output": json.dumps({"error": str(e)}),
|
||||
"output": error_message,
|
||||
}
|
||||
})
|
||||
await self.create_response()
|
||||
@@ -644,13 +634,17 @@ class RealtimeClient(RealtimeEventHandler):
|
||||
elif "role" in item:
|
||||
if item["role"] == "user":
|
||||
content = item.get("formatted", {}).get("text", "") or item.get("formatted", {}).get("transcript", "")
|
||||
await cl.Message(content=content, author="User").send()
|
||||
if content:
|
||||
await cl.Message(content=content, author="User").send()
|
||||
elif item["role"] == "assistant":
|
||||
content = item.get("formatted", {}).get("text", "") or item.get("formatted", {}).get("transcript", "")
|
||||
await cl.Message(content=content, author="AI").send()
|
||||
if content:
|
||||
await cl.Message(content=content, author="AI").send()
|
||||
else:
|
||||
logger.warning(f"Unhandled role: {item['role']}")
|
||||
else:
|
||||
# Handle items without a 'role' or 'type'
|
||||
logger.debug(f"Unhandled item type:\n{json.dumps(item, indent=2)}")
|
||||
|
||||
# Additional debug logging
|
||||
logger.debug(f"Processed Chainlit message for item: {item.get('id', 'unknown')}")
|
||||
logger.debug(f"Processed Chainlit message for item: {item.get('id', 'unknown')}")
|
||||
Reference in new issue
Block a user