Skip to content

Commit 36b2156

Browse files
Martin GuittenyGuittenyMartin
authored andcommitted
⚡️(summary) change formating from prompt to response_format
Add ability to use response_format in call function in order to have better result with albert-large model Use reponse_format for next steps and plan generation
1 parent ec94d61 commit 36b2156

3 files changed

Lines changed: 104 additions & 24 deletions

File tree

env.d/development/summary.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ WHISPERX_DEFAULT_LANGUAGE="fr"
1515

1616
LLM_BASE_URL="https://configure-your-url.com"
1717
LLM_API_KEY="dev-apikey"
18-
LLM_MODEL="Qwen/Qwen2.5-Coder-32B-Instruct-AWQ"
18+
LLM_MODEL="albert-large"
1919

2020
WEBHOOK_API_TOKEN="secret"
2121
WEBHOOK_URL="https://configure-your-url.com"

src/summary/summary/core/celery_worker.py

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import tempfile
88
import time
99
from pathlib import Path
10-
from typing import Optional
10+
from typing import Any, Mapping, Optional
1111

1212
import openai
1313
import sentry_sdk
@@ -22,6 +22,8 @@
2222
from summary.core.analytics import MetadataManager, get_analytics
2323
from summary.core.config import get_settings
2424
from summary.core.prompt import (
25+
FORMAT_NEXT_STEPS,
26+
FORMAT_PLAN,
2527
PROMPT_SYSTEM_CLEANING,
2628
PROMPT_SYSTEM_NEXT_STEP,
2729
PROMPT_SYSTEM_PART,
@@ -115,24 +117,53 @@ def __init__(self):
115117
base_url=settings.llm_base_url, api_key=settings.llm_api_key
116118
)
117119

118-
def call(self, system_prompt: str, user_prompt: str):
120+
def call(
121+
self,
122+
system_prompt: str,
123+
user_prompt: str,
124+
response_format: Optional[Mapping[str, Any]] = None,
125+
):
119126
"""Call the LLM service.
120127
121128
Takes a system prompt and a user prompt, and returns the LLM's response
122129
Returns None if the call fails.
123130
"""
124131
try:
125-
response = self._client.chat.completions.create(
126-
model=settings.llm_model,
127-
messages=[
132+
params: dict[str, Any] = {
133+
"model": settings.llm_model,
134+
"messages": [
128135
{"role": "system", "content": system_prompt},
129136
{"role": "user", "content": user_prompt},
130137
],
131-
)
138+
}
139+
if response_format is not None:
140+
params["response_format"] = response_format
141+
142+
response = self._client.chat.completions.create(**params)
143+
132144
return response.choices[0].message.content
145+
133146
except Exception as e:
134-
logger.error("LLM call failed: %s", e)
135-
raise LLMException("LLM call failed.") from e
147+
logger.exception("LLM call failed: %s", e)
148+
raise LLMException("LLM call failed: {e}") from e
149+
150+
151+
def format_actions(llm_output: dict) -> str:
152+
"""Format the actions from the LLM output into a markdown list.
153+
154+
fomat:
155+
- [ ] Action title Assignée à : assignee1, assignee2, Échéance : due_date
156+
"""
157+
lines = []
158+
for action in llm_output.get("actions", []):
159+
title = action.get("title", "").strip()
160+
assignees = ", ".join(action.get("assignees", [])) or "-"
161+
due_date = action.get("due_date") or "-"
162+
line = f"- [ ] {title} Assignée à : {assignees}, Échéance : {due_date}"
163+
lines.append(line)
164+
if lines:
165+
return "### Prochaines étapes\n\n" + "\n".join(lines)
166+
return ""
136167

137168

138169
def format_segments(transcription_data):
@@ -359,13 +390,14 @@ def summarize_transcription(self, transcript: str, email: str, sub: str, title:
359390

360391
logger.info("TLDR generated")
361392

362-
parts = llm_service.call(PROMPT_SYSTEM_PLAN, transcript)
393+
parts = llm_service.call(
394+
PROMPT_SYSTEM_PLAN, transcript, response_format=FORMAT_PLAN
395+
)
363396
logger.info("Plan generated")
364397

365-
parts = parts.split("\n")
366-
parts = [x for x in parts if x.strip() != ""]
367-
logger.info("Empty parts removed")
368-
398+
res = json.loads(parts)
399+
parts = res.get("titles", [])
400+
logger.info("Parts to summarize: %s", parts)
369401
parts_summarized = []
370402
for part in parts:
371403
prompt_user_part = PROMPT_USER_PART.format(part=part, transcript=transcript)
@@ -376,7 +408,12 @@ def summarize_transcription(self, transcript: str, email: str, sub: str, title:
376408

377409
raw_summary = "\n\n".join(parts_summarized)
378410

379-
next_steps = llm_service.call(PROMPT_SYSTEM_NEXT_STEP, transcript)
411+
next_steps = llm_service.call(
412+
PROMPT_SYSTEM_NEXT_STEP, transcript, response_format=FORMAT_NEXT_STEPS
413+
)
414+
415+
next_steps = format_actions(json.loads(next_steps))
416+
380417
logger.info("Next steps generated")
381418

382419
cleaned_summary = llm_service.call(PROMPT_SYSTEM_CLEANING, raw_summary)

src/summary/summary/core/prompt.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@
44
### Résumé TL;DR
55
[Résumé concis et structuré]"""
66

7-
PROMPT_SYSTEM_PLAN = """Ta tâche est de diviser le contenu du transcript en sujets concrets correspondant aux grands axes discutés durant la réunion. Ne crée pas de catégories génériques. Les titres doivent être courts, précis et représentatifs des échanges. Veille à ce que chaque sujet soit distinct et qu’aucun thème ne soit répété. Tu te limiteras à 5 ou 6 sujets maximum.
8-
L'introduction, ordre du jour, conclusion, etc. seront rajoutés a posteriori. Tu répondras dans le format suivant sans rien ajouter d'autre:
9-
"Titre du sujet 1
10-
Titre du sujet 2
11-
Titre du sujet 3
12-
..."
7+
PROMPT_SYSTEM_PLAN = """Ta tâche est de diviser le contenu du transcript en sujets concrets correspondant aux grands axes discutés durant la réunion. Ne crée pas de catégories génériques. Les titres doivent être courts, précis et représentatifs des échanges. Veille à ce que chaque sujet soit distinct et qu’aucun thème ne soit répété. Tu te limiteras à 5 ou 6 sujets maximum.
8+
L'introduction, ordre du jour, conclusion, etc. seront rajoutés a posteriori. Si il n'y a pas de sujets clairs, réponds "Général".
139
"""
1410

1511
PROMPT_SYSTEM_PART = """Tu es un agent dont le rôle est de créer une partie du résumé d'un compte rendu de réunion. Tu utiliseras un style synthétique, administratif, à la troisième personne, sans affect. Tu recevras en entrée le transcript, et le titre du sujet correspondant. Ta tâche est de rédiger un résumé concis de cette partie et uniquement cette partie, en te concentrant uniquement sur les informations essentielles et pertinentes. Le résumé de chaque partie doit tenir en 4 à 6 phrases maximum, sans entrer dans les détails mineurs. Tu répondras dans le format suivant :
@@ -23,6 +19,53 @@
2319

2420
PROMPT_SYSTEM_CLEANING = """Tu es un agent dont le rôle est de nettoyer un résumé de compte rendu de réunion. Tu recevras en entrée le résumé brut, potentiellement avec des erreurs de formatage, des incohérences ou des redondances. Ta tâche est de corriger les erreurs de formatage, d'améliorer la clarté et la cohérence du texte, et de t'assurer que le résumé est bien structuré et facile à lire. Ton but principal est de retirer les redondances et les répétitions. Assure la cohérence entre les titres et homogénéise le style d’écriture entre les parties. Supprime les doublons d’informations entre les parties si présents. Si certaines parties sont plus secondaires, tu peux les fusionner ou les réduire en 1 à 2 phrases. Mets en avant les points centraux qui ont fait l’objet de décisions ou d’actions. Tu répondras uniquement avec le résumé sans rien ajouter d'autre"""
2521

26-
PROMPT_SYSTEM_NEXT_STEP = """Tu es un agent dont le rôle est d'extraire les prochaines étapes d'un transcript de réunion. Tu utiliseras un style synthétique, administratif, à la troisième personne, sans affect. Tu recevras en entrée le transcript. Ta tâche est d'identifier et de lister toutes les actions à entreprendre, en indiquant la ou les personnes assignées et en précisant les échéances si elles sont mentionnées. Ne retiens que les actions concrètes et à venir. Ignore les remarques générales ou les constats sans suite. Les actions doivent suivre ce format strict :
27-
### Prochaines étapes
28-
- [ ] [Action à effectuer] Assignée à : [Nom], Échéance : [Date si mentionnée]"""
22+
PROMPT_SYSTEM_NEXT_STEP = """Tu es un agent dont le rôle est d'extraire les prochaines étapes d'un transcript de réunion. Tu utiliseras un style synthétique, administratif, à la troisième personne, sans affect. Tu recevras en entrée le transcript. Ta tâche est d'identifier et de lister toutes les actions à entreprendre, en indiquant la ou les personnes assignées et en précisant les échéances si elles sont mentionnées. Ne retiens que les actions concrètes et à venir. Ignore les remarques générales ou les constats sans suite."""
23+
24+
FORMAT_NEXT_STEPS = {
25+
"type": "json_schema",
26+
"json_schema": {
27+
"name": "actions",
28+
"schema": {
29+
"type": "object",
30+
"properties": {
31+
"actions": {
32+
"type": "array",
33+
"items": {
34+
"type": "object",
35+
"properties": {
36+
"title": {"type": "string"},
37+
"assignees": {
38+
"type": "array",
39+
"items": {"type": "string"},
40+
"description": "Noms des personnes assignées",
41+
},
42+
"due_date": {
43+
"type": "string",
44+
"description": "Date d'échéance si mentionnée (si l'année nest pas précisée, ne pas l'ajouter)",
45+
},
46+
},
47+
"required": ["title", "assignees"],
48+
"additionalProperties": False,
49+
},
50+
}
51+
},
52+
"required": ["actions"],
53+
"additionalProperties": False,
54+
},
55+
"strict": True,
56+
},
57+
}
58+
59+
FORMAT_PLAN = {
60+
"type": "json_schema",
61+
"json_schema": {
62+
"name": "Titles",
63+
"schema": {
64+
"type": "object",
65+
"properties": {"titles": {"type": "array", "items": {"type": "string"}}},
66+
"required": ["titles"],
67+
"additionalProperties": False,
68+
},
69+
"strict": True,
70+
},
71+
}

0 commit comments

Comments
 (0)