CC BY 4.0 (除特别声明或转载文章外)
如果这篇博客帮助到你,可以请我喝一杯咖啡~
gradio
NLP Tasks interface
加载HFAPI和相关库
import os
import io
from IPython.display import Image, display, HTML
from PIL import Image
import base64
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']
# Helper function
import requests, json
#Summarization endpoint
def get_completion(inputs, parameters=None,ENDPOINT_URL=os.environ['HF_API_SUMMARY_BASE']):
headers = {
"Authorization": f"Bearer {hf_api_key}",
"Content-Type": "application/json"
}
data = { "inputs": inputs }
if parameters is not None:
data.update({"parameters": parameters})
response = requests.request("POST",
ENDPOINT_URL, headers=headers,
data=json.dumps(data)
)
return json.loads(response.content.decode("utf-8"))
怎么本地运行
跟API差不多,具体看pipeline流程
from transformers import pipeline
get_completion = pipeline("summarization", model="shleifer/distilbart-cnn-12-6")
def summarize(input):
output = get_completion(input)
return output[0]['summary_text']
构建一个文本总结APP
text = ('''The tower is 324 metres (1,063 ft) tall, about the same height
as an 81-storey building, and the tallest structure in Paris.
Its base is square, measuring 125 metres (410 ft) on each side.
During its construction, the Eiffel Tower surpassed the Washington
Monument to become the tallest man-made structure in the world,
a title it held for 41 years until the Chrysler Building
in New York City was finished in 1930. It was the first structure
to reach a height of 300 metres. Due to the addition of a broadcasting
aerial at the top of the tower in 1957, it is now taller than the
Chrysler Building by 5.2 metres (17 ft). Excluding transmitters, the
Eiffel Tower is the second tallest free-standing structure in France
after the Millau Viaduct.''')
get_completion(text)
使用 Gradio gr.Interface 启动
import gradio as gr
def summarize(input):
output = get_completion(input)
return output[0]['summary_text']
gr.close_all()
demo = gr.Interface(fn=summarize, inputs="text", outputs="text")
demo.launch(share=True, server_port=int(os.environ['PORT1']))
demo.launch(share=True) 可以分享公共连接
import gradio as gr
def summarize(input):
output = get_completion(input)
return output[0]['summary_text']
gr.close_all()
demo = gr.Interface(fn=summarize,
inputs=[gr.Textbox(label="Text to summarize", lines=6)],
outputs=[gr.Textbox(label="Result", lines=3)],
title="Text summarization with distilbart-cnn",
description="Summarize any text using the `shleifer/distilbart-cnn-12-6` model under the hood!"
)
demo.launch(share=True, server_port=int(os.environ['PORT2']))
构架一个名字实体识别APP
我们用dslim/bert-base-NER的推理端点,一个108M参数的针对NER微调的BART模型
- 怎么本地运行 ```python
from transformers import pipeline
get_completion = pipeline(“ner”, model=”dslim/bert-base-NER”)
def ner(input): output = get_completion(input) return {“text”: input, “entities”: output}
```python
API_URL = os.environ['HF_API_NER_BASE'] #NER endpoint
text = "My name is Andrew, I'm building DeepLearningAI and I live in California"
get_completion(text, parameters=None, ENDPOINT_URL= API_URL)
gr.interface()
- 注意这里的 input 和 output 都传递了一个[],因为ner()不止一个输入输出
- 输入输出的传递记得对应enr()函数参数和输出
def ner(input):
output = get_completion(input, parameters=None, ENDPOINT_URL=API_URL)
return {"text": input, "entities": output}
gr.close_all()
demo = gr.Interface(fn=ner,
inputs=[gr.Textbox(label="Text to find entities", lines=2)],
outputs=[gr.HighlightedText(label="Text with entities")],
title="NER with dslim/bert-base-NER",
description="Find entities using the `dslim/bert-base-NER` model under the hood!",
allow_flagging="never",
#Here we introduce a new tag, examples, easy to use examples for your application
examples=["My name is Andrew and I live in California", "My name is Poli and work at HuggingFace"])
demo.launch(share=True, server_port=int(os.environ['PORT3']))
添加辅助函数合并token
def merge_tokens(tokens):
merged_tokens = []
for token in tokens:
if merged_tokens and token['entity'].startswith('I-') and merged_tokens[-1]['entity'].endswith(token['entity'][2:]):
# If current token continues the entity of the last one, merge them
last_token = merged_tokens[-1]
last_token['word'] += token['word'].replace('##', '')
last_token['end'] = token['end']
last_token['score'] = (last_token['score'] + token['score']) / 2
else:
# Otherwise, add the token to the list
merged_tokens.append(token)
return merged_tokens
def ner(input):
output = get_completion(input, parameters=None, ENDPOINT_URL=API_URL)
merged_tokens = merge_tokens(output)
return {"text": input, "entities": merged_tokens}
gr.close_all()
demo = gr.Interface(fn=ner,
inputs=[gr.Textbox(label="Text to find entities", lines=2)],
outputs=[gr.HighlightedText(label="Text with entities")],
title="NER with dslim/bert-base-NER",
description="Find entities using the `dslim/bert-base-NER` model under the hood!",
allow_flagging="never",
examples=["My name is Andrew, I'm building DeeplearningAI and I live in California", "My name is Poli, I live in Vienna and work at HuggingFace"])
demo.launch(share=True, server_port=int(os.environ['PORT4']))
gr.close_all()
怎么获取自己的HF API Key
安全使用自己的key
- 在项目根目录下创建
.env
文件 - 文件包含
HF_API_KEY="ABC!@#XXX"
- 保存文件
- 安装
Python-dotenv
,使得在jupyter下第一次cell运行pip install python-dotenv
创建图片捕获APP
import os import io import IPython.display from PIL import Image import base64 from dotenv import load_dotenv, find_dotenv _ = load_dotenv(find_dotenv()) # read local .env file hf_api_key = os.environ['HF_API_KEY']
```python
Helper functions
import requests, json
#Image-to-text endpoint def get_completion(inputs, parameters=None, ENDPOINT_URL=os.environ[‘HF_API_ITT_BASE’]): headers = { “Authorization”: f”Bearer {hf_api_key}”, “Content-Type”: “application/json” } data = { “inputs”: inputs } if parameters is not None: data.update({“parameters”: parameters}) response = requests.request(“POST”, ENDPOINT_URL, headers=headers, data=json.dumps(data)) return json.loads(response.content.decode(“utf-8”))
### 构建图片捕获APP
`Salesforce/blip-image-captioning-base`,一个14M参数的模型
```python
image_url = "https://free-images.com/sm/9596/dog_animal_greyhound_983023.jpg"
display(IPython.display.Image(url=image_url))
get_completion(image_url)
gr.Interface()
-
类型参数是FN函数期望接收到其输入的格式。如果类型为numpy或pil,则Gr.image()将将上传的文件转换为此格式,然后将其发送到FN函数。
-
如果类型是filepath,则Gr.image()将临时存储图像,并为该图像位置提供字符串路径作为FN函数的输入。
import gradio as gr
def image_to_base64_str(pil_image):
byte_arr = io.BytesIO()
pil_image.save(byte_arr, format='PNG')
byte_arr = byte_arr.getvalue()
return str(base64.b64encode(byte_arr).decode('utf-8'))
def captioner(image):
base64_image = image_to_base64_str(image)
result = get_completion(base64_image)
return result[0]['generated_text']
gr.close_all()
demo = gr.Interface(fn=captioner,
inputs=[gr.Image(label="Upload image", type="pil")],
outputs=[gr.Textbox(label="Caption")],
title="Image Captioning with BLIP",
description="Caption any image using the BLIP model",
allow_flagging="never",
examples=["christmas_dog.jpeg", "bird_flight.jpeg", "cow.jpeg"])
demo.launch(share=True, server_port=int(os.environ['PORT1']))
图片生成APP
import os
import io
import IPython.display
from PIL import Image
import base64
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']
# Helper function
import requests, json
#Text-to-image endpoint
def get_completion(inputs, parameters=None, ENDPOINT_URL=os.environ['HF_API_TTI_BASE']):
headers = {
"Authorization": f"Bearer {hf_api_key}",
"Content-Type": "application/json"
}
data = { "inputs": inputs }
if parameters is not None:
data.update({"parameters": parameters})
response = requests.request("POST",
ENDPOINT_URL,
headers=headers,
data=json.dumps(data))
return json.loads(response.content.decode("utf-8"))
构建图片生成APP
runwayml/stable-diffusion-v1-5
,🧨 diffusers
库里的
prompt = "a dog in a park"
result = get_completion(prompt)
IPython.display.HTML(f'<img src="data:image/png;base64,{result}" />')
gr.Interface()
import gradio as gr
#A helper function to convert the PIL image to base64
#so you can send it to the API
def base64_to_pil(img_base64):
base64_decoded = base64.b64decode(img_base64)
byte_stream = io.BytesIO(base64_decoded)
pil_image = Image.open(byte_stream)
return pil_image
def generate(prompt):
output = get_completion(prompt)
result_image = base64_to_pil(output)
return result_image
gr.close_all()
demo = gr.Interface(fn=generate,
inputs=[gr.Textbox(label="Your prompt")],
outputs=[gr.Image(label="Result")],
title="Image Generation with Stable Diffusion",
description="Generate any image with Stable Diffusion",
allow_flagging="never",
examples=["the spirit of a tamagotchi wandering in the city of Vienna","a mecha robot in a favela"])
demo.launch(share=True, server_port=int(os.environ['PORT1']))
高级交互
import gradio as gr
#A helper function to convert the PIL image to base64
# so you can send it to the API
def base64_to_pil(img_base64):
base64_decoded = base64.b64decode(img_base64)
byte_stream = io.BytesIO(base64_decoded)
pil_image = Image.open(byte_stream)
return pil_image
def generate(prompt, negative_prompt, steps, guidance, width, height):
params = {
"negative_prompt": negative_prompt,
"num_inference_steps": steps,
"guidance_scale": guidance,
"width": width,
"height": height
}
output = get_completion(prompt, params)
pil_image = base64_to_pil(output)
return pil_image
gr.Slider()
- 可设置 minimum,maximum 和开始值
- 希望滑块整数增加,可设置 step=1
gr.close_all()
demo = gr.Interface(fn=generate,
inputs=[
gr.Textbox(label="Your prompt"),
gr.Textbox(label="Negative prompt"),
gr.Slider(label="Inference Steps", minimum=1, maximum=100, value=25,
info="In how many steps will the denoiser denoise the image?"),
gr.Slider(label="Guidance Scale", minimum=1, maximum=20, value=7,
info="Controls how much the text prompt influences the result"),
gr.Slider(label="Width", minimum=64, maximum=512, step=64, value=512),
gr.Slider(label="Height", minimum=64, maximum=512, step=64, value=512),
],
outputs=[gr.Image(label="Result")],
title="Image Generation with Stable Diffusion",
description="Generate any image with Stable Diffusion",
allow_flagging="never"
)
demo.launch(share=True, server_port=int(os.environ['PORT2']))
gr.Blocks()
在gr.blocks()中,您可以定义多个gr.row()s或多个gr.column()s。
请注意,如果Jupyter笔记本非常狭窄,则布局可能会更改以更好地显示对象。如果您定义了两列但看不到应用程序中的两个列,请尝试扩展Web浏览器的宽度,以及包含此Jupyter笔记本的屏幕。
使用gr.blocks()时,您需要使用gr.button()明确定义“提交”按钮,而当使用gr.interface()时,将自动添加’clear’‘和’提交’按钮。
with gr.Blocks() as demo:
gr.Markdown("# Image Generation with Stable Diffusion")
prompt = gr.Textbox(label="Your prompt")
with gr.Row():
with gr.Column():
negative_prompt = gr.Textbox(label="Negative prompt")
steps = gr.Slider(label="Inference Steps", minimum=1, maximum=100, value=25,
info="In many steps will the denoiser denoise the image?")
guidance = gr.Slider(label="Guidance Scale", minimum=1, maximum=20, value=7,
info="Controls how much the text prompt influences the result")
width = gr.Slider(label="Width", minimum=64, maximum=512, step=64, value=512)
height = gr.Slider(label="Height", minimum=64, maximum=512, step=64, value=512)
btn = gr.Button("Submit")
with gr.Column():
output = gr.Image(label="Result")
btn.click(fn=generate, inputs=[prompt,negative_prompt,steps,guidance,width,height], outputs=[output])
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT3']))
规模
要选择要给每一列的相对宽度多少,请设置每个gr.column()的比例参数。
如果一列的比例= 4,而第二列的比例= 1,则第一列占总宽度的4/5,第二列占总宽度的1/5。
gr.Accordion()
gr.accordion()可以使用鼠标单击显示/隐藏应用程序选项。
设置open = true默认情况下显示手风琴的内容,或false默认将其隐藏。
with gr.Blocks() as demo:
gr.Markdown("# Image Generation with Stable Diffusion")
with gr.Row():
with gr.Column(scale=4):
prompt = gr.Textbox(label="Your prompt") #Give prompt some real estate
with gr.Column(scale=1, min_width=50):
btn = gr.Button("Submit") #Submit button side by side!
with gr.Accordion("Advanced options", open=False): #Let's hide the advanced options!
negative_prompt = gr.Textbox(label="Negative prompt")
with gr.Row():
with gr.Column():
steps = gr.Slider(label="Inference Steps", minimum=1, maximum=100, value=25,
info="In many steps will the denoiser denoise the image?")
guidance = gr.Slider(label="Guidance Scale", minimum=1, maximum=20, value=7,
info="Controls how much the text prompt influences the result")
with gr.Column():
width = gr.Slider(label="Width", minimum=64, maximum=512, step=64, value=512)
height = gr.Slider(label="Height", minimum=64, maximum=512, step=64, value=512)
output = gr.Image(label="Result") #Move the output up too
btn.click(fn=generate, inputs=[prompt,negative_prompt,steps,guidance,width,height], outputs=[output])
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT4']))
构建游戏
import os
import io
from IPython.display import Image, display, HTML
from PIL import Image
import base64
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']
#### Helper function
import requests, json
#Here we are going to call multiple endpoints!
def get_completion(inputs, parameters=None, ENDPOINT_URL=""):
headers = {
"Authorization": f"Bearer {hf_api_key}",
"Content-Type": "application/json"
}
data = { "inputs": inputs }
if parameters is not None:
data.update({"parameters": parameters})
response = requests.request("POST",
ENDPOINT_URL,
headers=headers,
data=json.dumps(data))
return json.loads(response.content.decode("utf-8"))
#text-to-image
TTI_ENDPOINT = os.environ['HF_API_TTI_BASE']
#image-to-text
ITT_ENDPOINT = os.environ['HF_API_ITT_BASE']
gr.Blocks()构建游戏
#Bringing the functions from lessons 3 and 4!
def image_to_base64_str(pil_image):
byte_arr = io.BytesIO()
pil_image.save(byte_arr, format='PNG')
byte_arr = byte_arr.getvalue()
return str(base64.b64encode(byte_arr).decode('utf-8'))
def base64_to_pil(img_base64):
base64_decoded = base64.b64decode(img_base64)
byte_stream = io.BytesIO(base64_decoded)
pil_image = Image.open(byte_stream)
return pil_image
def captioner(image):
base64_image = image_to_base64_str(image)
result = get_completion(base64_image, None, ITT_ENDPOINT)
return result[0]['generated_text']
def generate(prompt):
output = get_completion(prompt, None, TTI_ENDPOINT)
result_image = base64_to_pil(output)
return result_image
首次尝试捕获
import gradio as gr
with gr.Blocks() as demo:
gr.Markdown("# Describe-and-Generate game 🖍️")
image_upload = gr.Image(label="Your first image",type="pil")
btn_caption = gr.Button("Generate caption")
caption = gr.Textbox(label="Generated caption")
btn_caption.click(fn=captioner, inputs=[image_upload], outputs=[caption])
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT1']))
增加生成
with gr.Blocks() as demo:
gr.Markdown("# Describe-and-Generate game 🖍️")
image_upload = gr.Image(label="Your first image",type="pil")
btn_caption = gr.Button("Generate caption")
caption = gr.Textbox(label="Generated caption")
btn_image = gr.Button("Generate image")
image_output = gr.Image(label="Generated Image")
btn_caption.click(fn=captioner, inputs=[image_upload], outputs=[caption])
btn_image.click(fn=generate, inputs=[caption], outputs=[image_output])
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT2']))
一次性做完
def caption_and_generate(image):
caption = captioner(image)
image = generate(caption)
return [caption, image]
with gr.Blocks() as demo:
gr.Markdown("# Describe-and-Generate game 🖍️")
image_upload = gr.Image(label="Your first image",type="pil")
btn_all = gr.Button("Caption and generate")
caption = gr.Textbox(label="Generated caption")
image_output = gr.Image(label="Generated Image")
btn_all.click(fn=caption_and_generate, inputs=[image_upload], outputs=[caption, image_output])
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT3']))
构建 ChatBot
import os
import io
import IPython.display
from PIL import Image
import base64
import requests
requests.adapters.DEFAULT_TIMEOUT = 60
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
hf_api_key = os.environ['HF_API_KEY']
# Helper function
import requests, json
from text_generation import Client
#FalcomLM-instruct endpoint on the text_generation library
client = Client(os.environ['HF_API_FALCOM_BASE'], headers={"Authorization": f"Basic {hf_api_key}"}, timeout=120)
在任何LLM上构建chatbot
falcon-40b-instruct
prompt = "Has math been invented or discovered?"
client.generate(prompt, max_new_tokens=256).generated_text
#Back to Lesson 2, time flies!
import gradio as gr
def generate(input, slider):
output = client.generate(input, max_new_tokens=slider).generated_text
return output
demo = gr.Interface(fn=generate,
inputs=[gr.Textbox(label="Prompt"),
gr.Slider(label="Max new tokens",
value=20,
maximum=1024,
minimum=1)],
outputs=[gr.Textbox(label="Completion")])
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT1']))
gr.Chatbot()
gr.Chatbot()
允许您保存用户和LLM之间的聊天历史,并在应用程序中显示对话。- 定义您的
fn
以接收一个gr.Chatbot()
对象。- 在您定义的
fn
函数中,添加一个包含用户消息和LLM响应的元组(或列表):chatbot_object.append( (user_message, llm_message) )
- 在您定义的
- 在应用程序的输入和输出中都包含聊天机器人对象。
import random
def respond(message, chat_history):
#No LLM here, just respond with a random pre-made message
bot_message = random.choice(["Tell me more about it",
"Cool, but I'm not interested",
"Hmmmm, ok then"])
chat_history.append((message, bot_message))
return "", chat_history
with gr.Blocks() as demo:
chatbot = gr.Chatbot(height=240) #just to fit the notebook
msg = gr.Textbox(label="Prompt")
btn = gr.Button("Submit")
clear = gr.ClearButton(components=[msg, chatbot], value="Clear console")
btn.click(respond, inputs=[msg, chatbot], outputs=[msg, chatbot])
msg.submit(respond, inputs=[msg, chatbot], outputs=[msg, chatbot]) #Press enter to submit
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT2']))
使用聊天历史格式化提示
- 您可以使用for循环遍历聊天机器人对象。
- 每个项目都是一个元组,包含用户消息和LLM的消息。
for turn in chat_history:
user_msg, bot_msg = turn
...
def format_chat_prompt(message, chat_history):
prompt = ""
for turn in chat_history:
user_message, bot_message = turn
prompt = f"{prompt}\nUser: {user_message}\nAssistant: {bot_message}"
prompt = f"{prompt}\nUser: {message}\nAssistant:"
return prompt
def respond(message, chat_history):
formatted_prompt = format_chat_prompt(message, chat_history)
bot_message = client.generate(formatted_prompt,
max_new_tokens=1024,
stop_sequences=["\nUser:", "<|endoftext|>"]).generated_text
chat_history.append((message, bot_message))
return "", chat_history
with gr.Blocks() as demo:
chatbot = gr.Chatbot(height=240) #just to fit the notebook
msg = gr.Textbox(label="Prompt")
btn = gr.Button("Submit")
clear = gr.ClearButton(components=[msg, chatbot], value="Clear console")
btn.click(respond, inputs=[msg, chatbot], outputs=[msg, chatbot])
msg.submit(respond, inputs=[msg, chatbot], outputs=[msg, chatbot]) #Press enter to submit
gr.close_all()
demo.launch(share=True, server_port=int(os.environ['PORT3']))
添加高级功能
def format_chat_prompt(message, chat_history, instruction):
prompt = f"System:{instruction}"
for turn in chat_history:
user_message, bot_message = turn
prompt = f"{prompt}\nUser: {user_message}\nAssistant: {bot_message}"
prompt = f"{prompt}\nUser: {message}\nAssistant:"
return prompt
流式处理
- 如果您的LLM可以一次提供一个令牌流,您可以在聊天机器人对象中累积这些令牌。
- 下面函数中的
for
循环遍历流中的所有令牌,并将它们追加到聊天机器人消息历史中最近的对话轮次中。
def respond(message, chat_history, instruction, temperature=0.7):
prompt = format_chat_prompt(message, chat_history, instruction)
chat_history = chat_history + [[message, ""]]
stream = client.generate_stream(prompt,
max_new_tokens=1024,
stop_sequences=["\nUser:", "<|endoftext|>"],
temperature=temperature)
#stop_sequences to not generate the user answer
acc_text = ""
#Streaming the tokens
for idx, response in enumerate(stream):
text_token = response.token.text
if response.details:
return
if idx == 0 and text_token.startswith(" "):
text_token = text_token[1:]
acc_text += text_token
last_turn = list(chat_history.pop(-1))
last_turn[-1] += acc_text
chat_history = chat_history + [last_turn]
yield "", chat_history
acc_text = ""
with gr.Blocks() as demo:
chatbot = gr.Chatbot(height=240) #just to fit the notebook
msg = gr.Textbox(label="Prompt")
with gr.Accordion(label="Advanced options",open=False):
system = gr.Textbox(label="System message", lines=2, value="A conversation between a user and an LLM-based AI assistant. The assistant gives helpful and honest answers.")
temperature = gr.Slider(label="temperature", minimum=0.1, maximum=1, value=0.7, step=0.1)
btn = gr.Button("Submit")
clear = gr.ClearButton(components=[msg, chatbot], value="Clear console")
btn.click(respond, inputs=[msg, chatbot, system], outputs=[msg, chatbot])
msg.submit(respond, inputs=[msg, chatbot, system], outputs=[msg, chatbot]) #Press enter to submit
gr.close_all()
demo.queue().launch(share=True, server_port=int(os.environ['PORT4']))