|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import logging |
|
import os |
|
import markdown |
|
from dotenv import load_dotenv |
|
import gradio as gr |
|
from langchain_groq import ChatGroq |
|
from langchain.utilities.tavily_search import TavilySearchAPIWrapper |
|
from langchain_community.tools.tavily_search import TavilySearchResults |
|
from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage |
|
|
|
|
|
logging.basicConfig( |
|
level=logging.INFO, |
|
format='%(asctime)s - %(levelname)s - %(message)s', |
|
datefmt='%Y-%m-%d %H:%M:%S' |
|
) |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
load_dotenv('.env.local') |
|
|
|
|
|
groq_api_key = os.getenv('GROQ_API_KEY') |
|
tavily_api_key = os.getenv('TAVILY_API_KEY') |
|
|
|
|
|
llm = ChatGroq( |
|
model_name="llama-3.3-70b-versatile", |
|
groq_api_key=groq_api_key, |
|
temperature=0 |
|
) |
|
|
|
|
|
tavilySearch = TavilySearchAPIWrapper(tavily_api_key=tavily_api_key) |
|
search_tool = TavilySearchResults(max_results=3, api_wrapper=tavilySearch) |
|
|
|
system_prompt = """ |
|
You are Unica, a friendly and helpful assistant designed to support students on the Moodle platform. Your primary goal is to provide quick and accurate answers to students' study-related questions, helping them navigate their courses and resources efficiently. |
|
|
|
Guidelines: |
|
1. Understand the context of Moodle and the student's coursework. |
|
2. Be concise and clear in your responses. |
|
3. Provide relevant information directly addressing the student's question. |
|
4. Maintain a positive and encouraging tone. |
|
5. Offer study tips when appropriate. |
|
6. Handle unknowns gracefully by suggesting resources or encouraging further inquiry. |
|
7. Respect privacy and maintain a professional demeanor. |
|
8. Encourage engagement with course materials and resources. |
|
9. Use Markdown formatting to enhance the readability of your responses. |
|
|
|
Example Responses: |
|
- Student: "How do I submit my assignment on Moodle?" |
|
Unica: "To submit your assignment, navigate to the course page, find the assignment link, and click on **'Submit assignment'**. Follow the prompts to upload your file. If you encounter any issues, feel free to ask for further assistance!" |
|
|
|
- Student: "What are the upcoming deadlines for my course?" |
|
Unica: "To view upcoming deadlines, check the course calendar or the announcements section on your Moodle dashboard. If you have specific questions about a deadline, it's best to contact your instructor." |
|
""" |
|
|
|
class Agent: |
|
def __init__(self, model, tools, system_prompt=""): |
|
self.system_prompt = system_prompt |
|
self.model = model |
|
self.tools = {t.name: t for t in tools} |
|
|
|
def call_groq(self, messages): |
|
if self.system_prompt: |
|
messages = [SystemMessage(content=self.system_prompt)] + messages |
|
logger.info(f"Calling Groq with messages: {messages}") |
|
message = self.model.invoke(messages) |
|
logger.info(f"Groq response: {message}") |
|
return message |
|
|
|
def handle_query(self, user_query): |
|
messages = [HumanMessage(content=user_query)] |
|
response = self.call_groq(messages) |
|
return response.content |
|
|
|
|
|
agent = Agent(model=llm, tools=[search_tool], system_prompt=system_prompt) |
|
|
|
def render_markdown(markdown_text, is_user=False): |
|
|
|
html_content = markdown.markdown(markdown_text) |
|
|
|
bubble_class = "user-bubble" if is_user else "assistant-bubble" |
|
bubble_html = f""" |
|
<div class="{bubble_class}"> |
|
{html_content} |
|
</div> |
|
<style> |
|
.user-bubble {{ |
|
background-color: #e1f5fe; |
|
border-radius: 15px; |
|
padding: 10px; |
|
margin: 10px 0; |
|
max-width: 70%; |
|
align-self: flex-end; |
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
}} |
|
.assistant-bubble {{ |
|
background-color: #f1f1f1; |
|
border-radius: 15px; |
|
padding: 10px; |
|
margin: 10px 0; |
|
max-width: 70%; |
|
align-self: flex-start; |
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
}} |
|
.chat-container {{ |
|
display: flex; |
|
flex-direction: column; |
|
gap: 10px; |
|
padding: 10px; |
|
}} |
|
</style> |
|
""" |
|
return bubble_html |
|
|
|
def handle_user_query(user_query): |
|
try: |
|
response = agent.handle_query(user_query) |
|
logger.info(f"Assistant's message: {response}") |
|
|
|
user_html = render_markdown(user_query, is_user=True) |
|
assistant_html = render_markdown(response, is_user=False) |
|
chat_html = f""" |
|
<div class="chat-container"> |
|
{user_html} |
|
{assistant_html} |
|
</div> |
|
""" |
|
return chat_html |
|
except Exception as e: |
|
logger.error(f"Error handling user query: {e}") |
|
return "Sorry, I encountered an error. Please try again." |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(theme='ParityError/Interstellar') as demo: |
|
chatbot = gr.Chatbot([], label="Chat with Unica") |
|
user_input = gr.Textbox(lines=2, placeholder="Ask your study-related questions here", label="Your Message") |
|
send_button = gr.Button("Send") |
|
|
|
def respond(user_message, history): |
|
response = agent.handle_query(user_message) |
|
history.append((user_message, response)) |
|
return history, "" |
|
|
|
|
|
send_button.click(respond, [user_input, chatbot], [chatbot, user_input]) |
|
|
|
user_input.submit(respond, [user_input, chatbot], [chatbot, user_input]) |
|
|
|
if __name__ == "__main__": |
|
demo.launch(pwa=True, share=True) |
|
|
|
''' |
|
Note: |
|
If you are running this chatbot on your own feel free to add parameter of `debug=True` in launch() so that you can be able to handle any bugs asap |
|
Happy coding *_* |
|
''' |
|
|
|
|
|
|
|
|
|
|