
보안 연구 랩으로, CVE-2023-6572(GHSA-gqvf-3hgp-5hxv)를 재현합니다: gradio-app/gradio의 workflow_run이 generate-changeset.yml을 처리할 때 발생하는 명령 주입 취약점
자동화된 연구 산출물 — 업스트림 프로젝트가 아님.
이 저장소는 Université Laval의 석사 논문을 위해 자동화된 하네스가 구축한 일회용 실험실로, 공개된 GitHub Actions 워크플로우 취약점 재현을 목적으로 합니다. 이는 커밋
1d986217f6f4fc1829e528d2afe365635788204f(2023-11-03) 시점의gradio-app/gradio를 그대로 스냅샷한 것이며, 해당 프로젝트의 자체 라이선스 하에 재배포되며, 해당 라이선스 파일은 이 스냅샷에 변경 없이 포함되어 있습니다.업스트림 프로젝트는 관여하지 않으며, 결코 공격 대상이 아니며, 여기서 연구된 취약점은 이미 공개된 상태입니다. 이 저장소의 모든 비밀값과 변수는 무작위로 생성된 더미 값입니다 — 실제 자격 증명은 존재하지 않습니다. 액션 참조와 러너 이미지는 2023-11-03에 확인된 값으로 고정되어 있습니다. 스냅샷에 적용된 모든 변경 사항은 하네스 출력의
pinning.md를 참조하세요.질문 또는 이의 제기: [email protected]
Website | Documentation | Guides | Getting Started | Examples | 中文
Gradio는 머신러닝 및 데이터 사이언스 데모와 웹 애플리케이션을 구축하는 데 사용되는 오픈소스 Python 라이브러리입니다.
Gradio를 사용하면 머신러닝 모델이나 데이터 사이언스 워크플로우 주변에 아름다운 사용자 인터페이스를 빠르게 만들 수 있으며, 사용자들이 브라우저를 통해 자신의 이미지를 드래그 앤 드롭하고, 텍스트를 붙여넣고, 자신의 목소리를 녹음하고, 데모와 상호작용하며 "직접 체험"할 수 있습니다.

Gradio는 다음과 같은 경우에 유용합니다:
클라이언트/협업자/사용자/학생을 위한 머신러닝 모델 데모 제공.
자동 공유 링크로 모델을 빠르게 배포하고 모델 성능에 대한 피드백 받기.
개발 중 내장된 입력 조작 도구를 사용하여 모델을 대화형으로 디버깅.
사전 요구사항: Gradio는 Python 3.8 이상이 필요합니다. 그게 전부입니다!
머신러닝 모델, API 또는 데이터 사이언스 워크플로우를 다른 사람들과 공유하는 가장 좋은 방법 중 하나 는 사용자나 동료가 브라우저에서 데모를 직접 체험할 수 있는 대화형 앱을 만드는 것입니다.
Gradio를 사용하면 데모를 만들고 공유하는 모든 것을 Python으로 할 수 있습니다. 그리고 보통 단 몇 줄의 코드만으로 가능합니다! 시작해 봅시다.
간단한 "Hello, World" 예제로 Gradio를 실행하려면 다음 세 단계를 따르세요:
1. pip로 Gradio를 설치합니다:
pip install gradio
2. 아래 코드를 Python 스크립트 또는 Jupyter Notebook(또는 Google Colab)에서 실행합니다:
import gradio as gr
def greet(name):
return "Hello " + name + "!"
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch()
Gradio를 사용하는 코드의 가독성을 높이기 위해 import된 이름을 gr로 줄여 사용합니다. 이는 널리 채택된 관례이므로, 여러분의 코드를 작업하는 모든 사람이 쉽게 이해할 수 있도록 이 관례를 따르는 것이 좋습니다.
3. 아래 데모는 Jupyter Notebook 내에서 자동으로 나타나거나, 스크립트에서 실행하는 경우 http://localhost:7860의 브라우저에 팝업으로 표시됩니다:

로컬에서 개발할 때 코드를 Python 스크립트로 실행하려면 Gradio CLI를 사용하여 리로드 모드로 애플리케이션을 실행할 수 있으며, 이는 원활하고 빠른 개발을 제공합니다. 리로딩에 대한 자세한 내용은 자동 리로드 가이드에서 확인하세요.
gradio app.py
참고: python app.py로도 실행할 수 있지만, 자동 리로드 메커니즘은 제공되지 않습니다.
Interface 클래스데모를 만들기 위해 gr.Interface를 생성한 것을 확인할 수 있습니다. 이 Interface 클래스는 모든 Python 함수를 사용자 인터페이스로 감쌀 수 있습니다. 위의 예제에서는 간단한 텍스트 기반 함수를 보았지만, 함수는 음악 생성기부터 세금 계산기, 사전 훈련된 머신러닝 모델의 예측 함수까지 무엇이든 될 수 있습니다.
핵심 Interface 클래스는 세 가지 필수 매개변수로 초기화됩니다:
fn: UI로 감쌀 함수inputs: 입력에 사용할 컴포넌트 (예: "text", "image" 또는 "audio")outputs: 출력에 사용할 컴포넌트 (예: "text", "image" 또는 "label")입력과 출력을 제공하는 데 사용되는 이러한 컴포넌트를 자세히 살펴보겠습니다.
이전 예제에서 간단한 Textbox 컴포넌트를 보았지만, UI 컴포넌트의 모양이나 동작을 변경하려면 어떻게 해야 할까요?
입력 텍스트 필드를 사용자 지정하고 싶다고 가정해 봅시다 — 예를 들어 더 크게 만들고 텍스트 플레이스홀더를 추가하고 싶다면요. 문자열 단축키 대신 실제 Textbox 클래스를 사용하면 컴포넌트 속성을 통해 훨씬 더 많은 사용자 지정이 가능합니다.
import gradio as gr
def greet(name):
return "Hello " + name + "!"
demo = gr.Interface(
fn=greet,
inputs=gr.Textbox(lines=2, placeholder="Name Here..."),
outputs="text",
)
demo.launch()

여러 입력과 출력을 가진 더 복잡한 함수가 있다고 가정해 봅시다. 아래 예제에서는 문자열, 불리언, 숫자를 받아 문자열과 숫자를 반환하는 함수를 정의합니다. 입력 및 출력 컴포넌트 목록을 전달하는 방법을 살펴보세요.
import gradio as gr
def greet(name, is_morning, temperature):
salutation = "Good morning" if is_morning else "Good evening"
greeting = f"{salutation} {name}. It is {temperature} degrees today"
celsius = (temperature - 32) * 5 / 9
return greeting, round(celsius, 2)
demo = gr.Interface(
fn=greet,
inputs=["text", "checkbox", gr.Slider(0, 100)],
outputs=["text", "number"],
)
demo.launch()

컴포넌트를 리스트로 감싸기만 하면 됩니다. inputs 리스트의 각 컴포넌트는 함수의 매개변수 중 하나에 순서대로 대응합니다. outputs 리스트의 각 컴포넌트는 함수가 반환하는 값 중 하나에 역시 순서대로 대응합니다.
Gradio는 Image, DataFrame, Video, Label과 같은 다양한 유형의 컴포넌트를 지원합니다. 이미지 간 변환 함수를 사용해 이러한 기능을 체험해 봅시다!
import numpy as np
import gradio as gr
def sepia(input_img):
sepia_filter = np.array([
[0.393, 0.769, 0.189],
[0.349, 0.686, 0.168],
[0.272, 0.534, 0.131]
])
sepia_img = input_img.dot(sepia_filter.T)
sepia_img /= sepia_img.max()
return sepia_img
demo = gr.Interface(sepia, gr.Image(width=200, height=200), "image")
demo.launch()

Image 컴포넌트를 입력으로 사용하면 함수는 (height, width, 3) 형태의 NumPy 배열을 받게 되며, 마지막 차원은 RGB 값을 나타냅니다. NumPy 배열 형태로 이미지도 반환합니다.
type= 키워드 인자를 사용하여 컴포넌트가 사용하는 데이터 유형을 설정할 수도 있습니다. 예를 들어 함수가 NumPy 배열 대신 이미지의 파일 경로를 받도록 하려면 입력 Image 컴포넌트를 다음과 같이 작성할 수 있습니다:
gr.Image(type="filepath", shape=...)
또한 입력 Image 컴포넌트에는 이미지 자르기와 확대/축소를 가능하게 하는 편집 버튼 🖉이 포함되어 있습니다. 이러한 방식으로 이미지를 조작하면 머신러닝 모델의 편향이나 숨겨진 결함을 발견하는 데 도움이 될 수 있습니다!
다양한 컴포넌트와 사용 방법에 대한 자세한 내용은 Gradio 문서에서 확인할 수 있습니다.
Gradio에는 gr.Interface와 유사하지만 챗봇 UI를 위해 특별히 설계된 고수준 클래스인 gr.ChatInterface가 포함되어 있습니다. gr.ChatInterface 클래스도 함수를 감싸지만, 이 함수는 특정 시그니처를 가져야 합니다. 함수는 두 개의 인자를 받아야 합니다: message와 history (인자 이름은 무엇이든 될 수 있지만 순서는 이대로여야 합니다)
message: 사용자 입력을 나타내는 strhistory: 해당 시점까지의 대화를 나타내는 list의 list. 각 내부 리스트는 [사용자 입력, 봇 응답] 쌍을 나타내는 두 개의 str로 구성됩니다.함수는 특정 사용자 입력 message에 대한 봇의 응답인 단일 문자열 응답을 반환해야 합니다.
그 외에 gr.ChatInterface에는 필수 매개변수가 없습니다 (UI 사용자 지정을 위한 여러 옵션은 제공됩니다).
간단한 예제입니다:
import random
import gradio as gr
def random_response(message, history):
return random.choice(["Yes", "No"])
demo = gr.ChatInterface(random_response)
demo.launch()

Gradio는 앱을 구축하는 두 가지 접근 방식을 제공합니다:
1. 지금까지 논의한 데모 생성을 위한 고수준 추상화를 제공하는 Interface 및 ChatInterface.
2. 더 유연한 레이아웃과 데이터 흐름으로 웹 앱을 설계하기 위한 저수준 API인 Blocks. Blocks를 사용하면 여러 데이터 흐름과 데모를 제공하고, 페이지에서 컴포넌트가 표시되는 위치를 제어하고, 복잡한 데이터 흐름(예: 출력이 다른 함수의 입력으로 사용될 수 있음)을 처리하고, 사용자 상호작용에 따라 컴포넌트의 속성/표시 여부를 업데이트할 수 있습니다 — 이 모든 것이 여전히 Python으로 가능합니다. 이러한 사용자 지정이 필요하다면 Blocks를 사용해 보세요!
간단한 예제를 살펴보겠습니다. 여기서 API가 Interface와 어떻게 다른지 주목하세요.
import gradio as gr
def greet(name):
return "Hello " + name + "!"
with gr.Blocks() as demo:
name = gr.Textbox(label="Name")
output = gr.Textbox(label="Output Box")
greet_btn = gr.Button("Greet")
greet_btn.click(fn=greet, inputs=name, outputs=output, api_name="greet")
demo.launch()

참고할 사항:
Blocks는 with 절로 생성되며, 이 절 내에서 생성된 모든 컴포넌트는 자동으로 앱에 추가됩니다.Button이 생성된 후 이 버튼에 click 이벤트 리스너가 추가되었습니다. 이 API는 익숙해 보일 것입니다! Interface와 마찬가지로 click 메서드는 Python 함수, 입력 컴포넌트, 출력 컴포넌트를 받습니다.Blocks로 가능한 것을 맛볼 수 있는 앱입니다:
import numpy as np
import gradio as gr
def flip_text(x):
return x[::-1]
def flip_image(x):
return np.fliplr(x)
with gr.Blocks() as demo:
gr.Markdown("Flip text or image files using this demo.")
with gr.Tab("Flip Text"):
text_input = gr.Textbox()
text_output = gr.Textbox()
text_button = gr.Button("Flip")
with gr.Tab("Flip Image"):
with gr.Row():
image_input = gr.Image()
image_output = gr.Image()
image_button = gr.Button("Flip")
with gr.Accordion("Open for More!"):
gr.Markdown("Look at me...")
text_button.click(flip_text, inputs=text_input, outputs=text_output)
image_button.click(flip_image, inputs=image_input, outputs=image_output)
demo.launch()

훨씬 더 많은 것이 진행되고 있습니다! 이와 같은 복잡한 Blocks 앱을 만드는 방법은 building with blocks 섹션에서 다룰 것입니다.
축하합니다! 이제 Gradio의 기본을 익혔습니다! 🥳 Gradio의 주요 기능에 대해 더 알아보려면 다음 가이드로 이동하세요.
Gradio는 많은 훌륭한 오픈소스 라이브러리로 구축되었습니다. 이들도 함께 지원해 주세요!
Gradio는 이 저장소의 루트 디렉터리에 있는 LICENSE 파일에 명시된 Apache License 2.0에 따라 라이선스가 부여됩니다.
또한 논문 _Gradio: Hassle-Free Sharing and Testing of ML Models in the Wild, ICML HILL 2019_을 확인하고, 작업에서 Gradio를 사용한다면 인용해 주세요.
@article{abid2019gradio,
title = {Gradio: Hassle-Free Sharing and Testing of ML Models in the Wild},
author = {Abid, Abubakar and Abdalla, Ali and Abid, Ali and Khan, Dawood and Alfozan, Abdulrahman and Zou, James},
journal = {arXiv preprint arXiv:1906.02569},
year = {2019},
}