Overhaul of architecture to act as a Flask web API, provide results as a JSON including event logs, and provide threading functionality.
This commit is contained in:
parent
b54cd363f4
commit
e43a9d5daf
|
@ -0,0 +1,5 @@
|
||||||
|
################################################################################
|
||||||
|
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
/.env
|
|
@ -4,7 +4,7 @@
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
<ProjectGuid>f31e605a-2c1b-40be-9c5d-e09f28ab8fe1</ProjectGuid>
|
<ProjectGuid>f31e605a-2c1b-40be-9c5d-e09f28ab8fe1</ProjectGuid>
|
||||||
<ProjectHome>.</ProjectHome>
|
<ProjectHome>.</ProjectHome>
|
||||||
<StartupFile>main.py</StartupFile>
|
<StartupFile>api.py</StartupFile>
|
||||||
<SearchPath>
|
<SearchPath>
|
||||||
</SearchPath>
|
</SearchPath>
|
||||||
<WorkingDirectory>.</WorkingDirectory>
|
<WorkingDirectory>.</WorkingDirectory>
|
||||||
|
@ -22,7 +22,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="agents.py" />
|
<Compile Include="agents.py" />
|
||||||
<Compile Include="main.py" />
|
<Compile Include="api.py" />
|
||||||
|
<Compile Include="crew.py" />
|
||||||
|
<Compile Include="job_manager.py" />
|
||||||
<Compile Include="tasks.py" />
|
<Compile Include="tasks.py" />
|
||||||
<Compile Include="tools\search_tools.py" />
|
<Compile Include="tools\search_tools.py" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from crewai import Agent
|
from crewai import Agent
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from langchain_community.llms import ollama
|
from langchain_community.llms import ollama
|
||||||
from langchain_openai import ChatOpenAI
|
|
||||||
|
|
||||||
from tools.search_tools import SearchTools
|
from tools.search_tools import SearchTools
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
from threading import Thread
|
||||||
|
from uuid import uuid4 as uuid
|
||||||
|
from flask import Flask, jsonify, request, abort
|
||||||
|
from crew import ChatCrew
|
||||||
|
from job_manager import jobs_lock, append_event, jobs, Event
|
||||||
|
from datetime import datetime
|
||||||
|
import json
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
def kickoff_crew(job_id, company, contact, interests, city):
|
||||||
|
print(f"Running crew for {job_id} for company {company} with point of contact {contact}")
|
||||||
|
|
||||||
|
# Setup the crew, run, and process results
|
||||||
|
results = None
|
||||||
|
try:
|
||||||
|
crew = ChatCrew(job_id=job_id)
|
||||||
|
crew.setup_crew(company=company, contact=contact, interests=interests, city=city)
|
||||||
|
result = crew.kickoff()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"CREW FALED: {str(e)}")
|
||||||
|
append_event(job_id, f"CREW FAILED: {str(e)}")
|
||||||
|
with jobs_lock:
|
||||||
|
jobs[job_id].status = "ERROR"
|
||||||
|
jobs[job_id].result = str(e)
|
||||||
|
|
||||||
|
with jobs_lock:
|
||||||
|
jobs[job_id].status = "COMPLETE"
|
||||||
|
jobs[job_id].result = result
|
||||||
|
jobs[job_id].events.append(Event(
|
||||||
|
data="CREW COMPLETED", timestamp=datetime.now()
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/crew', methods=['POST'])
|
||||||
|
def run_crew():
|
||||||
|
data = request.json
|
||||||
|
if not data or 'company' not in data or 'contact' not in data or 'interests' not in data or 'city' not in data:
|
||||||
|
abort(400, description='Invalid request')
|
||||||
|
|
||||||
|
job_id = str(uuid())
|
||||||
|
company = data['company']
|
||||||
|
contact = data['contact']
|
||||||
|
interests = data['interests']
|
||||||
|
city = data['city']
|
||||||
|
|
||||||
|
# Run the crew
|
||||||
|
thread = Thread(target=kickoff_crew, args=(job_id, company, contact, interests, city))
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
return jsonify({'job_id': job_id}), 200
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/crew/<job_id>', methods=['GET'])
|
||||||
|
def get_status(job_id):
|
||||||
|
# Lock the job and check if it exists
|
||||||
|
with jobs_lock:
|
||||||
|
job = jobs.get(job_id)
|
||||||
|
if not job:
|
||||||
|
abort(404, description="Job not found")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result_json = json.loads(job.result)
|
||||||
|
except:
|
||||||
|
result_json = job.result
|
||||||
|
|
||||||
|
print(f"{job_id} | {job.status} | {result_json}")
|
||||||
|
return jsonify({
|
||||||
|
'job_id': job_id,
|
||||||
|
'status': job.status,
|
||||||
|
'result': result_json,
|
||||||
|
'events': [{"timestamp": event.timestamp.isoformat(), "data": event.data} for event in job.events]
|
||||||
|
}), 200
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(debug=True, port=3001)
|
|
@ -0,0 +1,52 @@
|
||||||
|
from crewai import Crew
|
||||||
|
from textwrap import dedent
|
||||||
|
from agents import TalkingAgents
|
||||||
|
from tasks import TalkingTasks
|
||||||
|
from job_manager import append_event
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
|
class ChatCrew:
|
||||||
|
def __init__(self, job_id):
|
||||||
|
# Crew variables
|
||||||
|
self.job_id = job_id
|
||||||
|
self.crew = None
|
||||||
|
|
||||||
|
def setup_crew(self, company, contact, interests, city):
|
||||||
|
print(f'Initializing crew for {self.job_id} for comapny {company} with point of contact {contact}')
|
||||||
|
|
||||||
|
# Initialize agents
|
||||||
|
agents = TalkingAgents()
|
||||||
|
master_networker = agents.master_networker()
|
||||||
|
local_expert = agents.local_expert()
|
||||||
|
|
||||||
|
# Initialize tasks
|
||||||
|
tasks = TalkingTasks(self.job_id)
|
||||||
|
chat_tasks = [
|
||||||
|
tasks.research_topics(master_networker, company), tasks.gather_city_info(local_expert, city, interests)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Initialize crew
|
||||||
|
self.crew = Crew(
|
||||||
|
agents=[master_networker, local_expert],
|
||||||
|
tasks=chat_tasks,
|
||||||
|
verbose=2
|
||||||
|
)
|
||||||
|
|
||||||
|
def kickoff(self):
|
||||||
|
if not self.crew:
|
||||||
|
print(f"No crew found for {self.job_id}")
|
||||||
|
return
|
||||||
|
|
||||||
|
append_event(self.job_id, "CREW STARTED")
|
||||||
|
try:
|
||||||
|
print(f'Running crew for {self.job_id}')
|
||||||
|
result = self.crew.kickoff()
|
||||||
|
append_event(self.job_id, "CREW COMPLETED")
|
||||||
|
return result
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
append_event(self.job_id, "ERROR ENCOUNTERED")
|
||||||
|
return str(e)
|
|
@ -0,0 +1,37 @@
|
||||||
|
from typing import List, Dict
|
||||||
|
from datetime import datetime
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from threading import Lock
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Event:
|
||||||
|
timestamp: datetime
|
||||||
|
data: str
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Job:
|
||||||
|
status: str
|
||||||
|
events: List[Event]
|
||||||
|
result: str
|
||||||
|
|
||||||
|
jobs_lock = Lock()
|
||||||
|
jobs: Dict[str, "Job"] = {}
|
||||||
|
|
||||||
|
def append_event(job_id, event_data):
|
||||||
|
# This is our job status db; so we need to lock it
|
||||||
|
with jobs_lock:
|
||||||
|
if job_id not in jobs: # If this is the first action, initialize defaults and flag as started
|
||||||
|
print(f"Start job: {job_id}")
|
||||||
|
jobs[job_id] = Job(
|
||||||
|
status="STARTED",
|
||||||
|
events=[],
|
||||||
|
result=""
|
||||||
|
)
|
||||||
|
else: # If the job already exists, append to list
|
||||||
|
print("Appending event for job")
|
||||||
|
jobs[job_id].events.append(
|
||||||
|
Event(
|
||||||
|
timestamp=datetime.now(),
|
||||||
|
data=event_data
|
||||||
|
)
|
||||||
|
)
|
89
main.py
89
main.py
|
@ -1,89 +0,0 @@
|
||||||
"""
|
|
||||||
Client Engagement Tool
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
from doctest import master
|
|
||||||
from crewai import Crew
|
|
||||||
from textwrap import dedent
|
|
||||||
from agents import TalkingAgents
|
|
||||||
from tasks import TalkingTasks
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
|
|
||||||
class TripCrew:
|
|
||||||
def __init__(self, customer, contact):
|
|
||||||
self.customer = customer
|
|
||||||
self.contact = contact
|
|
||||||
self.interests = 'Art, hiking, animals'
|
|
||||||
self.city = 'Canton, Michigan'
|
|
||||||
self.team_affinity = ''
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
# Define your custom agents and tasks in agents.py and tasks.py
|
|
||||||
agents = TalkingAgents()
|
|
||||||
tasks = TalkingTasks()
|
|
||||||
|
|
||||||
# Define your custom agents and tasks here
|
|
||||||
master_networker = agents.master_networker()
|
|
||||||
local_guide = agents.local_expert()
|
|
||||||
sports_analyst = agents.sports_analyst()
|
|
||||||
|
|
||||||
# Custom tasks include agent name and variables as input
|
|
||||||
research_topics = tasks.research_topics(
|
|
||||||
master_networker,
|
|
||||||
self.customer,
|
|
||||||
#self.contact
|
|
||||||
)
|
|
||||||
gather_sports_info = tasks.gather_sports_info(
|
|
||||||
sports_analyst,
|
|
||||||
# These two will be replaced programmatically, presumably from a db/excel lookup
|
|
||||||
self.city,
|
|
||||||
self.team_affinity
|
|
||||||
)
|
|
||||||
|
|
||||||
gather_city_info = tasks.gather_city_info(
|
|
||||||
local_guide,
|
|
||||||
self.city,
|
|
||||||
self.interests
|
|
||||||
)
|
|
||||||
|
|
||||||
# Define your custom crew here
|
|
||||||
crew = Crew(
|
|
||||||
agents=[master_networker,
|
|
||||||
sports_analyst,
|
|
||||||
local_guide
|
|
||||||
],
|
|
||||||
tasks=[
|
|
||||||
research_topics,
|
|
||||||
gather_sports_info,
|
|
||||||
gather_city_info
|
|
||||||
],
|
|
||||||
verbose=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
result = crew.kickoff()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
# This is the main function that you will use to run your custom crew.
|
|
||||||
if __name__ == "__main__":
|
|
||||||
print("## Welcome to PreCET")
|
|
||||||
print('-------------------------------')
|
|
||||||
customer = input(
|
|
||||||
dedent("""
|
|
||||||
Which company are you going to be contacting?
|
|
||||||
"""))
|
|
||||||
contact = input(
|
|
||||||
dedent("""
|
|
||||||
Who are you going to be talking with from {}?
|
|
||||||
""".format(customer)))
|
|
||||||
|
|
||||||
trip_crew = TripCrew(customer, contact)
|
|
||||||
result = trip_crew.run()
|
|
||||||
print("\n\n########################")
|
|
||||||
print("## Here are your Topics of Conversation")
|
|
||||||
print("########################\n")
|
|
||||||
print(result)
|
|
5
tasks.py
5
tasks.py
|
@ -46,7 +46,10 @@ Key Steps for Task Creation:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class TalkingTasks:
|
class TalkingTasks():
|
||||||
|
def __init__(self, job_id):
|
||||||
|
self.job_id = job_id
|
||||||
|
|
||||||
def __tip_section(self):
|
def __tip_section(self):
|
||||||
return "You work on commission, so securing the sale is your number one priority."
|
return "You work on commission, so securing the sale is your number one priority."
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue