增加环绕侦察场景适配
This commit is contained in:
@@ -135,7 +135,7 @@ class InferenceClient:
|
||||
Note: for better compatibility with OpenAI's client, `model` has been aliased as `base_url`. Those 2
|
||||
arguments are mutually exclusive. If a URL is passed as `model` or `base_url` for chat completion, the `(/v1)/chat/completions` suffix path will be appended to the URL.
|
||||
provider (`str`, *optional*):
|
||||
Name of the provider to use for inference. Can be `"black-forest-labs"`, `"cerebras"`, `"clarifai"`, `"cohere"`, `"fal-ai"`, `"featherless-ai"`, `"fireworks-ai"`, `"groq"`, `"hf-inference"`, `"hyperbolic"`, `"nebius"`, `"novita"`, `"nscale"`, `"openai"`, `"publicai"`, `"replicate"`, `"sambanova"`, `"scaleway"`, `"together"`, `"wavespeed"` or `"zai-org"`.
|
||||
Name of the provider to use for inference. Can be `"black-forest-labs"`, `"cerebras"`, `"clarifai"`, `"cohere"`, `"fal-ai"`, `"featherless-ai"`, `"fireworks-ai"`, `"groq"`, `"hf-inference"`, `"hyperbolic"`, `"nebius"`, `"novita"`, `"nscale"`, `"openai"`, `"ovhcloud"`, `"publicai"`, `"replicate"`, `"sambanova"`, `"scaleway"`, `"together"`, `"wavespeed"` or `"zai-org"`.
|
||||
Defaults to "auto" i.e. the first of the providers available for the model, sorted by the user's order in https://hf.co/settings/inference-providers.
|
||||
If model is a URL or `base_url` is passed, then `provider` is not used.
|
||||
token (`str`, *optional*):
|
||||
@@ -452,6 +452,7 @@ class InferenceClient:
|
||||
api_key=self.token,
|
||||
)
|
||||
response = self._inner_post(request_parameters)
|
||||
response = provider_helper.get_response(response, request_params=request_parameters)
|
||||
return AutomaticSpeechRecognitionOutput.parse_obj_as_instance(response)
|
||||
|
||||
@overload
|
||||
@@ -1028,7 +1029,7 @@ class InferenceClient:
|
||||
normalize: Optional[bool] = None,
|
||||
prompt_name: Optional[str] = None,
|
||||
truncate: Optional[bool] = None,
|
||||
truncation_direction: Optional[Literal["Left", "Right"]] = None,
|
||||
truncation_direction: Optional[Literal["left", "right"]] = None,
|
||||
model: Optional[str] = None,
|
||||
) -> "np.ndarray":
|
||||
"""
|
||||
@@ -1053,7 +1054,7 @@ class InferenceClient:
|
||||
truncate (`bool`, *optional*):
|
||||
Whether to truncate the embeddings or not.
|
||||
Only available on server powered by Text-Embedding-Inference.
|
||||
truncation_direction (`Literal["Left", "Right"]`, *optional*):
|
||||
truncation_direction (`Literal["left", "right"]`, *optional*):
|
||||
Which side of the input should be truncated when `truncate=True` is passed.
|
||||
|
||||
Returns:
|
||||
@@ -3195,10 +3196,7 @@ class InferenceClient:
|
||||
)
|
||||
response = self._inner_post(request_parameters)
|
||||
output = _bytes_to_dict(response)
|
||||
return [
|
||||
ZeroShotClassificationOutputElement.parse_obj_as_instance({"label": label, "score": score})
|
||||
for label, score in zip(output["labels"], output["scores"])
|
||||
]
|
||||
return ZeroShotClassificationOutputElement.parse_obj_as_list(output)
|
||||
|
||||
def zero_shot_image_classification(
|
||||
self,
|
||||
|
||||
@@ -144,7 +144,7 @@ def _open_as_mime_bytes(content: Optional[ContentT]) -> Optional[MimeBytes]:
|
||||
if hasattr(content, "read"): # duck-typing instead of isinstance(content, BinaryIO)
|
||||
logger.debug("Reading content from BinaryIO")
|
||||
data = content.read()
|
||||
mime_type = mimetypes.guess_type(content.name)[0] if hasattr(content, "name") else None
|
||||
mime_type = mimetypes.guess_type(str(content.name))[0] if hasattr(content, "name") else None
|
||||
if isinstance(data, str):
|
||||
raise TypeError("Expected binary stream (bytes), but got text stream")
|
||||
return MimeBytes(data, mime_type=mime_type)
|
||||
|
||||
@@ -126,7 +126,7 @@ class AsyncInferenceClient:
|
||||
Note: for better compatibility with OpenAI's client, `model` has been aliased as `base_url`. Those 2
|
||||
arguments are mutually exclusive. If a URL is passed as `model` or `base_url` for chat completion, the `(/v1)/chat/completions` suffix path will be appended to the URL.
|
||||
provider (`str`, *optional*):
|
||||
Name of the provider to use for inference. Can be `"black-forest-labs"`, `"cerebras"`, `"clarifai"`, `"cohere"`, `"fal-ai"`, `"featherless-ai"`, `"fireworks-ai"`, `"groq"`, `"hf-inference"`, `"hyperbolic"`, `"nebius"`, `"novita"`, `"nscale"`, `"openai"`, `"publicai"`, `"replicate"`, `"sambanova"`, `"scaleway"`, `"together"`, `"wavespeed"` or `"zai-org"`.
|
||||
Name of the provider to use for inference. Can be `"black-forest-labs"`, `"cerebras"`, `"clarifai"`, `"cohere"`, `"fal-ai"`, `"featherless-ai"`, `"fireworks-ai"`, `"groq"`, `"hf-inference"`, `"hyperbolic"`, `"nebius"`, `"novita"`, `"nscale"`, `"openai"`, `"ovhcloud"`, `"publicai"`, `"replicate"`, `"sambanova"`, `"scaleway"`, `"together"`, `"wavespeed"` or `"zai-org"`.
|
||||
Defaults to "auto" i.e. the first of the providers available for the model, sorted by the user's order in https://hf.co/settings/inference-providers.
|
||||
If model is a URL or `base_url` is passed, then `provider` is not used.
|
||||
token (`str`, *optional*):
|
||||
@@ -472,6 +472,7 @@ class AsyncInferenceClient:
|
||||
api_key=self.token,
|
||||
)
|
||||
response = await self._inner_post(request_parameters)
|
||||
response = provider_helper.get_response(response, request_params=request_parameters)
|
||||
return AutomaticSpeechRecognitionOutput.parse_obj_as_instance(response)
|
||||
|
||||
@overload
|
||||
@@ -1055,7 +1056,7 @@ class AsyncInferenceClient:
|
||||
normalize: Optional[bool] = None,
|
||||
prompt_name: Optional[str] = None,
|
||||
truncate: Optional[bool] = None,
|
||||
truncation_direction: Optional[Literal["Left", "Right"]] = None,
|
||||
truncation_direction: Optional[Literal["left", "right"]] = None,
|
||||
model: Optional[str] = None,
|
||||
) -> "np.ndarray":
|
||||
"""
|
||||
@@ -1080,7 +1081,7 @@ class AsyncInferenceClient:
|
||||
truncate (`bool`, *optional*):
|
||||
Whether to truncate the embeddings or not.
|
||||
Only available on server powered by Text-Embedding-Inference.
|
||||
truncation_direction (`Literal["Left", "Right"]`, *optional*):
|
||||
truncation_direction (`Literal["left", "right"]`, *optional*):
|
||||
Which side of the input should be truncated when `truncate=True` is passed.
|
||||
|
||||
Returns:
|
||||
@@ -3245,10 +3246,7 @@ class AsyncInferenceClient:
|
||||
)
|
||||
response = await self._inner_post(request_parameters)
|
||||
output = _bytes_to_dict(response)
|
||||
return [
|
||||
ZeroShotClassificationOutputElement.parse_obj_as_instance({"label": label, "score": score})
|
||||
for label, score in zip(output["labels"], output["scores"])
|
||||
]
|
||||
return ZeroShotClassificationOutputElement.parse_obj_as_list(output)
|
||||
|
||||
async def zero_shot_image_classification(
|
||||
self,
|
||||
|
||||
@@ -19,6 +19,8 @@ import types
|
||||
from dataclasses import asdict, dataclass
|
||||
from typing import Any, TypeVar, Union, get_args
|
||||
|
||||
from typing_extensions import dataclass_transform
|
||||
|
||||
|
||||
T = TypeVar("T", bound="BaseInferenceType")
|
||||
|
||||
@@ -29,6 +31,7 @@ def _repr_with_extra(self):
|
||||
return f"{self.__class__.__name__}({', '.join(f'{k}={self.__dict__[k]!r}' for k in fields + other_fields)})"
|
||||
|
||||
|
||||
@dataclass_transform()
|
||||
def dataclass_with_extra(cls: type[T]) -> type[T]:
|
||||
"""Decorator to add a custom __repr__ method to a dataclass, showing all fields, including extra ones.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from typing import Literal, Optional, Union
|
||||
from .base import BaseInferenceType, dataclass_with_extra
|
||||
|
||||
|
||||
FeatureExtractionInputTruncationDirection = Literal["Left", "Right"]
|
||||
FeatureExtractionInputTruncationDirection = Literal["left", "right"]
|
||||
|
||||
|
||||
@dataclass_with_extra
|
||||
|
||||
@@ -5,8 +5,8 @@ import traceback
|
||||
from typing import Optional
|
||||
|
||||
import typer
|
||||
from rich import print
|
||||
|
||||
from ...utils import ANSI
|
||||
from ._cli_hacks import _async_prompt, _patch_anyio_open_process
|
||||
from .agent import Agent
|
||||
from .utils import _load_agent_config
|
||||
@@ -55,10 +55,10 @@ async def run_agent(
|
||||
if first_sigint:
|
||||
first_sigint = False
|
||||
abort_event.set()
|
||||
print("\n[red]Interrupted. Press Ctrl+C again to quit.[/red]", flush=True)
|
||||
print(ANSI.red("\nInterrupted. Press Ctrl+C again to quit."), flush=True)
|
||||
return
|
||||
|
||||
print("\n[red]Exiting...[/red]", flush=True)
|
||||
print(ANSI.red("\nExiting..."), flush=True)
|
||||
exit_event.set()
|
||||
|
||||
try:
|
||||
@@ -75,8 +75,12 @@ async def run_agent(
|
||||
|
||||
if len(inputs) > 0:
|
||||
print(
|
||||
"[bold blue]Some initial inputs are required by the agent. "
|
||||
"Please provide a value or leave empty to load from env.[/bold blue]"
|
||||
ANSI.bold(
|
||||
ANSI.blue(
|
||||
"Some initial inputs are required by the agent. "
|
||||
"Please provide a value or leave empty to load from env."
|
||||
)
|
||||
)
|
||||
)
|
||||
for input_item in inputs:
|
||||
input_id = input_item["id"]
|
||||
@@ -98,15 +102,17 @@ async def run_agent(
|
||||
|
||||
if not input_usages:
|
||||
print(
|
||||
f"[yellow]Input '{input_id}' defined in config but not used by any server or as an API key."
|
||||
" Skipping.[/yellow]"
|
||||
ANSI.yellow(
|
||||
f"Input '{input_id}' defined in config but not used by any server or as an API key."
|
||||
" Skipping."
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
# Prompt user for input
|
||||
env_variable_key = input_id.replace("-", "_").upper()
|
||||
print(
|
||||
f"[blue] • {input_id}[/blue]: {description}. (default: load from {env_variable_key}).",
|
||||
ANSI.blue(f" • {input_id}") + f": {description}. (default: load from {env_variable_key}).",
|
||||
end=" ",
|
||||
)
|
||||
user_input = (await _async_prompt(exit_event=exit_event)).strip()
|
||||
@@ -118,10 +124,12 @@ async def run_agent(
|
||||
if not final_value:
|
||||
final_value = os.getenv(env_variable_key, "")
|
||||
if final_value:
|
||||
print(f"[green]Value successfully loaded from '{env_variable_key}'[/green]")
|
||||
print(ANSI.green(f"Value successfully loaded from '{env_variable_key}'"))
|
||||
else:
|
||||
print(
|
||||
f"[yellow]No value found for '{env_variable_key}' in environment variables. Continuing.[/yellow]"
|
||||
ANSI.yellow(
|
||||
f"No value found for '{env_variable_key}' in environment variables. Continuing."
|
||||
)
|
||||
)
|
||||
resolved_inputs[input_id] = final_value
|
||||
|
||||
@@ -150,9 +158,9 @@ async def run_agent(
|
||||
prompt=prompt,
|
||||
) as agent:
|
||||
await agent.load_tools()
|
||||
print(f"[bold blue]Agent loaded with {len(agent.available_tools)} tools:[/bold blue]")
|
||||
print(ANSI.bold(ANSI.blue("Agent loaded with {} tools:".format(len(agent.available_tools)))))
|
||||
for t in agent.available_tools:
|
||||
print(f"[blue] • {t.function.name}[/blue]")
|
||||
print(ANSI.blue(f" • {t.function.name}"))
|
||||
|
||||
while True:
|
||||
abort_event.clear()
|
||||
@@ -165,13 +173,13 @@ async def run_agent(
|
||||
user_input = await _async_prompt(exit_event=exit_event)
|
||||
first_sigint = True
|
||||
except EOFError:
|
||||
print("\n[red]EOF received, exiting.[/red]", flush=True)
|
||||
print(ANSI.red("\nEOF received, exiting."), flush=True)
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
if not first_sigint and abort_event.is_set():
|
||||
continue
|
||||
else:
|
||||
print("\n[red]Keyboard interrupt during input processing.[/red]", flush=True)
|
||||
print(ANSI.red("\nKeyboard interrupt during input processing."), flush=True)
|
||||
break
|
||||
|
||||
try:
|
||||
@@ -195,7 +203,7 @@ async def run_agent(
|
||||
print(f"{call.function.arguments}", end="")
|
||||
else:
|
||||
print(
|
||||
f"\n\n[green]Tool[{chunk.name}] {chunk.tool_call_id}\n{chunk.content}[/green]\n",
|
||||
ANSI.green(f"\n\nTool[{chunk.name}] {chunk.tool_call_id}\n{chunk.content}\n"),
|
||||
flush=True,
|
||||
)
|
||||
|
||||
@@ -203,12 +211,12 @@ async def run_agent(
|
||||
|
||||
except Exception as e:
|
||||
tb_str = traceback.format_exc()
|
||||
print(f"\n[bold red]Error during agent run: {e}\n{tb_str}[/bold red]", flush=True)
|
||||
print(ANSI.red(f"\nError during agent run: {e}\n{tb_str}"), flush=True)
|
||||
first_sigint = True # Allow graceful interrupt for the next command
|
||||
|
||||
except Exception as e:
|
||||
tb_str = traceback.format_exc()
|
||||
print(f"\n[bold red]An unexpected error occurred: {e}\n{tb_str}[/bold red]", flush=True)
|
||||
print(ANSI.red(f"\nAn unexpected error occurred: {e}\n{tb_str}"), flush=True)
|
||||
raise e
|
||||
|
||||
finally:
|
||||
@@ -236,10 +244,10 @@ def run(
|
||||
try:
|
||||
asyncio.run(run_agent(path))
|
||||
except KeyboardInterrupt:
|
||||
print("\n[red]Application terminated by KeyboardInterrupt.[/red]", flush=True)
|
||||
print(ANSI.red("\nApplication terminated by KeyboardInterrupt."), flush=True)
|
||||
raise typer.Exit(code=130)
|
||||
except Exception as e:
|
||||
print(f"\n[bold red]An unexpected error occurred: {e}[/bold red]", flush=True)
|
||||
print(ANSI.red(f"\nAn unexpected error occurred: {e}"), flush=True)
|
||||
raise e
|
||||
|
||||
|
||||
|
||||
@@ -57,10 +57,10 @@ def format_result(result: "mcp_types.CallToolResult") -> str:
|
||||
elif item.type == "resource":
|
||||
resource = item.resource
|
||||
|
||||
if hasattr(resource, "text"):
|
||||
if hasattr(resource, "text") and isinstance(resource.text, str):
|
||||
formatted_parts.append(resource.text)
|
||||
|
||||
elif hasattr(resource, "blob"):
|
||||
elif hasattr(resource, "blob") and isinstance(resource.blob, str):
|
||||
formatted_parts.append(
|
||||
f"[Binary Content ({resource.uri}): {resource.mimeType}, {_get_base64_size(resource.blob)} bytes]\n"
|
||||
f"The task is complete and the content accessible to the User"
|
||||
|
||||
@@ -38,8 +38,15 @@ from .nebius import (
|
||||
from .novita import NovitaConversationalTask, NovitaTextGenerationTask, NovitaTextToVideoTask
|
||||
from .nscale import NscaleConversationalTask, NscaleTextToImageTask
|
||||
from .openai import OpenAIConversationalTask
|
||||
from .ovhcloud import OVHcloudConversationalTask
|
||||
from .publicai import PublicAIConversationalTask
|
||||
from .replicate import ReplicateImageToImageTask, ReplicateTask, ReplicateTextToImageTask, ReplicateTextToSpeechTask
|
||||
from .replicate import (
|
||||
ReplicateAutomaticSpeechRecognitionTask,
|
||||
ReplicateImageToImageTask,
|
||||
ReplicateTask,
|
||||
ReplicateTextToImageTask,
|
||||
ReplicateTextToSpeechTask,
|
||||
)
|
||||
from .sambanova import SambanovaConversationalTask, SambanovaFeatureExtractionTask
|
||||
from .scaleway import ScalewayConversationalTask, ScalewayFeatureExtractionTask
|
||||
from .together import TogetherConversationalTask, TogetherTextGenerationTask, TogetherTextToImageTask
|
||||
@@ -70,6 +77,7 @@ PROVIDER_T = Literal[
|
||||
"novita",
|
||||
"nscale",
|
||||
"openai",
|
||||
"ovhcloud",
|
||||
"publicai",
|
||||
"replicate",
|
||||
"sambanova",
|
||||
@@ -166,10 +174,14 @@ PROVIDERS: dict[PROVIDER_T, dict[str, TaskProviderHelper]] = {
|
||||
"openai": {
|
||||
"conversational": OpenAIConversationalTask(),
|
||||
},
|
||||
"ovhcloud": {
|
||||
"conversational": OVHcloudConversationalTask(),
|
||||
},
|
||||
"publicai": {
|
||||
"conversational": PublicAIConversationalTask(),
|
||||
},
|
||||
"replicate": {
|
||||
"automatic-speech-recognition": ReplicateAutomaticSpeechRecognitionTask(),
|
||||
"image-to-image": ReplicateImageToImageTask(),
|
||||
"text-to-image": ReplicateTextToImageTask(),
|
||||
"text-to-speech": ReplicateTextToSpeechTask(),
|
||||
|
||||
@@ -32,6 +32,7 @@ HARDCODED_MODEL_INFERENCE_MAPPING: dict[str, dict[str, InferenceProviderMapping]
|
||||
"hyperbolic": {},
|
||||
"nebius": {},
|
||||
"nscale": {},
|
||||
"ovhcloud": {},
|
||||
"replicate": {},
|
||||
"sambanova": {},
|
||||
"scaleway": {},
|
||||
|
||||
@@ -112,7 +112,7 @@ class FalAIAutomaticSpeechRecognitionTask(FalAITask):
|
||||
text = _as_dict(response)["text"]
|
||||
if not isinstance(text, str):
|
||||
raise ValueError(f"Unexpected output format from FalAI API. Expected string, got {type(text)}.")
|
||||
return text
|
||||
return {"text": text}
|
||||
|
||||
|
||||
class FalAITextToImageTask(FalAITask):
|
||||
|
||||
@@ -72,6 +72,67 @@ class ReplicateTextToSpeechTask(ReplicateTask):
|
||||
return payload
|
||||
|
||||
|
||||
class ReplicateAutomaticSpeechRecognitionTask(ReplicateTask):
|
||||
def __init__(self) -> None:
|
||||
super().__init__("automatic-speech-recognition")
|
||||
|
||||
def _prepare_payload_as_dict(
|
||||
self,
|
||||
inputs: Any,
|
||||
parameters: dict,
|
||||
provider_mapping_info: InferenceProviderMapping,
|
||||
) -> Optional[dict]:
|
||||
mapped_model = provider_mapping_info.provider_id
|
||||
audio_url = _as_url(inputs, default_mime_type="audio/wav")
|
||||
|
||||
payload: dict[str, Any] = {
|
||||
"input": {
|
||||
**{"audio": audio_url},
|
||||
**filter_none(parameters),
|
||||
}
|
||||
}
|
||||
|
||||
if ":" in mapped_model:
|
||||
payload["version"] = mapped_model.split(":", 1)[1]
|
||||
|
||||
return payload
|
||||
|
||||
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
|
||||
response_dict = _as_dict(response)
|
||||
output = response_dict.get("output")
|
||||
|
||||
if isinstance(output, str):
|
||||
return {"text": output}
|
||||
|
||||
if isinstance(output, list) and output:
|
||||
first_item = output[0]
|
||||
if isinstance(first_item, str):
|
||||
return {"text": first_item}
|
||||
if isinstance(first_item, dict):
|
||||
output = first_item
|
||||
|
||||
text: Optional[str] = None
|
||||
if isinstance(output, dict):
|
||||
transcription = output.get("transcription")
|
||||
if isinstance(transcription, str):
|
||||
text = transcription
|
||||
|
||||
translation = output.get("translation")
|
||||
if isinstance(translation, str):
|
||||
text = translation
|
||||
|
||||
txt_file = output.get("txt_file")
|
||||
if isinstance(txt_file, str):
|
||||
text_response = get_session().get(txt_file)
|
||||
text_response.raise_for_status()
|
||||
text = text_response.text
|
||||
|
||||
if text is not None:
|
||||
return {"text": text}
|
||||
|
||||
raise ValueError("Received malformed response from Replicate automatic-speech-recognition API")
|
||||
|
||||
|
||||
class ReplicateImageToImageTask(ReplicateTask):
|
||||
def __init__(self):
|
||||
super().__init__("image-to-image")
|
||||
|
||||
Reference in New Issue
Block a user