實戰(zhàn)干貨!基于ERNIE Bot SDK的數(shù)字詩人聊天開發(fā)教程
隨著人工智能技術的不斷迭代發(fā)展,數(shù)字人的開發(fā)與應用需求也與日俱增,并且隨著大語言模型的發(fā)展,數(shù)字人也更智能,從最初的語音預制到現(xiàn)在的實時交流,目前已在很多場景都有廣泛應用。 虛擬客服:數(shù)字人可以通過語音或文字與用戶進行交互,提供客戶服務等支持,從而替代傳統(tǒng)的人工客服。
虛擬購物助手:數(shù)字人可以通過語音或文字與用戶進行交互,為用戶提供購物建議和推薦,從而提高用戶的購物體驗。
虛擬教師:數(shù)字人可以通過語音或文字與學生進行交互,為學生提供個性化的教育服務。
虛擬醫(yī)生:數(shù)字人可以通過語音或文字與患者進行交互,為患者提供醫(yī)療咨詢和診斷服務。
本開發(fā)教程將以ERNIE Bot SDK作為語言交互的基礎,并結合Stable Diffusion、PaddleGan、Edge TTS等技術,實現(xiàn)數(shù)字詩人的實時交互,提高詩詞的表現(xiàn)力。
本教程共計分為4部分:定制聲音、定制造型、生成數(shù)字人、數(shù)字人語音聊天。
定制數(shù)字人聲音
生成詩詞:ERNIE Bot SDK
安裝ERNIE Bot SDK,將用戶輸入的描述詞或主題,生成七言律詩。
!pip install --upgrade erniebot import erniebot def wx_api(prompt): # List supported models models = erniebot.Model.list() print(models) erniebot.api_type = "aistudio" erniebot.access_token = "請輸入自己的令牌" # 令牌來源如下圖 # ernie-bot-turbo 選用原因,速度快些 response = erniebot.ChatCompletion.create(model="ernie-bot-turbo", messages=[{"role": "user", "content": f"{prompt}"}]) answer = response.result return answer # 作詩 def poetry(prompt): answer = wx_api( f"你是偉大的詩人,請賦詩一首七言絕句描述以下情景:{prompt}") print("{} 作詩反饋:\n{}".format(prompt, answer)) return answer poetry("觀看天津直升機博覽會。")
生成聲音:Edge TTS
將ERNIE Bot SDK所生成的詩詞轉為聲音。
!pip install edge_tts -i https://mirror.baidu.com/pypi/simple !pip install librosa==0.8.1 import librosa import os boot_path = '/home/aistudio/Gradio_packages/' sound_path = os.path.join(boot_path,'file/sound.wav') text = "空港博覽直升機,列隊飛行人如潮。老爸肩頭怡然坐,風雷絕技盡收眼。碧空綻放絢四機,陸航芭蕾舞云間。盛會雄風震八方,幸見中華復巔峰。" tts_cmd = 'edge-tts --voice zh-CN-XiaoxiaoNeural --text "' + text + '" --write-media ' +sound_path os.system(tts_cmd)
定制數(shù)字人形象
數(shù)字人靜態(tài)形象可以上傳圖片,也可以直接通過Stable Diffusion生成。
文生圖:Stable Diffusion
Stable Diffusion是一種潛在擴散模型(Latent Diffusion), 屬于生成類模型,這類模型通過對隨機噪聲進行一步步地迭代降噪并采樣來獲得感興趣的圖像,當前取得了令人驚艷的效果。相比于Disco Diffusion, Stable Diffusion通過在低緯度的潛在空間(lower dimensional latent space)而不是原像素空間來做迭代,極大地降低了內存和計算量的需求,并且在V100上一分鐘之內即可以渲染出想要的圖像。 參數(shù)說明: prompts: 輸入的語句,描述想要生成的圖像的內容。 !pip install paddlenlp==2.6.0rc0 !pip install ppdiffusers #重啟內核,項目框架需為:PaddlePaddle develop # 安裝完后import ppdiffusers可能會失敗,點擊最上面的重啟內核即可,不行就重復pip+重啟內核幾次,總能成功的~ import os import paddle from ppdiffusers import StableDiffusionPipeline from ppdiffusers import DPMSolverMultistepScheduler fdir_path = '/home/aistudio/Gradio_packages/file/' diffu_img_path = os.path.join(fdir_path,'diffu_img.jpg') face_img_path = os.path.join(fdir_path,'face_img.jpg') temp_img_path = os.path.join(fdir_path,'temp.jpg') # 模型 pretrained_model_name_or_path = "runwayml/stable-diffusion-v1-5" #unet_model_path = "./dream_booth_lora_outputs" # 加載原始的模型 pipe = StableDiffusionPipeline.from_pretrained(pretrained_model_name_or_path, safety_checker=None) pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config) # 將 adapter layers 添加到 UNet 模型 #pipe.unet.load_attn_procs(unet_model_path, from_hf_hub=False) def diffu_result0(prompt): if prompt == '': prompt = 'face' negative_prompt = "lowres, error_face, bad_face, bad_anatomy, error_body, error_hair, error_arm, (error_hands, bad_hands, error_fingers, bad_fingers, missing_fingers) error_legs, bad_legs, multiple_legs, missing_legs, error_lighting, error_shadow, error_reflection, text, error, extra_digit, fewer_digits, cropped, worst_quality, low_quality, normal_quality, jpeg_artifacts, signature, watermark, username, blurry" guidance_scale = 8 num_inference_steps = 50 height = 512 width = 512 img = pipe(prompt, negative_prompt=negative_prompt, guidance_scale=guidance_scale, height=height, width=width, num_inference_steps=num_inference_steps).images[0] img.save(diffu_img_path) img.save(temp_img_path) # 備份 在使用stable diffusion時,可以使用ERNIE Bot SDK中的翻譯和擴寫功能對prompt進行處理。 def magic_prompt(query: str): magic_template = """ 你是一個提示詞擴寫大師, 你需要根據(jù)我的輸入,改寫擴寫為提示詞,直接輸出全英文。 提示詞需要遵循以下規(guī)則: 遵循示例提示詞的結構,這意味著首先描述繪畫主體,然后描述場景,然后添加繪畫筆觸、情緒、繪畫風格、燈光、鏡頭、等, 然后是best quality,、masterpiece、8K這樣表達高質量照片的詞語,所有這些詞語之間用逗號分隔。 請不要換行,請用英語表達。 舉例: 輸入:一個穿明亮裙子的小姑娘 a portrait of a cute girl wearing a luminous, vibrant and colorful dress standing in front of an abstract dreamy background with subtle pastel colors, inspired by the works of Ulyana Aster, digital art made using Adobe Photoshop and Corel Painter, surrealistic elements like glitters, stars and clouds to create a magical atmosphere, RAW photo,hyper-realistic, close-up, product view, artstation trends, cgsociety, super high quality, digital art, exquisite ultra-detailed, 4k, soft lighting, fantasy, fashion, unreal engine rendering,8k uhd, HDR, high quality,untra detailed,film grain 輸入:一間白色的帶有瓷磚的浴室 a nature look and chic bathroom with white wall, beige ceramic tile, natural stone flooring, modern fixtures and appliances in silver chrome, contemporary vanity sink and mirror in black marble countertop, spa-like atmosphere with a luxurious freestanding bathtub in the center of the room. Rendered in Unreal Engine 4 for photorealistic lighting effects and textures, RAW photo,hyper-realistic,RAW photo,hyper-realistic,, product view, artstation trends, cgsociety, super high quality, digital art, exquisite ultra-detailed, 4k, soft lighting, dreamy, stylish, unreal engine Rendering Model: Midjourney style, CFG scale: 7, 8k, uhd, HDR, high quality,untra detailed,film grain,8k uhd, HDR, high quality,untra detailed,film grain 輸入:"{query}" """ answer = wx_api(magic_template) # 此處出現(xiàn)過LangChain部署失敗問題,故調整方案,放棄使用 return answer def translate_prompt(query: str): translate_template = """ 你是一個翻譯大師, 你需要根據(jù)我的輸入,把中文翻譯為英文。
環(huán)境準備:PaddleGAN
PaddleGAN 生成對抗網(wǎng)絡開發(fā)套件
,為開發(fā)者提供經(jīng)典及前沿的生成對抗網(wǎng)絡高性能實現(xiàn),并支撐開發(fā)者快速構建、訓練及部署生成對抗網(wǎng)絡,以供學術、娛樂及產(chǎn)業(yè)應用。
環(huán)境準備--若需在main.ipynb中運行以下代碼,需將main.ipynb置于Gradio_packages文件夾下。 # 本項目已經(jīng)修改PaddleGAN文件夾內容,無需再運行此處代碼,避免覆蓋。 #!git clone https://gitee.com/PaddlePaddle/PaddleGAN #%cd /home/aistudio/PaddleGAN/ #!python ./setup.py develop !pip install dlib !pip install scikit-image !pip install imageio-ffmpeg !pip install munch !pip install natsort !pip install numpy==1.22 #重啟內核
臉部融合:StyleGANv2Fitting,StyleGANv2Mixing
將兩個來源的圖片形象進行臉部融合生成新的形象。
基礎知識 StyleGANv2Fitting,StyleGANv2Mixing
1、StyleGAN是隨機生成向量,根據(jù)向量生成圖片。 2、Fitting模塊是根據(jù)已有的圖像反推出解耦程度高的風格向量。得到的風格向量可用于人臉融合、人臉屬性編輯等任務中。 3、Mixing模塊則是利用其風格向量實現(xiàn)兩張生成圖像不同層次不同比例的混合。
原理步驟
實現(xiàn)人臉融合一共分為三個步驟: 1、Fitting模塊提取兩張人臉圖片的向量,StyleGAN V2根據(jù)向量生成StyleGAN世界中的人臉; 2、Mixing模塊融合兩張人臉的向量; 3、StyleGAN V2根據(jù)融合后的向量生成新的人臉。 import os from PaddleGAN.ppgan.apps.styleganv2fitting_predictor import StyleGANv2FittingPredictor fdir_path = '/home/aistudio/Gradio_packages/file/' fit_path = '/home/aistudio/Gradio_packages/file/fit1' diffu_img_path = os.path.join(fdir_path,'diffu_img.jpg') print(diffu_img_path) img2fit = StyleGANv2FittingPredictor(output_path=fit_path, model_type='ffhq-config-f', seed=None, size=1024, style_dim=512, n_mlp=8, channel_multiplier=2) img2fit.run(diffu_img_path,need_align=True) import os from PaddleGAN.ppgan.apps.styleganv2fitting_predictor import StyleGANv2FittingPredictor fdir_path = '/home/aistudio/Gradio_packages/file/' fit_path = '/home/aistudio/Gradio_packages/file/fit2' input_face_path = os.path.join(fdir_path,'input_face.jpg') print(diffu_img_path) img2fit = StyleGANv2FittingPredictor(output_path=fit_path, model_type='ffhq-config-f', seed=None, size=1024, style_dim=512, n_mlp=8, channel_multiplier=2) img2fit.run(input_face_path,need_align=True) import os from PaddleGAN.ppgan.apps import StyleGANv2MixingPredictor from PIL import Image fdir_path = '/home/aistudio/Gradio_packages/file/' fit1_path = os.path.join(fdir_path,'fit1/dst.fitting.npy') print(fit1_path) fit2_path = os.path.join(fdir_path,'fit2/dst.fitting.npy') mix_path = os.path.join(fdir_path,'dst.mixing.png') face_img_path = os.path.join(fdir_path,'face_img.jpg') predictor = StyleGANv2MixingPredictor(output_path=fdir_path, model_type='ffhq-config-f', seed=None, size=512, style_dim=512, n_mlp=8, channel_multiplier=2) predictor.run(fit1_path, fit2_path) img = Image.open(mix_path) img.resize((512, 512), Image.LANCZOS).save(face_img_path) print(face_img_path)
老化和卡通化:Pixel2Style2Pixel,StyleGANv2
可以嘗試更多數(shù)字人形象。
老化基礎知識 Pixel2Style2Pixel,StyleGANv2
1、Latent Code:潛在因子,每張圖像對應一個潛在因子(高維的向量),stylegan能夠用這個向量生成圖像。 2、屬性編輯:由于潛在因子包含維度比較多,無法確定維度對應的方向以及編輯所帶來的變化,因此利用大量的潛在因子和對應的屬性(比如年齡或性別)訓練線性的分類器,即可將分類器的權重作為潛在因子和對應屬性的方向。 3、StyleGAN:根據(jù)向量生成圖片。
老化原理步驟
1、獲取圖片的Latent Code,用于后續(xù)的屬性編輯和人臉生成,使用Pixel2Style2Pixel提取Latent Code。 temp_img_path:原圖路徑,即需要提取隱藏特征的照片路徑。 age_dir:原圖的隱藏特征的存放路徑,后續(xù)需要放在屬性編輯和生成的模塊中使用。 2、將Latent Code根據(jù)特定方向進行編輯,即可編輯對應的人臉屬性,如年齡、性別、頭發(fā)、眼睛等。 3、StyleGAN V2根據(jù)第二步中編輯好的Latent Code向量生成目標人臉。 age_pix_path:STEP2中提取的原圖的Latent Code(STEP2中的output_path路徑)。 age_path:新人臉(年齡變換后)的保存路徑。
應用使用說明
老化或卡通化:老化值不為0時,產(chǎn)生效果;老化值為0時,撤銷上一步老化或卡通化操作,僅能撤銷一步。 import os from PaddleGAN.ppgan.apps.pixel2style2pixel_predictor import Pixel2Style2PixelPredictor from PaddleGAN.ppgan.apps.styleganv2editing_predictor import StyleGANv2EditingPredictor from PaddleGAN.ppgan.apps.photo2cartoon_predictor import Photo2CartoonPredictor def resize_image1(in_path, out_path, w, h): img = Image.open(in_path) img.resize((w, h), Image.LANCZOS).save(out_path) fdir_path = '/home/aistudio/Gradio_packages/file' diffu_img_path = os.path.join(fdir_path,'diffu_img.jpg') face_img_path = os.path.join(fdir_path,'face_img.jpg') temp_img_path = os.path.join(fdir_path,'temp.jpg') age_dir = os.path.join(fdir_path,'age/') age_pix_path = os.path.join(fdir_path,'age/dst.npy') age_path = os.path.join(fdir_path,'age/dst.editing.png') cartoon_dir = os.path.join(fdir_path,'cartoon/') cartoon_path = os.path.join(fdir_path,'cartoon/p2c_cartoon.png') age_pixel_predictor = Pixel2Style2PixelPredictor(output_path = age_dir, model_type = 'ffhq-inversion', size = 512) age_predictor = StyleGANv2EditingPredictor(output_path = age_dir, model_type = 'ffhq-config-f', size = 512) cartoon_predictor = Photo2CartoonPredictor(output_path = cartoon_dir) # 變換年齡提取像素 def age_pixel(): age_pixel_predictor.run(temp_img_path) # 變換年齡 def age(num): age_predictor.run(age_pix_path, 'age', num/5) resize_image1(age_path, diffu_img_path, 512, 512) # 變換卡通形象 def cartoon(): cartoon_predictor.run(temp_img_path) resize_image1(cartoon_path, diffu_img_path, 512, 512) age_pixel() age(5) #cartoon()
生成數(shù)字人
將靜態(tài)形象轉化為動態(tài),并與聲音進行唇形匹配生成數(shù)字人視頻。
表情遷移:First order motion model
將靜態(tài)造型轉化為動態(tài)。 First order motion model的任務是image animation,給定一張源圖片,給定一個驅動視頻,生成一段視頻,其中主角是源圖片,動作是驅動視頻中的動作,源圖像通常包含一個主體,驅動視頻包含一系列動作。 以人臉表情遷移為例,給定一個源人物,給定一個驅動視頻,可以生成一個視頻,其中主體是源人物,視頻中源人物的表情是由驅動視頻中的表情所確定的。通常情況下,我們需要對源人物進行人臉關鍵點標注、進行表情遷移的模型訓練。 參數(shù)說明: face_driving_path: 驅動視頻,視頻中人物的表情動作作為待遷移的對象。 face_img_path: 原始圖片,視頻中人物的表情動作將遷移到該原始圖片中的人物上。 relative: 指示程序中使用視頻和圖片中人物關鍵點的相對坐標還是絕對坐標,建議使用相對坐標,若使用絕對坐標,會導致遷移后人物扭曲變形。 adapt_scale: 根據(jù)關鍵點凸包自適應運動尺度。 import os from PaddleGAN.ppgan.apps.first_order_predictor import FirstOrderPredictor fdir_path = '/home/aistudio/Gradio_packages/file' face_img_path = os.path.join(fdir_path,'face_img.jpg') face_driving_path = os.path.join(fdir_path,'face_dri.mp4') face_path = os.path.join(fdir_path,'face.mp4') FOM_predictor = FirstOrderPredictor(output = fdir_path, filename = 'face.mp4', face_enhancement = False, ratio = 0.4, relative = True, image_size = 512, adapt_scale = True) def FOM(): FOM_predictor.run(face_img_path, face_driving_path) return face_path FOM()
唇形匹配:Wav2Lip
動態(tài)造型并與聲音進行唇形匹配生成數(shù)字人視頻。
Wav2Lip模型是一個基于GAN的唇形動作遷移算法,實現(xiàn)生成的視頻人物口型與輸入語音同步。Wav2Lip不僅可以基于靜態(tài)圖像來輸出與目標語音匹配的唇形同步視頻,還可以直接將動態(tài)的視頻進行唇形轉換,輸出與輸入語音匹配的視頻。 Wav2lip實現(xiàn)唇形與語音精準同步突破的關鍵在于,它采用了唇形同步判別器,以強制生成器持續(xù)產(chǎn)生準確而逼真的唇部運動。 此外,該研究通過在鑒別器中,使用多個連續(xù)幀而不是單個幀,并使用視覺質量損失(而不僅僅是對比損失)來考慮時間相關性,從而改善了視覺質量。 該wav2lip模型幾乎是萬能的,適用于任何人臉、任何語音、任何語言,對任意視頻都能達到很高的準確率,可以無縫地與原始視頻融合,還可以用于轉換動畫人臉,并且導入合成語音也是可行的。 參數(shù)說明: face_path: 動態(tài)造型視頻,其中的人物唇形將根據(jù)音頻進行唇形合成。 sound_path: 驅動唇形合成的音頻。 result_path: 指定生成的視頻文件的保存路徑及文件名。 import os from PaddleGAN.ppgan.apps.wav2lip_predictor import Wav2LipPredictor fdir_path = '/home/aistudio/Gradio_packages/file' face_path = os.path.join(fdir_path,'face.mp4') sound_path = os.path.join(fdir_path,'sound.wav') result_path = os.path.join(fdir_path,'result.mp4') wav2lip_predictor = Wav2LipPredictor(face_det_batch_size = 2, wav2lip_batch_size = 16, face_enhancement = True) def wav2lip(input_video,input_audio,output): wav2lip_predictor.run(input_video, input_audio, output) return output wav2lip(face_path, sound_path, result_path)
數(shù)字人語音聊天
通過語音識別技術和文心一言能力實現(xiàn)數(shù)字人聊天。
語音識別:百度智能云api
調用百度智能云語音識別api——短語音識別標準版。 import os import base64 import urllib import requests import json fdir_path = '/home/aistudio/Gradio_packages/file/' sound_path = os.path.join(fdir_path,'chat_in.wav') def get_access_token(): API_KEY = "??????" # 獲取方式可參考本項目文檔結尾部分—--創(chuàng)建百度智能云語音識別api步驟 SECRET_KEY = "??????" """ 使用 AK,SK 生成鑒權簽名(Access Token) :return: access_token,或是None(如果錯誤) """ url = "https://aip.baidubce.com/oauth/2.0/token" params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY} print(params) return str(requests.post(url, params=params).json().get("access_token")) def get_file_content_as_base64(path, urlencoded=False): """ 獲取文件base64編碼 :param path: 文件路徑 :param urlencoded: 是否對結果進行urlencoded :return: base64編碼信息 """ with open(path, "rb") as f: content = base64.b64encode(f.read()).decode("utf8") if urlencoded: content = urllib.parse.quote_plus(content) return content url = "https://vop.baidu.com/server_api" print(sound_path) speech = get_file_content_as_base64(sound_path,False) print(speech) payload = json.dumps({ "format": "PCM", "rate": 16000, "channel": 1, "cuid": "I0MZDdBsn2GsmuQXofM4kXugUrZySh0l", "token": get_access_token(), "dev_pid": 1737, "speech": get_file_content_as_base64(sound_path,False), "len": os.path.getsize(sound_path) }) headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } response = requests.request("POST", url, headers=head
數(shù)字人聊天:ERNIE Bot SDK
使用文心一言能力生成對話內容。 from api import wx_api chat_in = "你是誰" prompt = f""" 人物設定: 你名叫“奇奇”。是一個知識淵博、善解人意、風趣幽默的聊天小達人,能夠與用戶進行幽默而富有洞察力的對話。 對話案例: 用戶:“嗨,奇奇!今天天氣真好,適合出去散步。你覺得呢?” 奇奇:“是的,確實是個散步的好日子。你喜歡去哪里散步呢?是公園還是河邊?” 用戶:“我通常喜歡去公園散步。那里的花草樹木都很美麗,還能聽到鳥叫聲?!? 奇奇:“聽起來很愜意??!散步在自然環(huán)境中可以緩解壓力,也有助于健康。你平時還有其他喜歡的戶外活動嗎?” 輸出要求: 根據(jù)用戶的輸入,生成有趣、相關且富有洞察力的回應。 在對話中保持自然、流暢的風格,與用戶進行互動。 可以根據(jù)對話的上下文,主動引導對話的深入和擴展。 回答內容盡量簡短。 回答用戶最新的問題:{chat_in} """ answer = wx_api(prompt) print("{} 聊天最終反饋:{}".format(chat_in, answer))
作者故事
星河小編:
可以簡單介紹一下自己哦。
司進龍:
大家好,我叫司進龍,現(xiàn)在是神州數(shù)碼資深RPA工程師,原來從事行業(yè)分析咨詢工作,于三年前學習Python并成功轉行到RPA行業(yè)。
星河小編:
是怎么加入到飛槳星河社區(qū)的呢?
司進龍:
與飛槳星河社區(qū)的結緣是在一年前,最開始是學習飛槳星河社區(qū)的課程,從深度學習理論到大模型應用開發(fā)等一系列課程,最開始只是自己學,后來甚至推薦家人一起聽,一起組隊參賽卷卷ai。
星河小編:
可以再介紹下這個項目嘛?
司進龍:
這個應用是為了黑客松5th比賽而準備的。在進行數(shù)字人人物設定時,用的就是我家孩子的小名奇奇和思思。他們還喜歡測試作品,思思最喜歡測試數(shù)字人生成、老化等功能。奇奇則最喜歡測試與數(shù)字人對話的功能,他們找出來好多bug,也玩的不亦樂乎。我妻子高磊不僅提出許多創(chuàng)意,更重要的是給我很多鼓勵,使我有了不斷前行的動力。 該教程項目來源于飛槳星河社區(qū)五周年開發(fā)精品教程征集,更多教程或有投稿需求請進入飛槳星河社區(qū)查看。