【NVIDIA NIM 黑客松训练营】文生图小应用

server/2024/10/17 14:51:03/

项目简介

以下是一个使用 NIM 平台的生成式 AI模型构建的简单 Demo。
Demo使用了模型meta / llama3-70b-instructnvidia / consistory,首先是优化了模型meta / llama3-70b-instruct默认的英文输出,使其对中文用户更友好;其次根据用户输入判断是否有作画意图,来判断是否调用nvidia / consistory模型。
这里使用 Python 和 FastAPI框架来搭建服务端,使用html搭建web端。

项目结构

work/

├── images/
├── chat.py
└── chat.html

技术方案与实现步骤

安装依赖

pip install fastapi uvicorn openai

创建聊天应用

  1. 首先要在NIM平台获取你的API KEY替换代码中的相应位置
from openai import OpenAI
from fastapi import FastAPI, Query
import uvicorn
from fastapi.middleware.cors import CORSMiddleware
import requests, base64
from datetime import datetime
import jsoninvoke_url = "https://ai.api.nvidia.com/v1/genai/nvidia/consistory"
headers = {"Authorization": "Bearer 你的apikey","Accept": "application/json",
}
client = OpenAI(base_url = "https://integrate.api.nvidia.com/v1",api_key = "你的apikey"
)
  1. 实现draw_image方法,接受四个传参,分别是图片主题prompt、主题词素、图片风格、场景描述,这四个参数是要传给nvidia / consistory模型的提示prompt,模型会根据这些参数进行绘画,如果想要一个好的图片质量,这四个参数尤为重要。方法返回的是图片链接,我这里不是本地服务所以有相应的域名,可以根据自己的情况进行更改,CORS配置也可以根据情况决定是否去掉。
def draw_image(subject_prompt, subject_tokens, style_prompt, scene_prompt1):print("subject_prompt=====",subject_prompt)print("subject_tokens=====",subject_tokens)print("style_prompt=====",style_prompt)print("scene_prompt1=====",scene_prompt1)payload = {"mode": 'init',"subject_prompt": subject_prompt,"subject_tokens": subject_tokens,"subject_seed": 43,"style_prompt": style_prompt,"scene_prompt1": scene_prompt1,"scene_prompt2": scene_prompt1,"negative_prompt": "","cfg_scale": 5,"same_initial_noise": False}response = requests.post(invoke_url, headers=headers, json=payload)response.raise_for_status()data = response.json()current_time = datetime.now()img_base64 = data['artifacts'][0]["base64"]img_bytes = base64.b64decode(img_base64)fileName = f"imgs/{current_time}.jpg"with open(fileName, "wb") as f:f.write(img_bytes)# 返回图片链接,就是srcreturn "https://abc/files/myWorkSapce/wordk1/" + fileName + "?_xsrf=2%7Cc6e76894%7Cfa2f2f15a513717ec5fe62cb04591a57%7C1728806376"app = FastAPI()
# 配置 CORS 中间件
app.add_middleware(CORSMiddleware,allow_origins=["*"],  # 允许所有来源allow_credentials=True,  # 允许传递凭证(如 cookies)allow_methods=["*"],  # 允许所有 HTTP 方法allow_headers=["*"],  # 允许所有头部
)
  1. img_template是调用模型meta / llama3-70b-instruct时的系统prompt,生成的json会直接传给nvidia / consistory模型,所以这里的prompt描述也很重要,可以根据自己的需求对这里进行优化。
img_template = """分析用户是否有关于画图的意向,如果有画图意向,则根据用户的描述按照下面的 json 格式进行输出,输出内容一定要满足json格式,输出内容不要有其它冗余:
'{"subject_prompt": 图片的主题(使用英文输出,一定要描述清楚,不要省略,比如“猫”),"subject_tokens": 图像的主题描述词汇,输出为数组格式[词汇, 词汇],使用英文输出,"style_prompt": 图像的风格,使用英文输出,"scene_prompt1": 场景描述,使用英文输出
}'
"""
  1. get_answer接口函数,根据用户输入调用模型meta / llama3-70b-instruct,判断用户是否有画图的意向,如果有则输出JSON字符串,解析其中的字段值传给nvidia / consistory模型进行绘图,返回给前端;如果没有绘图意向,则再调用一次模型meta / llama3-70b-instruct,这次的调用也是用了系统prompt,使它返回中文,对中文用户更友好。
def need_draw(json_str):# 解析 JSON 字符串try:json.loads(json_str)return Trueexcept json.JSONDecodeError:return False@app.get("/get_answer")
async def get_answer(question: str = Query(..., description="输入的问题")):imageCompletion = client.chat.completions.create(model="meta/llama3-70b-instruct",messages=[{"role":"system","content":img_template},{"role":"user","content":question}],temperature=0.5,top_p=1,max_tokens=1024,stream=False)print("imageCompletion=====",imageCompletion)if need_draw(imageCompletion.choices[0].message.content):data = json.loads(imageCompletion.choices[0].message.content)# 获取 style_prompt 字段subject_prompt = data.get("subject_prompt")subject_tokens = data.get("subject_tokens")style_prompt = data.get("style_prompt")scene_prompt1 = data.get("scene_prompt1")return {"answer": draw_image(subject_prompt,subject_tokens,style_prompt,scene_prompt1), "isImage": True}else:completion = client.chat.completions.create(model="meta/llama3-70b-instruct",messages=[{"role":"system","content":"You are a helpful assistant, Communicate using Chinese."},{"role":"user","content":question}],temperature=0.5,top_p=1,max_tokens=1024,stream=True)answer = ""for chunk in completion:if chunk.choices[0].delta.content is not None:answer += chunk.choices[0].delta.contentreturn {"answer": answer, "isImage": False}if __name__ == "__main__":uvicorn.run(app, host="0.0.0.0", port=8000)

HTML模板

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>聊天页面</title><style>body {font-family: Arial, sans-serif;background-color: #f4f4f4;margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;}.chat-container {width: 100%;max-width: 600px;background-color: #fff;border-radius: 8px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);overflow: hidden;}.chat-header {background-color: #007bff;color: #fff;padding: 10px;text-align: center;font-size: 18px;}.chat-body {padding: 20px;height: 400px;overflow-y: auto;border-bottom: 1px solid #ddd;}.chat-message {margin-bottom: 10px;}.chat-message.user {text-align: right;color: #007bff;}.chat-message.bot {text-align: left;color: #333;}.chat-input {display: flex;padding: 10px;}.chat-input input {flex: 1;padding: 10px;border: 1px solid #ddd;border-radius: 4px;margin-right: 10px;}.chat-input button {padding: 10px 20px;background-color: #007bff;color: #fff;border: none;border-radius: 4px;cursor: pointer;}.chat-input button:hover {background-color: #0056b3;}</style>
</head>
<body><div class="chat-container"><div class="chat-header">聊天页面</div><div class="chat-body" id="chat-body"><!-- 聊天记录将在这里显示 --></div><div class="chat-input"><input type="text" id="user-input" placeholder="输入问题..."><button onclick="sendMessage()">发送</button></div></div><script>function sendMessage() {const userInput = document.getElementById('user-input').value.trim();if (userInput === '') {alert('请输入问题');return;}// 显示用户消息const chatBody = document.getElementById('chat-body');const userMessage = document.createElement('div');userMessage.className = 'chat-message user';userMessage.textContent = userInput;chatBody.appendChild(userMessage);chatBody.scrollTop = chatBody.scrollHeight;// 清空输入框document.getElementById('user-input').value = '';// 发送请求获取回答fetch(`http://localhost:8001/get_answer?question=${encodeURIComponent(userInput)}`).then(response => response.json()).then(data => {if (data.isImage) {const botMessage = document.createElement('img');botMessage.src = data.answer;botMessage.className = 'chat-message bot';botMessage.width = 300;botMessage.height = 200;chatBody.appendChild(botMessage);chatBody.scrollTop = chatBody.scrollHeight;} else {const botMessage = document.createElement('div');botMessage.className = 'chat-message bot';botMessage.textContent = data.answer;chatBody.appendChild(botMessage);chatBody.scrollTop = chatBody.scrollHeight;}}).catch(error => {console.error('Error:', error);const errorMessage = document.createElement('div');errorMessage.className = 'chat-message bot';errorMessage.textContent = '无法获取回答,请稍后再试。';chatBody.appendChild(errorMessage);chatBody.scrollTop = chatBody.scrollHeight;});}</script>
</body>
</html>

运行应用

python chat.py

实验结果展示

在这里插入图片描述
在这里插入图片描述

分析与总结

总的来说成功的结合了两个模型,简单的实现了根据用户需求判断是否画图的功能,但还是有很多可以优化的地方,比如生成的图片还是比较粗糙,可以使用meta / llama3-70b-instruct对文生图的prompt在不改变用户需求的前提下进行润色,是图片输出的更为好看;再一个画完图后可以带着一些文字描述一起返回给用户;再优化一下界面、结合一些语音读取的模型…


http://www.ppmy.cn/server/132506.html

相关文章

华为HCIP考试改革,实验部分重要性提升,备考需知!

在当今这个行情复杂多变的时代&#xff0c;网络工程师的技能水平评估标准愈发重要&#xff0c;而认证无疑成为了其中关键的衡量尺度之一。 最近&#xff0c;华为认证领域内部传出了一则颇具影响力的消息&#xff1a;HCIP 认证即将增加实验考试&#xff01;想必不少朋友都已有所…

基于springboot实习管理系统

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 系统展示 【2024最新】基于JavaSpringBootVueMySQL的&#xff0c;前后端分离。 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;…

【JVM】一文详解类加载器

文章目录 类加载器的概述类加载器的分类启动类加载器(Bootstrap ClassLoader )扩展类型加载器(ExClassLoader)系统类加载器(Application ClassLoader )总结 双亲委派机制概念双亲委派机制的优势 ClassLoaderfindClassdefineClassloadClass&#xff0c;findClass&#xff0c;def…

使用DeepKE训练命名实体识别模型DEMO(官方DEMO)

使用DeepKE训练命名实体识别模型DEMO&#xff08;官方DEMO&#xff09; 说明&#xff1a; 首次发表日期&#xff1a;2024-10-10DeepKE资源&#xff1a; 文档&#xff1a; https://www.zjukg.org/DeepKE/网站&#xff1a; http://deepke.zjukg.cn/cnschema&#xff1a; http:/…

Java设计模式梳理:行为型模式(策略,观察者等)

行为型模式 行为型模式关注的是各个类之间的相互作用&#xff0c;将职责划分清楚&#xff0c;使得我们的代码更加地清晰。 策略模式 策略模式太常用了&#xff0c;所以把它放到最前面进行介绍。它比较简单&#xff0c;我就不废话&#xff0c;直接用代码说事吧。 下面设计的…

用示波器观测RC一阶电路零输入响应是否激励必须是方波信号

概述 RC一阶电路是一种简单但非常重要的电路&#xff0c;广泛应用于滤波、信号处理和时间常数分析等领域。在研究RC电路的动态特性时&#xff0c;零输入响应&#xff08;Natural Response&#xff09;是一项关键内容。本文将详细解析用示波器观测RC一阶电路零输入响应时&#…

Spring Boot助力B2B医疗平台病历数据交换

第1章绪论 计算机已经从科研院所&#xff0c;大中型企业&#xff0c;走进了平常百姓家&#xff0c;Internet遍及世界各地&#xff0c;在网上能够用计算机进行文字草拟、修改、打印清样、文件登陆、检索、综合统计、分类、数据库管理等&#xff0c;用科学的方法将无序的信息进行…

不用搭建服务?MemFire Cloud让开发更简单

不用搭建服务&#xff1f;MemFire Cloud让开发更简单 在当今的开发世界里&#xff0c;想要开发一个功能齐全的应用&#xff0c;往往意味着需要搭建复杂的后端、开发API接口、处理认证授权、管理数据库……这些琐碎的工作让很多开发者头疼不已&#xff0c;尤其是独立开发者或者…