Source code for pyrit.prompt_target.openai.openai_completion_target
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
import logging
from openai import NotGiven, NOT_GIVEN
from openai.types.completion import Completion
from typing import Optional
from pyrit.models import PromptResponse, PromptRequestResponse, construct_response_from_request
from pyrit.prompt_target import limit_requests_per_minute, OpenAITarget
logger = logging.getLogger(__name__)
[docs]
class OpenAICompletionTarget(OpenAITarget):
[docs]
def __init__(
self,
max_tokens: Optional[int] | NotGiven = NOT_GIVEN,
temperature: float = 1.0,
top_p: float = 1.0,
frequency_penalty: float = 0.0,
presence_penalty: float = 0.0,
*args,
**kwargs,
):
"""
Args:
max_tokens (int, Optional): The maximum number of tokens that can be generated in the
completion. The token count of your prompt plus `max_tokens` cannot exceed the model's
context length.
"""
super().__init__(*args, **kwargs)
self._max_tokens = max_tokens
self._temperature = temperature
self._top_p = top_p
self._frequency_penalty = frequency_penalty
self._presence_penalty = presence_penalty
def _set_azure_openai_env_configuration_vars(self):
self.deployment_environment_variable = "AZURE_OPENAI_COMPLETION_DEPLOYMENT"
self.endpoint_uri_environment_variable = "AZURE_OPENAI_COMPLETION_ENDPOINT"
self.api_key_environment_variable = "AZURE_OPENAI_COMPLETION_KEY"
@limit_requests_per_minute
async def send_prompt_async(self, *, prompt_request: PromptRequestResponse) -> PromptRequestResponse:
"""
Sends a normalized prompt async to the prompt target.
"""
self._validate_request(prompt_request=prompt_request)
request = prompt_request.request_pieces[0]
logger.info(f"Sending the following prompt to the prompt target: {request}")
text_response: Completion = await self._async_client.completions.create(
model=self._deployment_name,
prompt=request.converted_value,
top_p=self._top_p,
temperature=self._temperature,
frequency_penalty=self._frequency_penalty,
presence_penalty=self._presence_penalty,
max_tokens=self._max_tokens,
)
prompt_response = PromptResponse(
completion=text_response.choices[0].text,
prompt=request.converted_value,
id=text_response.id,
completion_tokens=text_response.usage.completion_tokens,
prompt_tokens=text_response.usage.prompt_tokens,
total_tokens=text_response.usage.total_tokens,
model=text_response.model,
object=text_response.object,
)
response_entry = construct_response_from_request(
request=request,
response_text_pieces=[prompt_response.completion],
prompt_metadata=prompt_response.to_json(),
)
return response_entry
def _validate_request(self, *, prompt_request: PromptRequestResponse) -> None:
if len(prompt_request.request_pieces) != 1:
raise ValueError("This target only supports a single prompt request piece.")
if prompt_request.request_pieces[0].converted_value_data_type != "text":
raise ValueError("This target only supports text prompt input.")
request = prompt_request.request_pieces[0]
messages = self._memory.get_chat_messages_with_conversation_id(conversation_id=request.conversation_id)
if len(messages) > 0:
raise ValueError("This target only supports a single turn conversation.")