chore: import upstream snapshot with attribution
tools_continuous_delivery / Private PyPI non-main branch release (push) Has been skipped
tools_continuous_delivery / Private PyPI main branch release (push) Failing after 2m42s
Publish Promptflow Doc / Build (push) Has been cancelled
Publish Promptflow Doc / Deploy (push) Has been cancelled
Flake8 Lint / flake8 (push) Has been cancelled
Spell check CI / Spell_Check (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:52 +08:00
commit e768098d0e
4004 changed files with 2804145 additions and 0 deletions
@@ -0,0 +1,184 @@
import logging
import logging.config
import re
from pathlib import Path
from typing import List
import promptflow
import yaml
from openai import AzureOpenAI
from promptflow.connections import AzureOpenAIConnection
from tenacity import (
RetryError,
Retrying,
after_log,
before_sleep_log,
stop_after_attempt,
wait_random_exponential,
)
class Logger:
"""
A class for setting up and getting a logger object.
Attributes:
config_file (str): Path to the YAML file containing the logger configuration.
logger (logging.Logger): The logger object.
"""
def __init__(self):
"""
Initializes the Logger class.
Args:
config_file (str): Path to YAML file containing the logger configuration.
"""
config_file = Path(__file__).parent.joinpath("log_config.yaml").resolve()
with open(config_file, "r") as f:
config = yaml.safe_load(f.read())
logging.config.dictConfig(config)
self.logger = logging.getLogger(__name__)
def get_logger(self):
"""
Returns the logger object.
Returns:
logging.Logger: The logger object.
"""
return self.logger
logger = Logger().get_logger()
def parse_output(output: str, max: float) -> float:
"""
Function that extracts numerical score from the beginning of string
Args:
output (str): String to search
max (float): Maximum score allowed
Returns:
float: The extracted score
"""
# match with either non-negative float or integer
# if number has non-whitespace characture before that, it won't match
matched: List[str] = re.findall(r"(?<!\S)\d+(?:\.\d+)?", output)
if matched:
if len(matched) == 1:
score = float(matched[0])
if score > max:
raise ValueError(
f"Parsed number: {score} was larger than max score: {max}"
)
else:
raise ValueError(
f"More than one number detected in input. Input to parser was: {output}"
)
else:
raise ValueError(
f'No number detected in input. Input to parser was "{output}". '
)
return score
@promptflow.tool
def geval_summarization(
prompt_with_src_and_gen: str,
max_score: float,
connection: AzureOpenAIConnection,
deployment_name: str = "gpt-4",
) -> float:
"""Using GPT, evaluate a generated summary with respect to a source document from
which it was generated. This function should be used for four dimensions of
summarization evaluation inline with the SummEval benchmark: fluency, coherence,
consistency, relevance.
Args:
prompt_with_src_and_gen (str): The prompt containing the source document and generated summary.
max_score (float): The maximum score allowed.
connection (AzureOpenAIConnection): The connection object for Azure OpenAI.
deployment_name (str, optional): The name of the deployment. Defaults to "gpt-4".
Returns:
float: The evaluation score
"""
# make sure you use the same api version/model with the one used for meta evaluation
logger.info(
f"OpenAI API Base: {connection.api_base} - Version: {connection.api_version}"
f" - Deployment: {deployment_name}"
)
client = AzureOpenAI(
azure_endpoint=connection.api_base,
api_version=connection.api_version,
api_key=connection.api_key,
)
message = {"role": "system", "content": prompt_with_src_and_gen}
try:
for attempt in Retrying(
reraise=True,
before_sleep=before_sleep_log(logger, logging.INFO),
after=after_log(logger, logging.INFO),
wait=wait_random_exponential(multiplier=1, min=1, max=120),
stop=stop_after_attempt(10),
):
with attempt:
response = client.chat.completions.create(
model=deployment_name,
messages=[message],
temperature=2,
max_tokens=5,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=None,
n=20,
)
except RetryError:
logger.exception(f"geval openai call failed\nInput prompt was: {message}")
raise
all_responses = []
for i in range(len(response.choices)):
try:
content = response.choices[i].message.content
all_responses.append(content)
except KeyError:
# `content` won't exist in returned json when openai content_filter is triggered
logger.exception(
f"""data with key missing was: {response.choices[i]}\nInput prompt was: {message}"""
)
return aggregate_llm_scores(all_responses, max_score=max_score)
def aggregate_llm_scores(llm_responses: List[str], max_score: int) -> float:
"""Parse and average valid scores from the generated responses of
the G-Eval LLM call.
Args:
llm_responses (List[str]): List of scores from multiple LLMs
max_score (float): The maximum score allowed.
Returns:
float: The average of all the valid scores
"""
all_scores = []
error_count = 0
for generated in llm_responses:
try:
parsed = parse_output(generated, max_score)
all_scores.append(parsed)
except ValueError as e:
logger.warning(e)
error_count += 1
if error_count:
logger.warning(
f"{error_count} out of 20 scores were discarded due to corrupt g-eval generation"
)
score = sum(all_scores) / len(all_scores)
return score