mirror of
https://github.com/msoedov/agentic_security.git
synced 2026-07-18 08:57:19 +02:00
fix(add image and files to llm spec):
This commit is contained in:
@@ -2,8 +2,7 @@ import httpx
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class InvalidHTTPSpecError(Exception):
|
class InvalidHTTPSpecError(Exception): ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class LLMSpec(BaseModel):
|
class LLMSpec(BaseModel):
|
||||||
@@ -11,6 +10,8 @@ class LLMSpec(BaseModel):
|
|||||||
url: str
|
url: str
|
||||||
headers: dict
|
headers: dict
|
||||||
body: str
|
body: str
|
||||||
|
has_files: bool = False
|
||||||
|
has_image: bool = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_string(cls, http_spec: str):
|
def from_string(cls, http_spec: str):
|
||||||
@@ -19,20 +20,29 @@ class LLMSpec(BaseModel):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise InvalidHTTPSpecError(f"Failed to parse HTTP spec: {e}") from e
|
raise InvalidHTTPSpecError(f"Failed to parse HTTP spec: {e}") from e
|
||||||
|
|
||||||
# TODO: add support of
|
async def _probe_with_files(self, files):
|
||||||
"""
|
async with httpx.AsyncClient() as client:
|
||||||
POST https://api.groq.com/openai/v1/audio/transcriptions
|
response = await client.request(
|
||||||
Authorization: Bearer $GROQ_API_KEY
|
method=self.method,
|
||||||
Content-Type: multipart/form-data
|
url=self.url,
|
||||||
|
headers=self.headers,
|
||||||
|
files=files,
|
||||||
|
timeout=(30, 90),
|
||||||
|
)
|
||||||
|
|
||||||
{
|
return response
|
||||||
"file": "@./sample_audio.m4a",
|
|
||||||
"model": "whisper-large-v3"
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# TODO: add support of BASE64 image encoding
|
def validate(self, prompt, encoded_image, files) -> None:
|
||||||
async def probe(self, prompt: str) -> httpx.Response:
|
if self.has_files and not files:
|
||||||
|
raise ValueError("Files are required for this request.")
|
||||||
|
|
||||||
|
if self.has_image:
|
||||||
|
if not encoded_image:
|
||||||
|
raise ValueError("An image is required for this request.")
|
||||||
|
|
||||||
|
async def probe(
|
||||||
|
self, prompt: str, encoded_image: str = "", files={}
|
||||||
|
) -> httpx.Response:
|
||||||
"""Sends an HTTP request using the `httpx` library.
|
"""Sends an HTTP request using the `httpx` library.
|
||||||
|
|
||||||
Replaces a placeholder in the request body with a provided prompt and returns the response.
|
Replaces a placeholder in the request body with a provided prompt and returns the response.
|
||||||
@@ -43,14 +53,19 @@ Content-Type: multipart/form-data
|
|||||||
Returns:
|
Returns:
|
||||||
httpx.Response: The response object containing the result of the HTTP request.
|
httpx.Response: The response object containing the result of the HTTP request.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.validate(prompt, encoded_image, files)
|
||||||
|
|
||||||
|
if files:
|
||||||
|
return await self._probe_with_files(files)
|
||||||
|
content = self.body.replace("<<PROMPT>>", escape_special_chars_for_json(prompt))
|
||||||
|
content = content.replace("<<BASE64_IMAGE>>", encoded_image)
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
response = await client.request(
|
response = await client.request(
|
||||||
method=self.method,
|
method=self.method,
|
||||||
url=self.url,
|
url=self.url,
|
||||||
headers=self.headers,
|
headers=self.headers,
|
||||||
content=self.body.replace(
|
content=content,
|
||||||
"<<PROMPT>>", escape_special_chars_for_json(prompt)
|
|
||||||
),
|
|
||||||
timeout=(30, 90),
|
timeout=(30, 90),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,8 +106,16 @@ def parse_http_spec(http_spec: str) -> LLMSpec:
|
|||||||
headers[key] = value
|
headers[key] = value
|
||||||
else:
|
else:
|
||||||
body += line
|
body += line
|
||||||
|
has_files = "multipart/form-data" in headers.get("Content-Type", "")
|
||||||
return LLMSpec(method=method, url=url, headers=headers, body=body)
|
has_image = "<<BASE64_IMAGE>>" in body
|
||||||
|
return LLMSpec(
|
||||||
|
method=method,
|
||||||
|
url=url,
|
||||||
|
headers=headers,
|
||||||
|
body=body,
|
||||||
|
has_files=has_files,
|
||||||
|
has_image=has_image,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def escape_special_chars_for_json(prompt: str) -> str:
|
def escape_special_chars_for_json(prompt: str) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user