Spaces:
Sleeping
Sleeping
Create crew_utils.py
Browse files- crew_utils.py +187 -0
crew_utils.py
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# crew_utils.py
|
2 |
+
from crewai import Agent, Crew, Process, Task
|
3 |
+
from crewai_tools import SerperDevTool
|
4 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
5 |
+
from pydantic import BaseModel, Field
|
6 |
+
from typing import List
|
7 |
+
from pdf_tool import PDFTool
|
8 |
+
|
9 |
+
# --- Définition des outils ---
|
10 |
+
search_tool = SerperDevTool()
|
11 |
+
pdf_tool = PDFTool()
|
12 |
+
|
13 |
+
# --- Définition du LLM (Gemini) ---
|
14 |
+
# Remplace par ta clé API
|
15 |
+
api_key = "VOTRE_CLE_API_GOOGLE_AI_STUDIO"
|
16 |
+
|
17 |
+
# Vérifie si la clé API est définie
|
18 |
+
if not api_key:
|
19 |
+
raise ValueError("La clé API Google AI Studio n'est pas définie. Veuillez la configurer comme variable d'environnement GOOGLE_API_KEY.")
|
20 |
+
|
21 |
+
llm = ChatGoogleGenerativeAI(
|
22 |
+
model="gemini-pro", google_api_key=api_key, temperature=0.7
|
23 |
+
)
|
24 |
+
|
25 |
+
# --- Définition des agents ---
|
26 |
+
# Chef de Projet
|
27 |
+
project_manager = Agent(
|
28 |
+
role="Chef de Projet",
|
29 |
+
goal="Coordonner la création d'un exposé complet et de haute qualité sur le thème donné.",
|
30 |
+
backstory="Expert en gestion de projet et en coordination d'équipes, capable de diriger des projets complexes jusqu'à leur aboutissement.",
|
31 |
+
verbose=True,
|
32 |
+
llm=llm,
|
33 |
+
allow_delegation=True,
|
34 |
+
)
|
35 |
+
|
36 |
+
# Planificateur
|
37 |
+
planner = Agent(
|
38 |
+
role="Planificateur d'Exposé",
|
39 |
+
goal="Créer un plan détaillé et pertinent pour l'exposé.",
|
40 |
+
backstory="Spécialiste de la structuration de contenu, capable de générer des plans clairs et logiques pour des exposés complexes.",
|
41 |
+
verbose=True,
|
42 |
+
llm=llm,
|
43 |
+
)
|
44 |
+
|
45 |
+
# Rédacteurs (3 instances pour gérer l'introduction, le développement et la conclusion)
|
46 |
+
researcher_intro = Agent(
|
47 |
+
role="Rédacteur Spécialisé en Introduction",
|
48 |
+
goal="Rédiger une introduction captivante pour l'exposé.",
|
49 |
+
backstory="Expert en recherche et en rédaction, capable de produire du contenu informatif et bien écrit sur des sujets variés.",
|
50 |
+
verbose=True,
|
51 |
+
llm=llm,
|
52 |
+
tools=[search_tool],
|
53 |
+
)
|
54 |
+
|
55 |
+
researcher_dev = Agent(
|
56 |
+
role="Rédacteur Spécialisé en Développement",
|
57 |
+
goal="Rédiger les sections de développement de l'exposé.",
|
58 |
+
backstory="Expert en recherche et en rédaction, capable de produire du contenu informatif et bien écrit sur des sujets variés.",
|
59 |
+
verbose=True,
|
60 |
+
llm=llm,
|
61 |
+
tools=[search_tool],
|
62 |
+
)
|
63 |
+
|
64 |
+
researcher_conclusion = Agent(
|
65 |
+
role="Rédacteur Spécialisé en Conclusion",
|
66 |
+
goal="Rédiger une conclusion percutante pour l'exposé.",
|
67 |
+
backstory="Expert en recherche et en rédaction, capable de produire du contenu informatif et bien écrit sur des sujets variés.",
|
68 |
+
verbose=True,
|
69 |
+
llm=llm,
|
70 |
+
tools=[search_tool],
|
71 |
+
)
|
72 |
+
|
73 |
+
# Assembleur
|
74 |
+
assembler = Agent(
|
75 |
+
role="Assembleur d'Exposé",
|
76 |
+
goal="Compiler toutes les sections rédigées de l'exposé dans un seul document et générer un document PDF final de qualité professionnelle.",
|
77 |
+
backstory="Expert en mise en forme et en compilation de documents, capable de transformer des contenus distincts en un document final harmonieux et esthétique.",
|
78 |
+
verbose=True,
|
79 |
+
llm=llm,
|
80 |
+
tools=[pdf_tool],
|
81 |
+
)
|
82 |
+
|
83 |
+
# --- Définition des tâches ---
|
84 |
+
# Tâche pour le Planificateur
|
85 |
+
create_plan_task = Task(
|
86 |
+
description="""
|
87 |
+
Créez un plan détaillé pour un exposé sur le thème suivant : {topic}.
|
88 |
+
Le plan doit inclure une introduction, plusieurs sections principales (au moins 3), et une conclusion.
|
89 |
+
Assurez-vous que le plan est logique et couvre tous les aspects importants du sujet.
|
90 |
+
Divisez les sections principales en sous-sections si nécessaire pour une meilleure organisation.
|
91 |
+
""",
|
92 |
+
expected_output="Un plan d'exposé structuré avec des titres de sections et sous-sections, en format Markdown.",
|
93 |
+
agent=planner,
|
94 |
+
)
|
95 |
+
|
96 |
+
class SectionContent(BaseModel):
|
97 |
+
title: str = Field(..., description="Titre de la section")
|
98 |
+
content: str = Field(..., description="Contenu de la section")
|
99 |
+
|
100 |
+
# Tâches pour les Rédacteurs (exemple pour 3 sections, à adapter)
|
101 |
+
async def write_section_task(
|
102 |
+
researcher: Agent, section_title: str, context: List[Any]
|
103 |
+
) -> Task:
|
104 |
+
return Task(
|
105 |
+
description=f"""
|
106 |
+
Rédigez la section '{section_title}' de l'exposé en vous basant sur le plan fourni.
|
107 |
+
Effectuez des recherches approfondies en utilisant l'outil de recherche pour enrichir le contenu.
|
108 |
+
La section doit être informative, bien écrite et doit respecter le ton académique d'un exposé.
|
109 |
+
Voici le contexte: {context}
|
110 |
+
""",
|
111 |
+
expected_output=f"Texte complet et bien rédigé pour la section '{section_title}' de l'exposé, au format Markdown.",
|
112 |
+
agent=researcher,
|
113 |
+
tools=[search_tool],
|
114 |
+
output_pydantic=SectionContent, # Utilisez le modèle Pydantic ici
|
115 |
+
context=context,
|
116 |
+
)
|
117 |
+
|
118 |
+
# Tâche pour l'Assembleur
|
119 |
+
compile_report_task = Task(
|
120 |
+
description="""
|
121 |
+
Compilez toutes les sections rédigées de l'exposé dans un seul document.
|
122 |
+
Organisez les sections selon le plan fourni par le planificateur.
|
123 |
+
Générez un document PDF final prêt pour la présentation.
|
124 |
+
Assurez-vous que le document est bien structuré, facile à lire et qu'il respecte les conventions d'un exposé académique.
|
125 |
+
Voici le contexte: {context}
|
126 |
+
""",
|
127 |
+
expected_output="Un document PDF complet de l'exposé, prêt à être présenté.",
|
128 |
+
agent=assembler,
|
129 |
+
tools=[pdf_tool],
|
130 |
+
)
|
131 |
+
|
132 |
+
# --- Orchestration des tâches avec un processus hiérarchique ---
|
133 |
+
async def process_section_tasks(
|
134 |
+
manager: Agent,
|
135 |
+
plan: Any, # Remplace Any par le type de retour attendu de la tâche create_plan_task
|
136 |
+
researchers: List[Agent],
|
137 |
+
):
|
138 |
+
# Assume que plan est une liste de titres de sections
|
139 |
+
sections = plan.split("\n") # Adapter selon le format réel du plan
|
140 |
+
section_tasks: List[Task] = []
|
141 |
+
|
142 |
+
for i, section in enumerate(sections):
|
143 |
+
if section != "":
|
144 |
+
researcher = researchers[i % len(researchers)]
|
145 |
+
section_task = await write_section_task(
|
146 |
+
researcher=researcher,
|
147 |
+
section_title=section.strip(),
|
148 |
+
context=[create_plan_task],
|
149 |
+
)
|
150 |
+
section_tasks.append(section_task)
|
151 |
+
|
152 |
+
return section_tasks
|
153 |
+
|
154 |
+
class ExposeCrew(Crew):
|
155 |
+
def __init__(self, agents, tasks, process, manager_llm, verbose):
|
156 |
+
super().__init__(agents=agents, tasks=tasks, process=process, manager_llm=manager_llm, verbose=verbose)
|
157 |
+
|
158 |
+
async def kickoff(self, inputs: dict = {}) -> str:
|
159 |
+
# Exécuter la tâche de création du plan
|
160 |
+
plan = await create_plan_task.execute(context=inputs)
|
161 |
+
print(f"Plan de l'exposé : {plan}")
|
162 |
+
|
163 |
+
# Créer et exécuter les tâches de rédaction de section en parallèle
|
164 |
+
section_tasks = await process_section_tasks(
|
165 |
+
manager=self.manager_llm,
|
166 |
+
plan=plan,
|
167 |
+
researchers=[researcher_intro, researcher_dev, researcher_conclusion],
|
168 |
+
)
|
169 |
+
|
170 |
+
section_outputs = await asyncio.gather(*[task.execute() for task in section_tasks])
|
171 |
+
|
172 |
+
print(f"Sections rédigées : {section_outputs}")
|
173 |
+
|
174 |
+
# Mettre à jour la description de la tâche de compilation avec les sections rédigées
|
175 |
+
compile_report_task.description = f"""
|
176 |
+
Compilez toutes les sections rédigées de l'exposé dans un seul document.
|
177 |
+
Organisez les sections selon le plan fourni par le planificateur :
|
178 |
+
{plan}
|
179 |
+
Sections rédigées :
|
180 |
+
{section_outputs}
|
181 |
+
Générez un document PDF final prêt pour la présentation.
|
182 |
+
"""
|
183 |
+
compile_report_task.context = section_tasks
|
184 |
+
|
185 |
+
# Exécuter la tâche de compilation
|
186 |
+
result = await compile_report_task.execute(context=section_outputs)
|
187 |
+
return result
|