update README and format code

This commit is contained in:
liangxinbing 2025-03-11 23:07:31 +08:00
parent 737abe4f90
commit 487b44fda8
7 changed files with 85 additions and 56 deletions

View File

@ -143,6 +143,9 @@ Join our networking group on Feishu and share your experience with other develop
Thanks to [anthropic-computer-use](https://github.com/anthropics/anthropic-quickstarts/tree/main/computer-use-demo)
and [browser-use](https://github.com/browser-use/browser-use) for providing basic support for this project!
Additionally, we are grateful to [AAAJ](https://github.com/metauto-ai/agent-as-a-judge)
and [MetaGPT](https://github.com/mannaandpoem/MetaGPT).
OpenManus is built by contributors from MetaGPT. Huge thanks to this agent community!
## Cite

View File

@ -145,4 +145,7 @@ python run_flow.py
特别感谢 [anthropic-computer-use](https://github.com/anthropics/anthropic-quickstarts/tree/main/computer-use-demo)
和 [browser-use](https://github.com/browser-use/browser-use) 为本项目提供的基础支持!
此外,我们感谢 [AAAJ](https://github.com/metauto-ai/agent-as-a-judge)
和 [MetaGPT](https://github.com/mannaandpoem/MetaGPT).
OpenManus 由 MetaGPT 社区的贡献者共同构建,感谢这个充满活力的智能体开发者社区!

View File

@ -1,6 +1,6 @@
from typing import Dict, List, Literal, Optional, Union, Tuple, Any
import os
import base64
import os
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
import litellm
from litellm import completion, completion_cost
@ -9,12 +9,17 @@ from litellm.exceptions import (
RateLimitError,
ServiceUnavailableError,
)
from tenacity import retry, stop_after_attempt, wait_random_exponential, retry_if_exception_type
from tenacity import (
retry,
retry_if_exception_type,
stop_after_attempt,
wait_random_exponential,
)
from app.config import LLMSettings, config
from app.llm.cost import Cost
from app.logger import logger
from app.schema import Message
from app.llm.cost import Cost
class LLM:
@ -32,7 +37,9 @@ class LLM:
def __init__(
self, config_name: str = "default", llm_config: Optional[LLMSettings] = None
):
if not hasattr(self, "initialized"): # Only initialize if not already initialized
if not hasattr(
self, "initialized"
): # Only initialize if not already initialized
llm_config = llm_config or config.llm
llm_config = llm_config.get(config_name, llm_config["default"])
@ -41,7 +48,9 @@ class LLM:
self.temperature = getattr(llm_config, "temperature", 0.7)
self.top_p = getattr(llm_config, "top_p", 0.9)
self.api_type = getattr(llm_config, "api_type", "openai")
self.api_key = getattr(llm_config, "api_key", os.environ.get("OPENAI_API_KEY", ""))
self.api_key = getattr(
llm_config, "api_key", os.environ.get("OPENAI_API_KEY", "")
)
self.api_version = getattr(llm_config, "api_version", "")
self.base_url = getattr(llm_config, "base_url", "https://api.openai.com/v1")
self.timeout = getattr(llm_config, "timeout", 60)
@ -183,7 +192,9 @@ class LLM:
# Add the cost to our tracker
if cost > 0:
self.cost_tracker.add_cost(cost)
logger.info(f"Added cost: ${cost:.6f}, Total: ${self.cost_tracker.accumulated_cost:.6f}")
logger.info(
f"Added cost: ${cost:.6f}, Total: ${self.cost_tracker.accumulated_cost:.6f}"
)
return cost
except Exception as e:
@ -202,7 +213,9 @@ class LLM:
substring in self.base_url
for substring in ["localhost", "127.0.0.1", "0.0.0.0"]
)
if self.model and (self.model.startswith("ollama") or "local" in self.model.lower()):
if self.model and (
self.model.startswith("ollama") or "local" in self.model.lower()
):
return True
return False
@ -234,7 +247,9 @@ class LLM:
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode("utf-8")
def prepare_messages(self, text: str, image_path: Optional[str] = None) -> List[dict]:
def prepare_messages(
self, text: str, image_path: Optional[str] = None
) -> List[dict]:
"""
Prepare messages for completion, including multimodal content if needed.
@ -257,7 +272,9 @@ class LLM:
]
return messages
def do_multimodal_completion(self, text: str, image_path: str) -> Tuple[Any, float, float]:
def do_multimodal_completion(
self, text: str, image_path: str
) -> Tuple[Any, float, float]:
"""
Perform a multimodal completion with text and image.
@ -342,7 +359,7 @@ class LLM:
print(chunk_message, end="", flush=True)
# For streaming responses, cost is calculated on the last chunk
if hasattr(chunk, 'usage') and chunk.usage:
if hasattr(chunk, "usage") and chunk.usage:
self._calculate_and_track_cost(chunk)
print() # Newline after streaming
@ -484,6 +501,7 @@ class LLM:
if __name__ == "__main__":
# Load environment variables if needed
from dotenv import load_dotenv
load_dotenv()
# Create LLM instance
@ -501,5 +519,7 @@ if __name__ == "__main__":
multimodal_response, mm_cost, mm_total_cost = llm.do_multimodal_completion(
"What's in this image?", image_path
)
print(f"Multimodal response: {multimodal_response['choices'][0]['message']['content']}")
print(
f"Multimodal response: {multimodal_response['choices'][0]['message']['content']}"
)
print(f"Cost: ${mm_cost:.6f}, Total cost: ${mm_total_cost:.6f}")

View File

@ -11,6 +11,7 @@ from pydantic_core.core_schema import ValidationInfo
from app.tool.base import BaseTool, ToolResult
MAX_LENGTH = 2000
_BROWSER_DESCRIPTION = """
@ -181,7 +182,9 @@ class BrowserUseTool(BaseTool):
elif action == "get_html":
html = await context.get_page_html()
truncated = html[:MAX_LENGTH] + "..." if len(html) > MAX_LENGTH else html
truncated = (
html[:MAX_LENGTH] + "..." if len(html) > MAX_LENGTH else html
)
return ToolResult(output=truncated)
elif action == "get_text":