You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

_image_generation_agent.py 3.0 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. from typing import Literal
  2. import openai
  3. from agnext.components import (
  4. DefaultTopicId,
  5. Image,
  6. RoutedAgent,
  7. message_handler,
  8. )
  9. from agnext.components.memory import ChatMemory
  10. from agnext.core import CancellationToken, MessageContext
  11. from ..types import (
  12. Message,
  13. MultiModalMessage,
  14. PublishNow,
  15. Reset,
  16. TextMessage,
  17. )
  18. class ImageGenerationAgent(RoutedAgent):
  19. """An agent that generates images using DALL-E models. It publishes the
  20. generated images as MultiModalMessage.
  21. Args:
  22. description (str): The description of the agent.
  23. memory (ChatMemory[Message]): The memory to store and retrieve messages.
  24. client (openai.AsyncClient): The client to use for the OpenAI API.
  25. model (Literal["dall-e-2", "dall-e-3"], optional): The DALL-E model to use. Defaults to "dall-e-2".
  26. """
  27. def __init__(
  28. self,
  29. description: str,
  30. memory: ChatMemory[Message],
  31. client: openai.AsyncClient,
  32. model: Literal["dall-e-2", "dall-e-3"] = "dall-e-2",
  33. ):
  34. super().__init__(description)
  35. self._client = client
  36. self._model = model
  37. self._memory = memory
  38. @message_handler
  39. async def on_text_message(self, message: TextMessage, ctx: MessageContext) -> None:
  40. """Handle a text message. This method adds the message to the memory."""
  41. await self._memory.add_message(message)
  42. @message_handler
  43. async def on_reset(self, message: Reset, ctx: MessageContext) -> None:
  44. await self._memory.clear()
  45. @message_handler
  46. async def on_publish_now(self, message: PublishNow, ctx: MessageContext) -> None:
  47. """Handle a publish now message. This method generates an image using a DALL-E model with
  48. a prompt. The prompt is a concatenation of all TextMessages in the memory. The generated
  49. image is published as a MultiModalMessage."""
  50. response = await self._generate_response(ctx.cancellation_token)
  51. await self.publish_message(response, topic_id=DefaultTopicId())
  52. async def _generate_response(self, cancellation_token: CancellationToken) -> MultiModalMessage:
  53. messages = await self._memory.get_messages()
  54. if len(messages) == 0:
  55. return MultiModalMessage(
  56. content=["I need more information to generate an image."], source=self.metadata["type"]
  57. )
  58. prompt = ""
  59. for m in messages:
  60. assert isinstance(m, TextMessage)
  61. prompt += m.content + "\n"
  62. prompt.strip()
  63. response = await self._client.images.generate(model=self._model, prompt=prompt, response_format="b64_json")
  64. assert len(response.data) > 0 and response.data[0].b64_json is not None
  65. # Create a MultiModalMessage with the image.
  66. image = Image.from_base64(response.data[0].b64_json)
  67. multi_modal_message = MultiModalMessage(content=[image], source=self.metadata["type"])
  68. return multi_modal_message