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.

application.py 5.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/env python
  2. import asyncio
  3. import logging
  4. import os
  5. from contextlib import asynccontextmanager # noqa: E402
  6. from datetime import datetime
  7. from typing import AsyncIterator, Dict, Iterator, List
  8. import uvicorn # noqa: E402
  9. from fastapi import FastAPI # noqa: E402
  10. from fastapi.responses import HTMLResponse # noqa: E402
  11. from websockets.sync.client import connect as ws_connect
  12. import autogen
  13. from autogen.io.websockets import IOWebsockets
  14. PORT = 8000
  15. # logger = getLogger(__name__)
  16. logger = logging.getLogger("uvicorn")
  17. def _get_config_list() -> List[Dict[str, str]]:
  18. """Get a list of config dictionaries with API keys for OpenAI and Azure OpenAI.
  19. Returns:
  20. List[Dict[str, str]]: A list of config dictionaries with API keys.
  21. Example:
  22. >>> _get_config_list()
  23. [
  24. {
  25. 'model': 'gpt-35-turbo-16k',
  26. 'api_key': '0123456789abcdef0123456789abcdef',
  27. 'base_url': 'https://my-deployment.openai.azure.com/',
  28. 'api_type': 'azure',
  29. 'api_version': '2024-02-01',
  30. },
  31. {
  32. 'model': 'gpt-4',
  33. 'api_key': '0123456789abcdef0123456789abcdef',
  34. },
  35. ]
  36. """
  37. # can use both OpenAI and Azure OpenAI API keys
  38. config_list = [
  39. {
  40. "model": "gpt-35-turbo-16k",
  41. "api_key": os.environ.get("AZURE_OPENAI_API_KEY"),
  42. "base_url": os.environ.get("AZURE_OPENAI_BASE_URL"),
  43. "api_type": "azure",
  44. "api_version": os.environ.get("AZURE_OPENAI_API_VERSION"),
  45. },
  46. {
  47. "model": "gpt-4",
  48. "api_key": os.environ.get("OPENAI_API_KEY"),
  49. },
  50. ]
  51. # filter out configs with no API key
  52. config_list = [llm_config for llm_config in config_list if llm_config["api_key"] is not None]
  53. if not config_list:
  54. raise ValueError(
  55. "No API keys found. Please set either AZURE_OPENAI_API_KEY or OPENAI_API_KEY environment variable."
  56. )
  57. return config_list
  58. def on_connect(iostream: IOWebsockets) -> None:
  59. logger.info(f"on_connect(): Connected to client using IOWebsockets {iostream}")
  60. logger.info("on_connect(): Receiving message from client.")
  61. # get the initial message from the client
  62. initial_msg = iostream.input()
  63. # instantiate an agent named "chatbot"
  64. agent = autogen.ConversableAgent(
  65. name="chatbot",
  66. system_message="Complete a task given to you and reply TERMINATE when the task is done. If asked about the weather, use tool weather_forecast(city) to get the weather forecast for a city.",
  67. llm_config={
  68. "config_list": _get_config_list(),
  69. "stream": True,
  70. },
  71. )
  72. # create a UserProxyAgent instance named "user_proxy"
  73. user_proxy = autogen.UserProxyAgent(
  74. name="user_proxy",
  75. system_message="A proxy for the user.",
  76. is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("TERMINATE"),
  77. human_input_mode="NEVER",
  78. max_consecutive_auto_reply=10,
  79. code_execution_config=False,
  80. )
  81. # register the weather_forecast function
  82. def weather_forecast(city: str) -> str:
  83. return f"The weather forecast for {city} at {datetime.now()} is sunny."
  84. autogen.register_function(
  85. weather_forecast, caller=agent, executor=user_proxy, description="Weather forecast for a city"
  86. )
  87. # instantiate a chat
  88. logger.info(
  89. f"on_connect(): Initiating chat with the agent ({agent.name}) and the user proxy ({user_proxy.name}) using the message '{initial_msg}'",
  90. )
  91. user_proxy.initiate_chat( # noqa: F704
  92. agent,
  93. message=initial_msg,
  94. )
  95. logger.info("on_connect(): Finished the task successfully.")
  96. html = """
  97. <!DOCTYPE html>
  98. <html>
  99. <head>
  100. <title>Autogen websocket test</title>
  101. </head>
  102. <body>
  103. <h1>WebSocket Chat</h1>
  104. <form action="" onsubmit="sendMessage(event)">
  105. <input type="text" id="messageText" autocomplete="off" value="Write a poem about the current wearther in Paris or London, you choose."/>
  106. <button>Send</button>
  107. </form>
  108. <ul id='messages'>
  109. </ul>
  110. <script>
  111. var ws = new WebSocket("ws://localhost:8080/ws");
  112. ws.onmessage = function(event) {
  113. var messages = document.getElementById('messages')
  114. var message = document.createElement('li')
  115. var content = document.createTextNode(event.data)
  116. message.appendChild(content)
  117. messages.appendChild(message)
  118. };
  119. function sendMessage(event) {
  120. var input = document.getElementById("messageText")
  121. ws.send(input.value)
  122. input.value = ''
  123. event.preventDefault()
  124. }
  125. </script>
  126. </body>
  127. </html>
  128. """
  129. @asynccontextmanager
  130. async def run_websocket_server(app: FastAPI) -> AsyncIterator[None]:
  131. with IOWebsockets.run_server_in_thread(on_connect=on_connect, port=8080) as uri:
  132. logger.info(f"Websocket server started at {uri}.")
  133. yield
  134. app = FastAPI(lifespan=run_websocket_server)
  135. @app.get("/")
  136. async def get() -> HTMLResponse:
  137. return HTMLResponse(html)
  138. async def start_uvicorn() -> None:
  139. config = uvicorn.Config(app)
  140. server = uvicorn.Server(config)
  141. try:
  142. await server.serve() # noqa: F704
  143. except KeyboardInterrupt:
  144. logger.info("Shutting down server")
  145. if __name__ == "__main__":
  146. # set the log level to INFO
  147. logger.setLevel("INFO")
  148. asyncio.run(start_uvicorn())