Spaces:
Sleeping
Sleeping
Add comprehensive logging to the application
Browse files- app.py +35 -16
- logger_config.py +38 -0
- prompt_manager.py +10 -0
app.py
CHANGED
@@ -8,8 +8,10 @@ from chainlit.prompt import Prompt, PromptMessage # importing prompt tools
|
|
8 |
from chainlit.playground.providers import ChatOpenAI # importing ChatOpenAI tools
|
9 |
from dotenv import load_dotenv
|
10 |
from prompt_manager import PromptManager
|
|
|
11 |
|
12 |
load_dotenv()
|
|
|
13 |
|
14 |
# Initialize prompt manager
|
15 |
prompt_manager = PromptManager()
|
@@ -128,6 +130,7 @@ USER_TEMPLATES = {
|
|
128 |
|
129 |
@cl.on_chat_start
|
130 |
async def start_chat():
|
|
|
131 |
# Create aspect selection buttons with descriptions
|
132 |
aspects = prompt_manager.get_aspect_names()
|
133 |
actions = []
|
@@ -147,6 +150,7 @@ async def start_chat():
|
|
147 |
content="Welcome! Please select an aspect for our conversation. Hover over each option to see examples and descriptions:",
|
148 |
actions=actions
|
149 |
).send()
|
|
|
150 |
|
151 |
@cl.action_callback("Concept Simplification")
|
152 |
@cl.action_callback("Summarization")
|
@@ -157,16 +161,20 @@ async def start_chat():
|
|
157 |
async def on_action(action):
|
158 |
# Store the selected aspect in the user session
|
159 |
cl.user_session.set("selected_aspect", action.value)
|
|
|
160 |
|
161 |
# Send confirmation message with examples
|
162 |
await cl.Message(
|
163 |
content=prompt_manager.get_confirmation_message(action.value)
|
164 |
).send()
|
|
|
165 |
|
166 |
@cl.on_message
|
167 |
async def main(message: cl.Message):
|
168 |
# Get the selected aspect from the session
|
169 |
selected_aspect = cl.user_session.get("selected_aspect")
|
|
|
|
|
170 |
|
171 |
settings = {
|
172 |
"model": "gpt-4-turbo-preview", # Upgraded to GPT-4 Turbo
|
@@ -176,11 +184,13 @@ async def main(message: cl.Message):
|
|
176 |
"frequency_penalty": 0.3, # Added to reduce repetition
|
177 |
"presence_penalty": 0.3, # Added to encourage diverse topics
|
178 |
}
|
|
|
179 |
|
180 |
client = AsyncOpenAI()
|
181 |
|
182 |
# Get the appropriate templates for the selected aspect
|
183 |
system_template, user_template = prompt_manager.get_templates(selected_aspect)
|
|
|
184 |
|
185 |
prompt = Prompt(
|
186 |
provider=ChatOpenAI.id,
|
@@ -199,21 +209,30 @@ async def main(message: cl.Message):
|
|
199 |
inputs={"input": message.content},
|
200 |
settings=settings,
|
201 |
)
|
|
|
202 |
|
203 |
msg = cl.Message(content="")
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
token =
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
from chainlit.playground.providers import ChatOpenAI # importing ChatOpenAI tools
|
9 |
from dotenv import load_dotenv
|
10 |
from prompt_manager import PromptManager
|
11 |
+
from logger_config import logger
|
12 |
|
13 |
load_dotenv()
|
14 |
+
logger.info("Environment variables loaded")
|
15 |
|
16 |
# Initialize prompt manager
|
17 |
prompt_manager = PromptManager()
|
|
|
130 |
|
131 |
@cl.on_chat_start
|
132 |
async def start_chat():
|
133 |
+
logger.info("Starting new chat session")
|
134 |
# Create aspect selection buttons with descriptions
|
135 |
aspects = prompt_manager.get_aspect_names()
|
136 |
actions = []
|
|
|
150 |
content="Welcome! Please select an aspect for our conversation. Hover over each option to see examples and descriptions:",
|
151 |
actions=actions
|
152 |
).send()
|
153 |
+
logger.info("Welcome message sent with aspect selection buttons")
|
154 |
|
155 |
@cl.action_callback("Concept Simplification")
|
156 |
@cl.action_callback("Summarization")
|
|
|
161 |
async def on_action(action):
|
162 |
# Store the selected aspect in the user session
|
163 |
cl.user_session.set("selected_aspect", action.value)
|
164 |
+
logger.info(f"User selected aspect: {action.value}")
|
165 |
|
166 |
# Send confirmation message with examples
|
167 |
await cl.Message(
|
168 |
content=prompt_manager.get_confirmation_message(action.value)
|
169 |
).send()
|
170 |
+
logger.debug(f"Confirmation message sent for aspect: {action.value}")
|
171 |
|
172 |
@cl.on_message
|
173 |
async def main(message: cl.Message):
|
174 |
# Get the selected aspect from the session
|
175 |
selected_aspect = cl.user_session.get("selected_aspect")
|
176 |
+
logger.info(f"Processing message with aspect: {selected_aspect}")
|
177 |
+
logger.debug(f"User message: {message.content}")
|
178 |
|
179 |
settings = {
|
180 |
"model": "gpt-4-turbo-preview", # Upgraded to GPT-4 Turbo
|
|
|
184 |
"frequency_penalty": 0.3, # Added to reduce repetition
|
185 |
"presence_penalty": 0.3, # Added to encourage diverse topics
|
186 |
}
|
187 |
+
logger.debug(f"OpenAI settings: {settings}")
|
188 |
|
189 |
client = AsyncOpenAI()
|
190 |
|
191 |
# Get the appropriate templates for the selected aspect
|
192 |
system_template, user_template = prompt_manager.get_templates(selected_aspect)
|
193 |
+
logger.debug("Templates retrieved for message processing")
|
194 |
|
195 |
prompt = Prompt(
|
196 |
provider=ChatOpenAI.id,
|
|
|
209 |
inputs={"input": message.content},
|
210 |
settings=settings,
|
211 |
)
|
212 |
+
logger.debug("Prompt created for OpenAI API call")
|
213 |
|
214 |
msg = cl.Message(content="")
|
215 |
+
logger.info("Starting OpenAI API call")
|
216 |
+
|
217 |
+
try:
|
218 |
+
# Call OpenAI
|
219 |
+
async for stream_resp in await client.chat.completions.create(
|
220 |
+
messages=[m.to_openai() for m in prompt.messages], stream=True, **settings
|
221 |
+
):
|
222 |
+
token = stream_resp.choices[0].delta.content
|
223 |
+
if not token:
|
224 |
+
token = ""
|
225 |
+
await msg.stream_token(token)
|
226 |
+
|
227 |
+
# Update the prompt object with the completion
|
228 |
+
prompt.completion = msg.content
|
229 |
+
msg.prompt = prompt
|
230 |
+
|
231 |
+
# Send and close the message stream
|
232 |
+
await msg.send()
|
233 |
+
logger.info("Response successfully sent to user")
|
234 |
+
except Exception as e:
|
235 |
+
logger.error(f"Error during OpenAI API call: {str(e)}")
|
236 |
+
await cl.Message(
|
237 |
+
content="I apologize, but I encountered an error processing your request. Please try again."
|
238 |
+
).send()
|
logger_config.py
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
import os
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
# Create logs directory if it doesn't exist
|
6 |
+
os.makedirs("logs", exist_ok=True)
|
7 |
+
|
8 |
+
# Configure logging
|
9 |
+
def setup_logger():
|
10 |
+
# Create a logger
|
11 |
+
logger = logging.getLogger("chainlit_chatbot")
|
12 |
+
logger.setLevel(logging.INFO)
|
13 |
+
|
14 |
+
# Create handlers
|
15 |
+
# Console handler
|
16 |
+
console_handler = logging.StreamHandler()
|
17 |
+
console_handler.setLevel(logging.INFO)
|
18 |
+
|
19 |
+
# File handler - log to file with timestamp
|
20 |
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
21 |
+
file_handler = logging.FileHandler(f"logs/chatbot_{timestamp}.log")
|
22 |
+
file_handler.setLevel(logging.DEBUG)
|
23 |
+
|
24 |
+
# Create formatters and add it to handlers
|
25 |
+
console_format = logging.Formatter('%(levelname)s - %(message)s')
|
26 |
+
file_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
27 |
+
|
28 |
+
console_handler.setFormatter(console_format)
|
29 |
+
file_handler.setFormatter(file_format)
|
30 |
+
|
31 |
+
# Add handlers to the logger
|
32 |
+
logger.addHandler(console_handler)
|
33 |
+
logger.addHandler(file_handler)
|
34 |
+
|
35 |
+
return logger
|
36 |
+
|
37 |
+
# Create and export the logger
|
38 |
+
logger = setup_logger()
|
prompt_manager.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
from dataclasses import dataclass
|
2 |
from typing import Dict, List
|
|
|
3 |
|
4 |
@dataclass
|
5 |
class AspectInfo:
|
@@ -10,6 +11,7 @@ class AspectInfo:
|
|
10 |
|
11 |
class PromptManager:
|
12 |
def __init__(self):
|
|
|
13 |
# Default template for when no aspect is selected
|
14 |
self.default_aspect = AspectInfo(
|
15 |
description="General purpose AI assistant with balanced capabilities",
|
@@ -24,6 +26,7 @@ Adapt your communication style based on the user's needs and the complexity of t
|
|
24 |
user_template="""{input}
|
25 |
Think through your response step by step."""
|
26 |
)
|
|
|
27 |
|
28 |
self.aspects = {
|
29 |
"Concept Simplification": AspectInfo(
|
@@ -117,22 +120,27 @@ Adapt your communication style to match the user's level of expertise.""",
|
|
117 |
- How does this relate to everyday experience?"""
|
118 |
)
|
119 |
}
|
|
|
120 |
|
121 |
def get_aspect_names(self) -> List[str]:
|
122 |
"""Get list of available aspect names."""
|
|
|
123 |
return list(self.aspects.keys())
|
124 |
|
125 |
def get_aspect_info(self, aspect_name: str) -> AspectInfo:
|
126 |
"""Get information for a specific aspect."""
|
|
|
127 |
return self.aspects.get(aspect_name, self.default_aspect)
|
128 |
|
129 |
def get_action_description(self, aspect_name: str) -> str:
|
130 |
"""Get formatted description for action button."""
|
|
|
131 |
info = self.aspects[aspect_name]
|
132 |
return f"{info.description}\n\nExample tasks:\n" + "\n".join(f"• {example}" for example in info.examples)
|
133 |
|
134 |
def get_confirmation_message(self, aspect_name: str) -> str:
|
135 |
"""Get formatted confirmation message for selected aspect."""
|
|
|
136 |
info = self.aspects[aspect_name]
|
137 |
examples = "\n".join(f"• {example}" for example in info.examples[:2])
|
138 |
return f"""You've selected: {aspect_name}
|
@@ -145,7 +153,9 @@ Try asking something like:
|
|
145 |
def get_templates(self, aspect_name: str | None) -> tuple[str, str]:
|
146 |
"""Get system and user templates for an aspect."""
|
147 |
if aspect_name is None:
|
|
|
148 |
info = self.default_aspect
|
149 |
else:
|
|
|
150 |
info = self.aspects.get(aspect_name, self.default_aspect)
|
151 |
return info.system_template, info.user_template
|
|
|
1 |
from dataclasses import dataclass
|
2 |
from typing import Dict, List
|
3 |
+
from logger_config import logger
|
4 |
|
5 |
@dataclass
|
6 |
class AspectInfo:
|
|
|
11 |
|
12 |
class PromptManager:
|
13 |
def __init__(self):
|
14 |
+
logger.info("Initializing PromptManager")
|
15 |
# Default template for when no aspect is selected
|
16 |
self.default_aspect = AspectInfo(
|
17 |
description="General purpose AI assistant with balanced capabilities",
|
|
|
26 |
user_template="""{input}
|
27 |
Think through your response step by step."""
|
28 |
)
|
29 |
+
logger.debug("Default aspect template created")
|
30 |
|
31 |
self.aspects = {
|
32 |
"Concept Simplification": AspectInfo(
|
|
|
120 |
- How does this relate to everyday experience?"""
|
121 |
)
|
122 |
}
|
123 |
+
logger.info(f"Initialized {len(self.aspects)} aspects")
|
124 |
|
125 |
def get_aspect_names(self) -> List[str]:
|
126 |
"""Get list of available aspect names."""
|
127 |
+
logger.debug("Getting aspect names")
|
128 |
return list(self.aspects.keys())
|
129 |
|
130 |
def get_aspect_info(self, aspect_name: str) -> AspectInfo:
|
131 |
"""Get information for a specific aspect."""
|
132 |
+
logger.debug(f"Getting aspect info for: {aspect_name}")
|
133 |
return self.aspects.get(aspect_name, self.default_aspect)
|
134 |
|
135 |
def get_action_description(self, aspect_name: str) -> str:
|
136 |
"""Get formatted description for action button."""
|
137 |
+
logger.debug(f"Getting action description for: {aspect_name}")
|
138 |
info = self.aspects[aspect_name]
|
139 |
return f"{info.description}\n\nExample tasks:\n" + "\n".join(f"• {example}" for example in info.examples)
|
140 |
|
141 |
def get_confirmation_message(self, aspect_name: str) -> str:
|
142 |
"""Get formatted confirmation message for selected aspect."""
|
143 |
+
logger.debug(f"Getting confirmation message for: {aspect_name}")
|
144 |
info = self.aspects[aspect_name]
|
145 |
examples = "\n".join(f"• {example}" for example in info.examples[:2])
|
146 |
return f"""You've selected: {aspect_name}
|
|
|
153 |
def get_templates(self, aspect_name: str | None) -> tuple[str, str]:
|
154 |
"""Get system and user templates for an aspect."""
|
155 |
if aspect_name is None:
|
156 |
+
logger.info("No aspect selected, using default template")
|
157 |
info = self.default_aspect
|
158 |
else:
|
159 |
+
logger.info(f"Using templates for aspect: {aspect_name}")
|
160 |
info = self.aspects.get(aspect_name, self.default_aspect)
|
161 |
return info.system_template, info.user_template
|