image input pipeline: content-hash cache, data-url vision, picture_edit real

This commit is contained in:
Oleksandr Kozachuk
2026-07-13 16:33:48 +02:00
parent 7e6eae10ee
commit e21c262299
8 changed files with 496 additions and 10 deletions
+27
View File
@@ -96,6 +96,10 @@ async def openai_image(client, *args, **kwargs):
return await client.images.generate(*args, **kwargs)
async def openai_image_edit(client, *args, **kwargs):
return await client.images.edit(*args, **kwargs)
class OpenAIResponder(AIResponder, LeonardoAIDrawMixIn):
def __init__(self, config: Dict[str, Any], channel: Optional[str] = None) -> None:
super().__init__(config, channel)
@@ -354,6 +358,29 @@ class OpenAIResponder(AIResponder, LeonardoAIDrawMixIn):
logging.debug(f"Full traceback: {traceback.format_exc()}")
return None, limit
async def edit_openai(self, description: str, paths: List[Any], count: int = 1) -> List[BytesIO]:
"""Edit/remix from cached inputs, ≤4 files (IMG-13)."""
if not self.ledger.budget_ok():
raise RuntimeError("daily budget exhausted - refusing image edit")
model = self.config.get("image-model", "gpt-image-2")
handles = [open(path, "rb") for path in paths[:4]]
try:
response = await openai_image_edit(
self.client,
model=model,
image=handles if len(handles) > 1 else handles[0],
prompt=description,
n=max(1, min(int(count), 4)),
size=self.config.get("image-size", "1024x1024"),
)
finally:
for handle in handles:
handle.close()
buffers = [BytesIO(base64.b64decode(item.b64_json)) for item in response.data]
self.ledger.add_images(len(buffers))
logging.info(f"edited {len(buffers)} image(s) on {model} from {len(handles)} input(s)")
return buffers
async def classify(self, message: Any, history_tail: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
"""~100-token reply/factual/emoji verdict on classifier-model (BEH-01/03)."""
if "classifier-model" not in self.config or not self.ledger.budget_ok():