mirror of
https://github.com/QuivrHQ/quivr.git
synced 2024-08-17 02:10:31 +03:00
feat(email): Add email sender tool and update image generator tool (#2579)
This pull request adds a new email sender tool and updates the image generator tool.
This commit is contained in:
parent
105a2b8ecc
commit
01c6e7b3bb
@ -9,13 +9,13 @@ from typing import List, Optional
|
||||
|
||||
from fastapi import UploadFile
|
||||
from logger import get_logger
|
||||
from modules.user.service.user_usage import UserUsage
|
||||
from modules.assistant.dto.inputs import InputAssistant
|
||||
from modules.assistant.ito.utils.pdf_generator import PDFGenerator, PDFModel
|
||||
from modules.chat.controller.chat.utils import update_user_usage
|
||||
from modules.contact_support.controller.settings import ContactsSettings
|
||||
from modules.upload.controller.upload_routes import upload_file
|
||||
from modules.user.entity.user_identity import UserIdentity
|
||||
from modules.user.service.user_usage import UserUsage
|
||||
from packages.emails.send_email import send_email
|
||||
from pydantic import BaseModel
|
||||
from unidecode import unidecode
|
||||
@ -111,8 +111,8 @@ class ITO(BaseModel):
|
||||
</div>
|
||||
"""
|
||||
params = {
|
||||
"from": mail_from,
|
||||
"to": mail_to,
|
||||
"sender": mail_from,
|
||||
"to": [mail_to],
|
||||
"subject": "Quivr Ingestion Processed",
|
||||
"reply_to": "no-reply@quivr.app",
|
||||
"html": body,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import json
|
||||
import operator
|
||||
from typing import Annotated, AsyncIterable, List, Sequence, TypedDict
|
||||
from typing import Annotated, AsyncIterable, List, Optional, Sequence, TypedDict
|
||||
from uuid import UUID
|
||||
|
||||
from langchain.tools import BaseTool
|
||||
@ -15,7 +15,12 @@ from modules.brain.knowledge_brain_qa import KnowledgeBrainQA
|
||||
from modules.chat.dto.chats import ChatQuestion
|
||||
from modules.chat.dto.outputs import GetChatHistoryOutput
|
||||
from modules.chat.service.chat_service import ChatService
|
||||
from modules.tools import ImageGeneratorTool, URLReaderTool, WebSearchTool
|
||||
from modules.tools import (
|
||||
EmailSenderTool,
|
||||
ImageGeneratorTool,
|
||||
URLReaderTool,
|
||||
WebSearchTool,
|
||||
)
|
||||
|
||||
|
||||
class AgentState(TypedDict):
|
||||
@ -37,8 +42,8 @@ class GPT4Brain(KnowledgeBrainQA):
|
||||
KnowledgeBrainQA (_type_): A brain that store the knowledge internaly
|
||||
"""
|
||||
|
||||
tools: List[BaseTool] = [WebSearchTool(), ImageGeneratorTool(), URLReaderTool()]
|
||||
tool_executor: ToolExecutor = ToolExecutor(tools)
|
||||
tools: Optional[List[BaseTool]] = None
|
||||
tool_executor: Optional[ToolExecutor] = None
|
||||
model_function: ChatOpenAI = None
|
||||
|
||||
def __init__(
|
||||
@ -48,6 +53,13 @@ class GPT4Brain(KnowledgeBrainQA):
|
||||
super().__init__(
|
||||
**kwargs,
|
||||
)
|
||||
self.tools = [
|
||||
WebSearchTool(),
|
||||
ImageGeneratorTool(),
|
||||
URLReaderTool(),
|
||||
EmailSenderTool(user_email=self.user_email),
|
||||
]
|
||||
self.tool_executor = ToolExecutor(tools=self.tools)
|
||||
|
||||
def calculate_pricing(self):
|
||||
return 3
|
||||
@ -164,7 +176,7 @@ class GPT4Brain(KnowledgeBrainQA):
|
||||
transformed_history, streamed_chat_history = (
|
||||
self.initialize_streamed_chat_history(chat_id, question)
|
||||
)
|
||||
filtered_history = self.filter_history(transformed_history, 20, 2000)
|
||||
filtered_history = self.filter_history(transformed_history, 40, 2000)
|
||||
response_tokens = []
|
||||
config = {"metadata": {"conversation_id": str(chat_id)}}
|
||||
|
||||
@ -232,7 +244,7 @@ class GPT4Brain(KnowledgeBrainQA):
|
||||
transformed_history, _ = self.initialize_streamed_chat_history(
|
||||
chat_id, question
|
||||
)
|
||||
filtered_history = self.filter_history(transformed_history, 20, 2000)
|
||||
filtered_history = self.filter_history(transformed_history, 40, 2000)
|
||||
config = {"metadata": {"conversation_id": str(chat_id)}}
|
||||
|
||||
prompt = ChatPromptTemplate.from_messages(
|
||||
|
@ -1,4 +1,4 @@
|
||||
from .image_generator import ImageGeneratorTool
|
||||
from .web_search import WebSearchTool
|
||||
from .url_reader import URLReaderTool
|
||||
|
||||
from .email_sender import EmailSenderTool
|
81
backend/modules/tools/email_sender.py
Normal file
81
backend/modules/tools/email_sender.py
Normal file
@ -0,0 +1,81 @@
|
||||
# Extract and combine content recursively
|
||||
from typing import Dict, Optional, Type
|
||||
|
||||
from langchain.callbacks.manager import (
|
||||
AsyncCallbackManagerForToolRun,
|
||||
CallbackManagerForToolRun,
|
||||
)
|
||||
from langchain.pydantic_v1 import BaseModel as BaseModelV1
|
||||
from langchain.pydantic_v1 import Field as FieldV1
|
||||
from langchain_community.document_loaders import PlaywrightURLLoader
|
||||
from langchain_core.tools import BaseTool
|
||||
from logger import get_logger
|
||||
from models import BrainSettings
|
||||
from modules.contact_support.controller.settings import ContactsSettings
|
||||
from packages.emails.send_email import send_email
|
||||
from pydantic import BaseModel
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class EmailInput(BaseModelV1):
|
||||
text: str = FieldV1(
|
||||
...,
|
||||
title="text",
|
||||
description="text to send in HTML email format. Use pretty formating, use bold, italic, next line, etc...",
|
||||
)
|
||||
|
||||
|
||||
class EmailSenderTool(BaseTool):
|
||||
user_email: str
|
||||
name = "email-sender"
|
||||
description = "useful for when you need to send an email."
|
||||
args_schema: Type[BaseModel] = EmailInput
|
||||
brain_settings: BrainSettings = BrainSettings()
|
||||
contact_settings: ContactsSettings = ContactsSettings()
|
||||
|
||||
def _run(
|
||||
self, text: str, run_manager: Optional[CallbackManagerForToolRun] = None
|
||||
) -> Dict:
|
||||
|
||||
html_body = f"""
|
||||
<div style="text-align: center;">
|
||||
<img src="https://quivr-cms.s3.eu-west-3.amazonaws.com/logo_quivr_white_7e3c72620f.png" alt="Quivr Logo" style="width: 100px; height: 100px; border-radius: 50%; margin: 0 auto; display: block;">
|
||||
<br />
|
||||
</div>
|
||||
"""
|
||||
html_body += f"""
|
||||
{text}
|
||||
"""
|
||||
logger.debug(f"Email body: {html_body}")
|
||||
logger.debug(f"Email to: {self.user_email}")
|
||||
logger.debug(f"Email from: {self.contact_settings.resend_contact_sales_from}")
|
||||
try:
|
||||
r = send_email(
|
||||
{
|
||||
"sender": self.contact_settings.resend_contact_sales_from,
|
||||
"to": self.user_email,
|
||||
"reply_to": "no-reply@quivr.app",
|
||||
"subject": "Email from your assistant",
|
||||
"html": html_body,
|
||||
}
|
||||
)
|
||||
logger.info("Resend response", r)
|
||||
except Exception as e:
|
||||
logger.error(f"Error sending email: {e}")
|
||||
return {"content": "Error sending email because of error: " + str(e)}
|
||||
|
||||
return {"content": "Email sent"}
|
||||
|
||||
async def _arun(
|
||||
self, url: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
|
||||
) -> Dict:
|
||||
"""Run the tool asynchronously."""
|
||||
loader = PlaywrightURLLoader(urls=[url], remove_selectors=["header", "footer"])
|
||||
data = loader.load()
|
||||
|
||||
extracted_content = ""
|
||||
for page in data:
|
||||
extracted_content += page.page_content
|
||||
|
||||
return {"content": extracted_content}
|
@ -57,5 +57,6 @@ class ImageGeneratorTool(BaseTool):
|
||||
n=1,
|
||||
)
|
||||
image_url = response.data[0].url
|
||||
revised_prompt = response.data[0].revised_prompt
|
||||
# Make the url a markdown image
|
||||
return f"![Generated Image]({image_url})"
|
||||
return f"{revised_prompt} \n ![Generated Image]({image_url}) "
|
||||
|
@ -78,3 +78,8 @@ class WebSearchTool(BaseTool):
|
||||
|
||||
def _format_result(self, title: str, description: str, url: str) -> str:
|
||||
return f"**{title}**\n{description}\n{url}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
tool = WebSearchTool()
|
||||
print(tool.run("python"))
|
||||
|
Loading…
Reference in New Issue
Block a user