Lucas ARRIESSE
commited on
Commit
·
2334311
1
Parent(s):
fb16ff6
Add search_solution/v2 endpoint
Browse files- app.py +67 -1
- prompts/search_solution.txt +7 -8
- prompts/search_solution_v2.txt +31 -0
- schemas.py +10 -1
app.py
CHANGED
@@ -4,7 +4,7 @@ import os
|
|
4 |
import sys
|
5 |
import uvicorn
|
6 |
from fastapi import APIRouter, FastAPI
|
7 |
-
from schemas import _RefinedSolutionModel, _SearchedSolutionModel, _SolutionCriticismOutput, CriticizeSolutionsRequest, CritiqueResponse, RequirementInfo, ReqGroupingCategory, ReqGroupingResponse, ReqGroupingRequest, _ReqGroupingCategory, _ReqGroupingOutput, SolutionCriticism, SolutionModel, SolutionSearchResponse
|
8 |
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
9 |
from litellm.router import Router
|
10 |
from dotenv import load_dotenv
|
@@ -178,6 +178,72 @@ async def search_solutions(params: ReqGroupingResponse) -> SolutionSearchRespons
|
|
178 |
return SolutionSearchResponse(solutions=final_solutions)
|
179 |
|
180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
@solution_router.post("/criticize_solution", response_model=CritiqueResponse)
|
182 |
async def criticize_solution(params: CriticizeSolutionsRequest) -> CritiqueResponse:
|
183 |
"""Criticize the challenges, weaknesses and limitations of the provided solutions."""
|
|
|
4 |
import sys
|
5 |
import uvicorn
|
6 |
from fastapi import APIRouter, FastAPI
|
7 |
+
from schemas import _RefinedSolutionModel, _SearchedSolutionModel, _SolutionCriticismOutput, CriticizeSolutionsRequest, CritiqueResponse, RequirementInfo, ReqGroupingCategory, ReqGroupingResponse, ReqGroupingRequest, _ReqGroupingCategory, _ReqGroupingOutput, SolutionCriticism, SolutionModel, SolutionSearchResponse, SolutionSearchV2Request
|
8 |
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
9 |
from litellm.router import Router
|
10 |
from dotenv import load_dotenv
|
|
|
178 |
return SolutionSearchResponse(solutions=final_solutions)
|
179 |
|
180 |
|
181 |
+
@solution_router.post("/search_solutions_gemini/v2", response_model=SolutionSearchResponse)
|
182 |
+
async def search_solutions(params: SolutionSearchV2Request) -> SolutionSearchResponse:
|
183 |
+
"""Searches solutions solving the given grouping params and respecting the user constraints using Gemini and grounded on google search"""
|
184 |
+
|
185 |
+
logging.info(f"Searching solutions for categories: {params.categories}")
|
186 |
+
|
187 |
+
async def _search_inner(cat: ReqGroupingCategory) -> SolutionModel:
|
188 |
+
# ================== generate the solution with web grounding
|
189 |
+
req_prompt = await prompt_env.get_template("search_solution_v2.txt").render_async(**{
|
190 |
+
"category": cat.model_dump(),
|
191 |
+
"user_constraints": params.user_constraints,
|
192 |
+
})
|
193 |
+
|
194 |
+
# generate the completion in non-structured mode.
|
195 |
+
# the googleSearch tool enables grounding gemini with google search
|
196 |
+
# this also forces gemini to perform a tool call
|
197 |
+
req_completion = await llm_router.acompletion(model="chat", messages=[
|
198 |
+
{"role": "user", "content": req_prompt}
|
199 |
+
], tools=[{"googleSearch": {}}], tool_choice="required")
|
200 |
+
|
201 |
+
# ==================== structure the solution as a json ===================================
|
202 |
+
|
203 |
+
structured_prompt = await prompt_env.get_template("structure_solution.txt").render_async(**{
|
204 |
+
"solution": req_completion.choices[0].message.content,
|
205 |
+
"response_schema": _SearchedSolutionModel.model_json_schema()
|
206 |
+
})
|
207 |
+
|
208 |
+
structured_completion = await llm_router.acompletion(model="chat", messages=[
|
209 |
+
{"role": "user", "content": structured_prompt}
|
210 |
+
], response_format=_SearchedSolutionModel)
|
211 |
+
solution_model = _SearchedSolutionModel.model_validate_json(
|
212 |
+
structured_completion.choices[0].message.content)
|
213 |
+
|
214 |
+
# ======================== build the final solution object ================================
|
215 |
+
|
216 |
+
sources_metadata = []
|
217 |
+
# extract the source metadata from the search items, if gemini actually called the tools to search .... and didn't hallucinated
|
218 |
+
try:
|
219 |
+
sources_metadata.extend([{"name": a["web"]["title"], "url": a["web"]["uri"]}
|
220 |
+
for a in req_completion["vertex_ai_grounding_metadata"][0]['groundingChunks']])
|
221 |
+
except KeyError as ke:
|
222 |
+
pass
|
223 |
+
|
224 |
+
final_sol = SolutionModel(
|
225 |
+
Context="",
|
226 |
+
Requirements=[
|
227 |
+
cat.requirements[i].requirement for i in solution_model.requirement_ids
|
228 |
+
],
|
229 |
+
Problem_Description=solution_model.problem_description,
|
230 |
+
Solution_Description=solution_model.solution_description,
|
231 |
+
References=sources_metadata,
|
232 |
+
Category_Id=cat.id,
|
233 |
+
)
|
234 |
+
return final_sol
|
235 |
+
|
236 |
+
solutions = await asyncio.gather(*[retry_until(_search_inner, cat, lambda v: len(v.References) > 0, 2) for cat in params.categories], return_exceptions=True)
|
237 |
+
logging.info(solutions)
|
238 |
+
final_solutions = [
|
239 |
+
sol for sol in solutions if not isinstance(sol, Exception)]
|
240 |
+
|
241 |
+
return SolutionSearchResponse(solutions=final_solutions)
|
242 |
+
|
243 |
+
|
244 |
+
# =================================================================================================================
|
245 |
+
|
246 |
+
|
247 |
@solution_router.post("/criticize_solution", response_model=CritiqueResponse)
|
248 |
async def criticize_solution(params: CriticizeSolutionsRequest) -> CritiqueResponse:
|
249 |
"""Criticize the challenges, weaknesses and limitations of the provided solutions."""
|
prompts/search_solution.txt
CHANGED
@@ -4,6 +4,12 @@ Your task is to create a solution that should cover the maximum possible of requ
|
|
4 |
The solution should be composed of multiple mechanisms, that are defined as processes, methods, or sequences of steps using a technology that explain how something works or achieves its requirements.
|
5 |
You may for that search mechanisms for the different requirements.
|
6 |
**Please actually make searches and do not simulate them.**
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
</task>
|
8 |
|
9 |
Here is the category item and the associated requirements:
|
@@ -14,11 +20,4 @@ Requirements:
|
|
14 |
{% for req in category["requirements"] -%}
|
15 |
- {{loop.index0}} {{req["requirement"]}}
|
16 |
{% endfor -%}
|
17 |
-
</requirements>
|
18 |
-
|
19 |
-
<additional_instructions>
|
20 |
-
- The solution must aim to maximize requirement satisfaction while respecting the context.
|
21 |
-
- Provide a list of requirements addressed by the solution (provide only the requirement IDs)
|
22 |
-
- Please also detail each mechanism and how they work in the final solution description.
|
23 |
-
- Please describe the solution description using markdown in a consistent format.
|
24 |
-
</additional_instructions>
|
|
|
4 |
The solution should be composed of multiple mechanisms, that are defined as processes, methods, or sequences of steps using a technology that explain how something works or achieves its requirements.
|
5 |
You may for that search mechanisms for the different requirements.
|
6 |
**Please actually make searches and do not simulate them.**
|
7 |
+
|
8 |
+
You must aim for the following goals:
|
9 |
+
- The solution must aim to maximize requirement satisfaction while respecting the context.
|
10 |
+
- Provide a list of requirements addressed by the solution (provide only the requirement IDs)
|
11 |
+
- Please also detail each mechanism and how they work in the final solution description.
|
12 |
+
- Please describe the solution description using markdown in a consistent format.
|
13 |
</task>
|
14 |
|
15 |
Here is the category item and the associated requirements:
|
|
|
20 |
{% for req in category["requirements"] -%}
|
21 |
- {{loop.index0}} {{req["requirement"]}}
|
22 |
{% endfor -%}
|
23 |
+
</requirements>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prompts/search_solution_v2.txt
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<role>You are an expert system designer</role>
|
2 |
+
<task>
|
3 |
+
Your task is to create a solution that should cover the maximum possible of requirements at once.
|
4 |
+
The solution should be composed of multiple mechanisms, that are defined as processes, methods, or sequences of steps using a technology that explain how something works or achieves its requirements.
|
5 |
+
You may for that search mechanisms for the different requirements.
|
6 |
+
|
7 |
+
**Please actually make searches and do not simulate them.**
|
8 |
+
|
9 |
+
You must aim for the following goals:
|
10 |
+
- The solution must aim to maximize requirement satisfaction while respecting the context.
|
11 |
+
- Provide a list of requirements addressed by the solution (provide only the requirement IDs)
|
12 |
+
- Please also detail each mechanism and how they work in the final solution description.
|
13 |
+
- Please describe the solution description using markdown in a consistent format.
|
14 |
+
</task>
|
15 |
+
|
16 |
+
Here is the category item and the associated requirements:
|
17 |
+
<requirements>
|
18 |
+
Category Title: {{category["title"]}}
|
19 |
+
Context: {{category["requirements"][0]["context"]}}
|
20 |
+
Requirements:
|
21 |
+
{% for req in category["requirements"] -%}
|
22 |
+
- {{loop.index0}} {{req["requirement"]}}
|
23 |
+
{% endfor -%}
|
24 |
+
</requirements>
|
25 |
+
|
26 |
+
{% if user_constraints is not none %}
|
27 |
+
Here are additional user constraints the solution must respect:
|
28 |
+
<user_constraints>
|
29 |
+
{{user_constraints}}
|
30 |
+
</user_constraints>
|
31 |
+
{% endif %}
|
schemas.py
CHANGED
@@ -114,6 +114,15 @@ class SolutionSearchResponse(BaseModel):
|
|
114 |
"""Response model for solution search"""
|
115 |
solutions: list[SolutionModel]
|
116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
|
118 |
# ================================================================= refine solution endpoints
|
119 |
|
@@ -124,4 +133,4 @@ class _RefinedSolutionModel(BaseModel):
|
|
124 |
problem_description: str = Field(...,
|
125 |
description="New description of the problem being solved.")
|
126 |
solution_description: str = Field(...,
|
127 |
-
description="New detailed description of the solution.")
|
|
|
114 |
"""Response model for solution search"""
|
115 |
solutions: list[SolutionModel]
|
116 |
|
117 |
+
# ================================================================ search solution endpoint v2
|
118 |
+
|
119 |
+
|
120 |
+
class SolutionSearchV2Request(BaseModel):
|
121 |
+
"""Response of a requirement grouping call."""
|
122 |
+
categories: List[ReqGroupingCategory]
|
123 |
+
user_constraints: Optional[str] = Field(
|
124 |
+
default=None, description="Additional user constraints to respect when generating the solutions.")
|
125 |
+
|
126 |
|
127 |
# ================================================================= refine solution endpoints
|
128 |
|
|
|
133 |
problem_description: str = Field(...,
|
134 |
description="New description of the problem being solved.")
|
135 |
solution_description: str = Field(...,
|
136 |
+
description="New detailed description of the solution.")
|