diff --git a/.github/workflows/fulltest.yaml b/.github/workflows/fulltest.yaml index f5c6049e1..70c800481 100644 --- a/.github/workflows/fulltest.yaml +++ b/.github/workflows/fulltest.yaml @@ -54,7 +54,6 @@ jobs: export ALLOW_OPENAI_API_CALL=0 echo "${{ secrets.METAGPT_KEY_YAML }}" | base64 -d > config/key.yaml mkdir -p ~/.metagpt && echo "${{ secrets.METAGPT_CONFIG2_YAML }}" | base64 -d > ~/.metagpt/config2.yaml - echo "${{ secrets.SPARK_YAML }}" | base64 -d > ~/.metagpt/spark.yaml pytest tests/ --doctest-modules --cov=./metagpt/ --cov-report=xml:cov.xml --cov-report=html:htmlcov --durations=20 | tee unittest.txt - name: Show coverage report run: | diff --git a/.github/workflows/unittest.yaml b/.github/workflows/unittest.yaml index 2e7e3ce2b..afa9faba7 100644 --- a/.github/workflows/unittest.yaml +++ b/.github/workflows/unittest.yaml @@ -31,7 +31,7 @@ jobs: - name: Test with pytest run: | export ALLOW_OPENAI_API_CALL=0 - mkdir -p ~/.metagpt && cp tests/config2.yaml ~/.metagpt/config2.yaml && cp tests/spark.yaml ~/.metagpt/spark.yaml + mkdir -p ~/.metagpt && cp tests/config2.yaml ~/.metagpt/config2.yaml pytest tests/ --doctest-modules --cov=./metagpt/ --cov-report=xml:cov.xml --cov-report=html:htmlcov --durations=20 | tee unittest.txt - name: Show coverage report run: | diff --git a/metagpt/provider/fireworks_api.py b/metagpt/provider/fireworks_api.py index 0c70a3cb4..f356c23c4 100644 --- a/metagpt/provider/fireworks_api.py +++ b/metagpt/provider/fireworks_api.py @@ -19,7 +19,7 @@ from metagpt.configs.llm_config import LLMConfig, LLMType from metagpt.logs import log_llm_stream, logger from metagpt.provider.llm_provider_registry import register_provider from metagpt.provider.openai_api import OpenAILLM, log_and_reraise -from metagpt.utils.cost_manager import CostManager, Costs +from metagpt.utils.cost_manager import CostManager MODEL_GRADE_TOKEN_COSTS = { "-1": {"prompt": 0.0, "completion": 0.0}, # abnormal condition @@ -81,17 +81,6 @@ class FireworksLLM(OpenAILLM): kwargs = dict(api_key=self.config.api_key, base_url=self.config.base_url) return kwargs - def _update_costs(self, usage: CompletionUsage): - if self.config.calc_usage and usage: - try: - # use FireworksCostManager not context.cost_manager - self.cost_manager.update_cost(usage.prompt_tokens, usage.completion_tokens, self.model) - except Exception as e: - logger.error(f"updating costs failed!, exp: {e}") - - def get_costs(self) -> Costs: - return self.cost_manager.get_costs() - async def _achat_completion_stream(self, messages: list[dict], timeout=3) -> str: response: AsyncStream[ChatCompletionChunk] = await self.aclient.chat.completions.create( **self._cons_kwargs(messages), stream=True diff --git a/metagpt/provider/google_gemini_api.py b/metagpt/provider/google_gemini_api.py index 2647ab16b..87ea81c80 100644 --- a/metagpt/provider/google_gemini_api.py +++ b/metagpt/provider/google_gemini_api.py @@ -72,16 +72,6 @@ class GeminiLLM(BaseLLM): kwargs = {"contents": messages, "generation_config": GenerationConfig(temperature=0.3), "stream": stream} return kwargs - def _update_costs(self, usage: dict): - """update each request's token cost""" - if self.config.calc_usage: - try: - prompt_tokens = int(usage.get("prompt_tokens", 0)) - completion_tokens = int(usage.get("completion_tokens", 0)) - self.cost_manager.update_cost(prompt_tokens, completion_tokens, self.model) - except Exception as e: - logger.error(f"google gemini updats costs failed! exp: {e}") - def get_choice_text(self, resp: GenerateContentResponse) -> str: return resp.text diff --git a/metagpt/provider/ollama_api.py b/metagpt/provider/ollama_api.py index c9103b018..52e8dbe36 100644 --- a/metagpt/provider/ollama_api.py +++ b/metagpt/provider/ollama_api.py @@ -46,16 +46,6 @@ class OllamaLLM(BaseLLM): kwargs = {"model": self.model, "messages": messages, "options": {"temperature": 0.3}, "stream": stream} return kwargs - def _update_costs(self, usage: dict): - """update each request's token cost""" - if self.config.calc_usage: - try: - prompt_tokens = int(usage.get("prompt_tokens", 0)) - completion_tokens = int(usage.get("completion_tokens", 0)) - self._cost_manager.update_cost(prompt_tokens, completion_tokens, self.model) - except Exception as e: - logger.error(f"ollama updats costs failed! exp: {e}") - def get_choice_text(self, resp: dict) -> str: """get the resp content from llm response""" assist_msg = resp.get("message", {}) diff --git a/metagpt/provider/open_llm_api.py b/metagpt/provider/open_llm_api.py index a29b263a4..69371e379 100644 --- a/metagpt/provider/open_llm_api.py +++ b/metagpt/provider/open_llm_api.py @@ -8,7 +8,7 @@ from metagpt.configs.llm_config import LLMConfig, LLMType from metagpt.logs import logger from metagpt.provider.llm_provider_registry import register_provider from metagpt.provider.openai_api import OpenAILLM -from metagpt.utils.cost_manager import Costs, TokenCostManager +from metagpt.utils.cost_manager import TokenCostManager from metagpt.utils.token_counter import count_message_tokens, count_string_tokens @@ -34,14 +34,3 @@ class OpenLLM(OpenAILLM): logger.error(f"usage calculation failed!: {e}") return usage - - def _update_costs(self, usage: CompletionUsage): - if self.config.calc_usage and usage: - try: - # use OpenLLMCostManager not CONFIG.cost_manager - self._cost_manager.update_cost(usage.prompt_tokens, usage.completion_tokens, self.model) - except Exception as e: - logger.error(f"updating costs failed!, exp: {e}") - - def get_costs(self) -> Costs: - return self._cost_manager.get_costs() diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 28abed752..90a61085f 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -30,7 +30,7 @@ from metagpt.provider.constant import GENERAL_FUNCTION_SCHEMA from metagpt.provider.llm_provider_registry import register_provider from metagpt.schema import Message from metagpt.utils.common import CodeParser, decode_image -from metagpt.utils.cost_manager import CostManager, Costs +from metagpt.utils.cost_manager import CostManager from metagpt.utils.exceptions import handle_exception from metagpt.utils.token_counter import ( count_message_tokens, @@ -56,16 +56,13 @@ class OpenAILLM(BaseLLM): def __init__(self, config: LLMConfig): self.config = config - self._init_model() self._init_client() self.auto_max_tokens = False self.cost_manager: Optional[CostManager] = None - def _init_model(self): - self.model = self.config.model # Used in _calc_usage & _cons_kwargs - def _init_client(self): """https://github.com/openai/openai-python#async-usage""" + self.model = self.config.model # Used in _calc_usage & _cons_kwargs kwargs = self._make_client_kwargs() self.aclient = AsyncOpenAI(**kwargs) @@ -272,16 +269,6 @@ class OpenAILLM(BaseLLM): return usage - @handle_exception - def _update_costs(self, usage: CompletionUsage): - if self.config.calc_usage and usage and self.cost_manager: - self.cost_manager.update_cost(usage.prompt_tokens, usage.completion_tokens, self.model) - - def get_costs(self) -> Costs: - if not self.cost_manager: - return Costs(0, 0, 0, 0) - return self.cost_manager.get_costs() - def _get_max_tokens(self, messages: list[dict]): if not self.auto_max_tokens: return self.config.max_token diff --git a/metagpt/provider/zhipuai_api.py b/metagpt/provider/zhipuai_api.py index 9e8e5fb53..4cbee4038 100644 --- a/metagpt/provider/zhipuai_api.py +++ b/metagpt/provider/zhipuai_api.py @@ -53,16 +53,6 @@ class ZhiPuAILLM(BaseLLM): kwargs = {"model": self.model, "messages": messages, "stream": stream, "temperature": 0.3} return kwargs - def _update_costs(self, usage: dict): - """update each request's token cost""" - if self.config.calc_usage: - try: - prompt_tokens = int(usage.get("prompt_tokens", 0)) - completion_tokens = int(usage.get("completion_tokens", 0)) - self.cost_manager.update_cost(prompt_tokens, completion_tokens, self.model) - except Exception as e: - logger.error(f"zhipuai updats costs failed! exp: {e}") - def completion(self, messages: list[dict], timeout=3) -> dict: resp: Completion = self.llm.chat.completions.create(**self._const_kwargs(messages)) usage = resp.usage.model_dump() diff --git a/tests/metagpt/provider/test_anthropic_api.py b/tests/metagpt/provider/test_anthropic_api.py index 6962ab064..93cfd7dbc 100644 --- a/tests/metagpt/provider/test_anthropic_api.py +++ b/tests/metagpt/provider/test_anthropic_api.py @@ -8,25 +8,25 @@ from anthropic.resources.completions import Completion from metagpt.provider.anthropic_api import Claude2 from tests.metagpt.provider.mock_llm_config import mock_llm_config +from tests.metagpt.provider.req_resp_const import prompt, resp_cont_tmpl -prompt = "who are you" -resp = "I'am Claude2" +resp_cont = resp_cont_tmpl.format(name="Claude") def mock_anthropic_completions_create(self, model: str, prompt: str, max_tokens_to_sample: int) -> Completion: - return Completion(id="xx", completion=resp, model="claude-2", stop_reason="stop_sequence", type="completion") + return Completion(id="xx", completion=resp_cont, model="claude-2", stop_reason="stop_sequence", type="completion") async def mock_anthropic_acompletions_create(self, model: str, prompt: str, max_tokens_to_sample: int) -> Completion: - return Completion(id="xx", completion=resp, model="claude-2", stop_reason="stop_sequence", type="completion") + return Completion(id="xx", completion=resp_cont, model="claude-2", stop_reason="stop_sequence", type="completion") def test_claude2_ask(mocker): mocker.patch("anthropic.resources.completions.Completions.create", mock_anthropic_completions_create) - assert resp == Claude2(mock_llm_config).ask(prompt) + assert resp_cont == Claude2(mock_llm_config).ask(prompt) @pytest.mark.asyncio async def test_claude2_aask(mocker): mocker.patch("anthropic.resources.completions.AsyncCompletions.create", mock_anthropic_acompletions_create) - assert resp == await Claude2(mock_llm_config).aask(prompt) + assert resp_cont == await Claude2(mock_llm_config).aask(prompt) diff --git a/tests/metagpt/provider/test_base_llm.py b/tests/metagpt/provider/test_base_llm.py index cc781f78a..cf44343bc 100644 --- a/tests/metagpt/provider/test_base_llm.py +++ b/tests/metagpt/provider/test_base_llm.py @@ -11,21 +11,13 @@ import pytest from metagpt.configs.llm_config import LLMConfig from metagpt.provider.base_llm import BaseLLM from metagpt.schema import Message +from tests.metagpt.provider.req_resp_const import ( + default_resp_cont, + get_part_chat_completion, + prompt, +) -default_chat_resp = { - "choices": [ - { - "index": 0, - "message": { - "role": "assistant", - "content": "I'am GPT", - }, - "finish_reason": "stop", - } - ] -} -prompt_msg = "who are you" -resp_content = default_chat_resp["choices"][0]["message"]["content"] +name = "GPT" class MockBaseLLM(BaseLLM): @@ -33,16 +25,13 @@ class MockBaseLLM(BaseLLM): pass def completion(self, messages: list[dict], timeout=3): - return default_chat_resp + return get_part_chat_completion(name) async def acompletion(self, messages: list[dict], timeout=3): - return default_chat_resp + return get_part_chat_completion(name) async def acompletion_text(self, messages: list[dict], stream=False, timeout=3) -> str: - return resp_content - - async def close(self): - return default_chat_resp + return default_resp_cont def test_base_llm(): @@ -86,25 +75,25 @@ def test_base_llm(): choice_text = base_llm.get_choice_text(openai_funccall_resp) assert choice_text == openai_funccall_resp["choices"][0]["message"]["content"] - # resp = base_llm.ask(prompt_msg) - # assert resp == resp_content + # resp = base_llm.ask(prompt) + # assert resp == default_resp_cont - # resp = base_llm.ask_batch([prompt_msg]) - # assert resp == resp_content + # resp = base_llm.ask_batch([prompt]) + # assert resp == default_resp_cont - # resp = base_llm.ask_code([prompt_msg]) - # assert resp == resp_content + # resp = base_llm.ask_code([prompt]) + # assert resp == default_resp_cont @pytest.mark.asyncio async def test_async_base_llm(): base_llm = MockBaseLLM() - resp = await base_llm.aask(prompt_msg) - assert resp == resp_content + resp = await base_llm.aask(prompt) + assert resp == default_resp_cont - resp = await base_llm.aask_batch([prompt_msg]) - assert resp == resp_content + resp = await base_llm.aask_batch([prompt]) + assert resp == default_resp_cont - # resp = await base_llm.aask_code([prompt_msg]) - # assert resp == resp_content + # resp = await base_llm.aask_code([prompt]) + # assert resp == default_resp_cont diff --git a/tests/metagpt/provider/test_fireworks_llm.py b/tests/metagpt/provider/test_fireworks_llm.py index 66b55e5b2..1c1aa9caa 100644 --- a/tests/metagpt/provider/test_fireworks_llm.py +++ b/tests/metagpt/provider/test_fireworks_llm.py @@ -3,14 +3,7 @@ # @Desc : the unittest of fireworks api import pytest -from openai.types.chat.chat_completion import ( - ChatCompletion, - ChatCompletionMessage, - Choice, -) from openai.types.chat.chat_completion_chunk import ChatCompletionChunk -from openai.types.chat.chat_completion_chunk import Choice as AChoice -from openai.types.chat.chat_completion_chunk import ChoiceDelta from openai.types.completion_usage import CompletionUsage from metagpt.provider.fireworks_api import ( @@ -20,42 +13,19 @@ from metagpt.provider.fireworks_api import ( ) from metagpt.utils.cost_manager import Costs from tests.metagpt.provider.mock_llm_config import mock_llm_config - -resp_content = "I'm fireworks" -default_resp = ChatCompletion( - id="cmpl-a6652c1bb181caae8dd19ad8", - model="accounts/fireworks/models/llama-v2-13b-chat", - object="chat.completion", - created=1703300855, - choices=[ - Choice( - finish_reason="stop", - index=0, - message=ChatCompletionMessage(role="assistant", content=resp_content), - logprobs=None, - ) - ], - usage=CompletionUsage(completion_tokens=110, prompt_tokens=92, total_tokens=202), +from tests.metagpt.provider.req_resp_const import ( + get_openai_chat_completion, + get_openai_chat_completion_chunk, + llm_general_chat_funcs_test, + messages, + prompt, + resp_cont_tmpl, ) -default_resp_chunk = ChatCompletionChunk( - id=default_resp.id, - model=default_resp.model, - object="chat.completion.chunk", - created=default_resp.created, - choices=[ - AChoice( - delta=ChoiceDelta(content=resp_content, role="assistant"), - finish_reason="stop", - index=0, - logprobs=None, - ) - ], - usage=dict(default_resp.usage), -) - -prompt_msg = "who are you" -messages = [{"role": "user", "content": prompt_msg}] +name = "fireworks" +resp_cont = resp_cont_tmpl.format(name=name) +default_resp = get_openai_chat_completion(name) +default_resp_chunk = get_openai_chat_completion_chunk(name, usage_as_dict=True) def test_fireworks_costmanager(): @@ -88,27 +58,17 @@ async def mock_openai_acompletions_create(self, stream: bool = False, **kwargs) async def test_fireworks_acompletion(mocker): mocker.patch("openai.resources.chat.completions.AsyncCompletions.create", mock_openai_acompletions_create) - fireworks_gpt = FireworksLLM(mock_llm_config) - fireworks_gpt.model = "llama-v2-13b-chat" + fireworks_llm = FireworksLLM(mock_llm_config) + fireworks_llm.model = "llama-v2-13b-chat" - fireworks_gpt._update_costs( + fireworks_llm._update_costs( usage=CompletionUsage(prompt_tokens=500000, completion_tokens=500000, total_tokens=1000000) ) - assert fireworks_gpt.get_costs() == Costs( + assert fireworks_llm.get_costs() == Costs( total_prompt_tokens=500000, total_completion_tokens=500000, total_cost=0.5, total_budget=0 ) - resp = await fireworks_gpt.acompletion(messages) - assert resp.choices[0].message.content in resp_content + resp = await fireworks_llm.acompletion(messages) + assert resp.choices[0].message.content in resp_cont - resp = await fireworks_gpt.aask(prompt_msg, stream=False) - assert resp == resp_content - - resp = await fireworks_gpt.acompletion_text(messages, stream=False) - assert resp == resp_content - - resp = await fireworks_gpt.acompletion_text(messages, stream=True) - assert resp == resp_content - - resp = await fireworks_gpt.aask(prompt_msg) - assert resp == resp_content + await llm_general_chat_funcs_test(fireworks_llm, prompt, messages, resp_cont) diff --git a/tests/metagpt/provider/test_google_gemini_api.py b/tests/metagpt/provider/test_google_gemini_api.py index 404ae1e90..50c15ee19 100644 --- a/tests/metagpt/provider/test_google_gemini_api.py +++ b/tests/metagpt/provider/test_google_gemini_api.py @@ -11,6 +11,12 @@ from google.generativeai.types import content_types from metagpt.provider.google_gemini_api import GeminiLLM from tests.metagpt.provider.mock_llm_config import mock_llm_config +from tests.metagpt.provider.req_resp_const import ( + gemini_messages, + llm_general_chat_funcs_test, + prompt, + resp_cont_tmpl, +) @dataclass @@ -18,10 +24,8 @@ class MockGeminiResponse(ABC): text: str -prompt_msg = "who are you" -messages = [{"role": "user", "parts": prompt_msg}] -resp_content = "I'm gemini from google" -default_resp = MockGeminiResponse(text=resp_content) +resp_cont = resp_cont_tmpl.format(name="gemini") +default_resp = MockGeminiResponse(text=resp_cont) def mock_gemini_count_tokens(self, contents: content_types.ContentsType) -> glm.CountTokensResponse: @@ -60,28 +64,18 @@ async def test_gemini_acompletion(mocker): mock_gemini_generate_content_async, ) - gemini_gpt = GeminiLLM(mock_llm_config) + gemini_llm = GeminiLLM(mock_llm_config) - assert gemini_gpt._user_msg(prompt_msg) == {"role": "user", "parts": [prompt_msg]} - assert gemini_gpt._assistant_msg(prompt_msg) == {"role": "model", "parts": [prompt_msg]} + assert gemini_llm._user_msg(prompt) == {"role": "user", "parts": [prompt]} + assert gemini_llm._assistant_msg(prompt) == {"role": "model", "parts": [prompt]} - usage = gemini_gpt.get_usage(messages, resp_content) + usage = gemini_llm.get_usage(gemini_messages, resp_cont) assert usage == {"prompt_tokens": 20, "completion_tokens": 20} - resp = gemini_gpt.completion(messages) + resp = gemini_llm.completion(gemini_messages) assert resp == default_resp - resp = await gemini_gpt.acompletion(messages) + resp = await gemini_llm.acompletion(gemini_messages) assert resp.text == default_resp.text - resp = await gemini_gpt.aask(prompt_msg, stream=False) - assert resp == resp_content - - resp = await gemini_gpt.acompletion_text(messages, stream=False) - assert resp == resp_content - - resp = await gemini_gpt.acompletion_text(messages, stream=True) - assert resp == resp_content - - resp = await gemini_gpt.aask(prompt_msg) - assert resp == resp_content + await llm_general_chat_funcs_test(gemini_llm, prompt, gemini_messages, resp_cont) diff --git a/tests/metagpt/provider/test_ollama_api.py b/tests/metagpt/provider/test_ollama_api.py index 5d942598b..af2e929e9 100644 --- a/tests/metagpt/provider/test_ollama_api.py +++ b/tests/metagpt/provider/test_ollama_api.py @@ -9,12 +9,15 @@ import pytest from metagpt.provider.ollama_api import OllamaLLM from tests.metagpt.provider.mock_llm_config import mock_llm_config +from tests.metagpt.provider.req_resp_const import ( + llm_general_chat_funcs_test, + messages, + prompt, + resp_cont_tmpl, +) -prompt_msg = "who are you" -messages = [{"role": "user", "content": prompt_msg}] - -resp_content = "I'm ollama" -default_resp = {"message": {"role": "assistant", "content": resp_content}} +resp_cont = resp_cont_tmpl.format(name="ollama") +default_resp = {"message": {"role": "assistant", "content": resp_cont}} async def mock_ollama_arequest(self, stream: bool = False, **kwargs) -> Tuple[Any, Any, bool]: @@ -41,19 +44,12 @@ async def mock_ollama_arequest(self, stream: bool = False, **kwargs) -> Tuple[An async def test_gemini_acompletion(mocker): mocker.patch("metagpt.provider.general_api_requestor.GeneralAPIRequestor.arequest", mock_ollama_arequest) - ollama_gpt = OllamaLLM(mock_llm_config) + ollama_llm = OllamaLLM(mock_llm_config) - resp = await ollama_gpt.acompletion(messages) + resp = await ollama_llm.acompletion(messages) assert resp["message"]["content"] == default_resp["message"]["content"] - resp = await ollama_gpt.aask(prompt_msg, stream=False) - assert resp == resp_content + resp = await ollama_llm.aask(prompt, stream=False) + assert resp == resp_cont - resp = await ollama_gpt.acompletion_text(messages, stream=False) - assert resp == resp_content - - resp = await ollama_gpt.acompletion_text(messages, stream=True) - assert resp == resp_content - - resp = await ollama_gpt.aask(prompt_msg) - assert resp == resp_content + await llm_general_chat_funcs_test(ollama_llm, prompt, messages, resp_cont) diff --git a/tests/metagpt/provider/test_open_llm_api.py b/tests/metagpt/provider/test_open_llm_api.py index fc7b510cc..aa38b95a6 100644 --- a/tests/metagpt/provider/test_open_llm_api.py +++ b/tests/metagpt/provider/test_open_llm_api.py @@ -3,53 +3,26 @@ # @Desc : import pytest -from openai.types.chat.chat_completion import ( - ChatCompletion, - ChatCompletionMessage, - Choice, -) from openai.types.chat.chat_completion_chunk import ChatCompletionChunk -from openai.types.chat.chat_completion_chunk import Choice as AChoice -from openai.types.chat.chat_completion_chunk import ChoiceDelta from openai.types.completion_usage import CompletionUsage from metagpt.provider.open_llm_api import OpenLLM -from metagpt.utils.cost_manager import Costs +from metagpt.utils.cost_manager import CostManager, Costs from tests.metagpt.provider.mock_llm_config import mock_llm_config - -resp_content = "I'm llama2" -default_resp = ChatCompletion( - id="cmpl-a6652c1bb181caae8dd19ad8", - model="llama-v2-13b-chat", - object="chat.completion", - created=1703302755, - choices=[ - Choice( - finish_reason="stop", - index=0, - message=ChatCompletionMessage(role="assistant", content=resp_content), - logprobs=None, - ) - ], +from tests.metagpt.provider.req_resp_const import ( + get_openai_chat_completion, + get_openai_chat_completion_chunk, + llm_general_chat_funcs_test, + messages, + prompt, + resp_cont_tmpl, ) -default_resp_chunk = ChatCompletionChunk( - id=default_resp.id, - model=default_resp.model, - object="chat.completion.chunk", - created=default_resp.created, - choices=[ - AChoice( - delta=ChoiceDelta(content=resp_content, role="assistant"), - finish_reason="stop", - index=0, - logprobs=None, - ) - ], -) +name = "llama2-7b" +resp_cont = resp_cont_tmpl.format(name=name) +default_resp = get_openai_chat_completion(name) -prompt_msg = "who are you" -messages = [{"role": "user", "content": prompt_msg}] +default_resp_chunk = get_openai_chat_completion_chunk(name) async def mock_openai_acompletions_create(self, stream: bool = False, **kwargs) -> ChatCompletionChunk: @@ -68,25 +41,16 @@ async def mock_openai_acompletions_create(self, stream: bool = False, **kwargs) async def test_openllm_acompletion(mocker): mocker.patch("openai.resources.chat.completions.AsyncCompletions.create", mock_openai_acompletions_create) - openllm_gpt = OpenLLM(mock_llm_config) - openllm_gpt.model = "llama-v2-13b-chat" + openllm_llm = OpenLLM(mock_llm_config) + openllm_llm.model = "llama-v2-13b-chat" - openllm_gpt._update_costs(usage=CompletionUsage(prompt_tokens=100, completion_tokens=100, total_tokens=200)) - assert openllm_gpt.get_costs() == Costs( + openllm_llm.cost_manager = CostManager() + openllm_llm._update_costs(usage=CompletionUsage(prompt_tokens=100, completion_tokens=100, total_tokens=200)) + assert openllm_llm.get_costs() == Costs( total_prompt_tokens=100, total_completion_tokens=100, total_cost=0, total_budget=0 ) - resp = await openllm_gpt.acompletion(messages) - assert resp.choices[0].message.content in resp_content + resp = await openllm_llm.acompletion(messages) + assert resp.choices[0].message.content in resp_cont - resp = await openllm_gpt.aask(prompt_msg, stream=False) - assert resp == resp_content - - resp = await openllm_gpt.acompletion_text(messages, stream=False) - assert resp == resp_content - - resp = await openllm_gpt.acompletion_text(messages, stream=True) - assert resp == resp_content - - resp = await openllm_gpt.aask(prompt_msg) - assert resp == resp_content + await llm_general_chat_funcs_test(openllm_llm, prompt, messages, resp_cont) diff --git a/tests/metagpt/provider/test_spark_api.py b/tests/metagpt/provider/test_spark_api.py index f5a6f66fd..9c278267d 100644 --- a/tests/metagpt/provider/test_spark_api.py +++ b/tests/metagpt/provider/test_spark_api.py @@ -4,12 +4,18 @@ import pytest -from metagpt.config2 import Config from metagpt.provider.spark_api import GetMessageFromWeb, SparkLLM -from tests.metagpt.provider.mock_llm_config import mock_llm_config +from tests.metagpt.provider.mock_llm_config import ( + mock_llm_config, + mock_llm_config_spark, +) +from tests.metagpt.provider.req_resp_const import ( + llm_general_chat_funcs_test, + prompt, + resp_cont_tmpl, +) -prompt_msg = "who are you" -resp_content = "I'm Spark" +resp_cont = resp_cont_tmpl.format(name="Spark") class MockWebSocketApp(object): @@ -23,7 +29,7 @@ class MockWebSocketApp(object): def test_get_msg_from_web(mocker): mocker.patch("websocket.WebSocketApp", MockWebSocketApp) - get_msg_from_web = GetMessageFromWeb(prompt_msg, mock_llm_config) + get_msg_from_web = GetMessageFromWeb(prompt, mock_llm_config) assert get_msg_from_web.gen_params()["parameter"]["chat"]["domain"] == "mock_domain" ret = get_msg_from_web.run() @@ -31,34 +37,26 @@ def test_get_msg_from_web(mocker): def mock_spark_get_msg_from_web_run(self) -> str: - return resp_content + return resp_cont @pytest.mark.asyncio -async def test_spark_aask(): - llm = SparkLLM(Config.from_home("spark.yaml").llm) +async def test_spark_aask(mocker): + mocker.patch("metagpt.provider.spark_api.GetMessageFromWeb.run", mock_spark_get_msg_from_web_run) + + llm = SparkLLM(mock_llm_config_spark) resp = await llm.aask("Hello!") - print(resp) + assert resp == resp_cont @pytest.mark.asyncio async def test_spark_acompletion(mocker): mocker.patch("metagpt.provider.spark_api.GetMessageFromWeb.run", mock_spark_get_msg_from_web_run) - spark_gpt = SparkLLM(mock_llm_config) + spark_llm = SparkLLM(mock_llm_config) - resp = await spark_gpt.acompletion([]) - assert resp == resp_content + resp = await spark_llm.acompletion([]) + assert resp == resp_cont - resp = await spark_gpt.aask(prompt_msg, stream=False) - assert resp == resp_content - - resp = await spark_gpt.acompletion_text([], stream=False) - assert resp == resp_content - - resp = await spark_gpt.acompletion_text([], stream=True) - assert resp == resp_content - - resp = await spark_gpt.aask(prompt_msg) - assert resp == resp_content + await llm_general_chat_funcs_test(spark_llm, prompt, prompt, resp_cont) diff --git a/tests/metagpt/provider/test_zhipuai_api.py b/tests/metagpt/provider/test_zhipuai_api.py index ad2ececa2..c51010122 100644 --- a/tests/metagpt/provider/test_zhipuai_api.py +++ b/tests/metagpt/provider/test_zhipuai_api.py @@ -6,22 +6,24 @@ import pytest from metagpt.provider.zhipuai_api import ZhiPuAILLM from tests.metagpt.provider.mock_llm_config import mock_llm_config_zhipu +from tests.metagpt.provider.req_resp_const import ( + get_part_chat_completion, + llm_general_chat_funcs_test, + messages, + prompt, + resp_cont_tmpl, +) -prompt_msg = "who are you" -messages = [{"role": "user", "content": prompt_msg}] - -resp_content = "I'm chatglm-turbo" -default_resp = { - "choices": [{"finish_reason": "stop", "index": 0, "message": {"content": resp_content, "role": "assistant"}}], - "usage": {"completion_tokens": 22, "prompt_tokens": 19, "total_tokens": 41}, -} +name = "ChatGLM-4" +resp_cont = resp_cont_tmpl.format(name=name) +default_resp = get_part_chat_completion(name) async def mock_zhipuai_acreate_stream(self, **kwargs): class MockResponse(object): async def _aread(self): class Iterator(object): - events = [{"choices": [{"index": 0, "delta": {"content": resp_content, "role": "assistant"}}]}] + events = [{"choices": [{"index": 0, "delta": {"content": resp_cont, "role": "assistant"}}]}] async def __aiter__(self): for event in self.events: @@ -46,22 +48,12 @@ async def test_zhipuai_acompletion(mocker): mocker.patch("metagpt.provider.zhipuai.zhipu_model_api.ZhiPuModelAPI.acreate", mock_zhipuai_acreate) mocker.patch("metagpt.provider.zhipuai.zhipu_model_api.ZhiPuModelAPI.acreate_stream", mock_zhipuai_acreate_stream) - zhipu_gpt = ZhiPuAILLM(mock_llm_config_zhipu) + zhipu_llm = ZhiPuAILLM(mock_llm_config_zhipu) - resp = await zhipu_gpt.acompletion(messages) - assert resp["choices"][0]["message"]["content"] == resp_content + resp = await zhipu_llm.acompletion(messages) + assert resp["choices"][0]["message"]["content"] == resp_cont - resp = await zhipu_gpt.aask(prompt_msg, stream=False) - assert resp == resp_content - - resp = await zhipu_gpt.acompletion_text(messages, stream=False) - assert resp == resp_content - - resp = await zhipu_gpt.acompletion_text(messages, stream=True) - assert resp == resp_content - - resp = await zhipu_gpt.aask(prompt_msg) - assert resp == resp_content + await llm_general_chat_funcs_test(zhipu_llm, prompt, messages, resp_cont) def test_zhipuai_proxy(): diff --git a/tests/spark.yaml b/tests/spark.yaml deleted file mode 100644 index a5bbd98bd..000000000 --- a/tests/spark.yaml +++ /dev/null @@ -1,7 +0,0 @@ -llm: - api_type: "spark" - app_id: "xxx" - api_key: "xxx" - api_secret: "xxx" - domain: "generalv2" - base_url: "wss://spark-api.xf-yun.com/v3.1/chat" \ No newline at end of file