Comenzando desde cero, implemente el servidor http basado en el modelo de lenguaje grande conversacional chino Firefly desarrollado por yangjianxin

Introducción del proyecto:

Firefly  es un proyecto de modelo de idioma chino de código abierto desarrollado por yangjianxin. Este artículo implementa principalmente la implementación de este modelo en un servidor http. Implementación del lenguaje: Python. Este proyecto es parte del código back-end del proyecto de innovación y emprendimiento masivo (modifiqué (se basa en el código de entrenamiento de Firefly + El modelo ajustado no es de código abierto por el momento), el modelo de muestra utiliza el modelo firefly1b4 en su lugar.

Entorno del proyecto:

1.pytorch:2.0.1+cpu

2.transformadores: 4.29.1

3.biblioteca del servidor https

Excepción: biblioteca de solicitudes (no es necesaria si no se conecta a otras API)

Descarga de modelo: YeungNLP (YeungNLP) (huggingface.co)

Después de la descarga, cree una nueva carpeta de modelo y coloque todos los archivos descargados en la carpeta, como se muestra en la siguiente figura.

Abra config.json y cambie el valor de torch_dtype a int8, lo que puede reducir efectivamente el retraso (especialmente adecuado para la versión de CPU)

Entorno de hardware:

Debido al uso del modelo, además de la inferencia, no consume mucha CPU / Gpu. Cargar el modelo consume memoria. Actualmente, después de las pruebas, se encuentra que en el funcionamiento real, 8G apenas puede ejecutar el modelo. pero existe una alta probabilidad de que toda la máquina se congele, se recomienda alcanzar al menos 12G de memoria

Entorno de desarrollo del proyecto: CPU: i58400, memoria: 16G (basta con ejecutar el modelo bajo esta configuración y luego ejecutar Android Studio + el simulador propio de Android Studio)


Parte del código:

1.Paquete de importación:

print("导入requests库中...")
import requests
print("导入http库中...")
import http.server
print("导入json库中...")
import json
print("导入os库中...")
import os
print("导入time库中...")
import time
print("导入urllib库中...")
import urllib
import random
from urllib import parse
print("导入transformers库中...")
from transformers import BloomTokenizerFast, BloomForCausalLM
print("导包完成=====================")

2.Parte de clase RequestHandlerImpl (servidor https) 

class RequestHandlerImpl(http.server.BaseHTTPRequestHandler):

    

    def do_GET(self):
        get_str=""
        get_cmd=self.requestline[5:self.requestline.find("HTTP/1.1")]
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.end_headers()
        get_str=checkget(get_cmd,self.headers)
        if get_str=="":get_str= "Hello World\n"
        self.wfile.write(get_str.encode("utf-8"))
        
                         

        

    def do_POST(self):
        req_body = self.rfile.read(int(self.headers["Content-Length"])).decode()
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.end_headers()
        get_str=checkpost(self.path,req_body)
        self.wfile.write(get_str.encode("utf-8"))

3. Parte de la función del proyecto (porque el backend de la aplicación tiene acceso a otras interfaces):

def get_answer(text): 
    print("得到新问题",text)
    input_ids = tokenizer(text, return_tensors="pt").input_ids
    input_ids = input_ids.to(device)
    outputs = model.generate(input_ids, max_new_tokens=200, do_sample=True, top_p=0.85, temperature=0.35,repetition_penalty=1.2, eos_token_id=tokenizer.eos_token_id)
    rets = tokenizer.batch_decode(outputs)
    output = rets[0].strip().replace(text, "").replace('</s>', "")
    return format(output)


def get_list(parm): #新闻类接口,可以发布
    parm=parm[1:]
    get_tx=parm.split("&")
    name="福州"
    page="0"

    for i in range(0, len(get_tx)):
        if get_tx[i][0:5]=="name=":
            name=get_tx[i][5:]
            
        if get_tx[i][0:5]=="page=":
            page=get_tx[i][5:].replace(' ', '')

    url = "https://v.api.aa1.cn/api/api-tplist/go.php/api/News/local_news?name=" +  name + "&page=" + page
    print(url)
    response = requests.get(url)
    content = response.text
    return content


def get_top(): #百度热搜接口
    url ='https://v.api.aa1.cn/api/topbaidu/index.php'
    response = requests.get(url)
    content = response.text
    return content


def get_weather(): #天气类接口(付费的)
    url ='http://apis.juhe.cn/simpleWeather/query?city=%E7%A6%8F%E5%B7%9E&key=需要自己加上'
    response = requests.get(url)
    content = response.text
    return content
  
def login(up): #登录接口
    get_tx=up.split("&")
    un=""
    pw=""
    code=0

    for i in range(0, len(get_tx)):
        if get_tx[i][0:5]=="user=":
            un=get_tx[i][5:]
            
        if get_tx[i][0:5]=="pass=":
            pw=get_tx[i][5:].replace(' ', '')
            
    print(un)
    print(pw)

    f=open('libaray/uw', encoding='gbk') #加载type字符库
    for line in f:
        get_tx=line.split(",")
        
        if un==get_tx[0] and pw==get_tx[1].replace('\n', ''):
            dic = {'code': 200, 'msg': "登录成功","token":token}
            break
        else:
            dic = {'code': 201, 'msg': "用户名或密码错误"}

    f.close()
    
    print(dic)
    return json.dumps(dic, sort_keys=True,ensure_ascii= False,indent=4, separators=(',', ':'))


def register(up):  #登录接口
    get_tx=up.split("&")
    uw=""
    pw=""
    code=0
    
    for i in range(0, len(get_tx)): #这里和登录类似,可以封装起来,目的是获取传来的用户,密码
        if get_tx[i][0:5]=="user=":
            un=get_tx[i][5:]
        if get_tx[i][0:5]=="pass=":
            pw=get_tx[i][5:].replace(' ', '')

    print(un)
    print(pw)

    #加载uw密码库,后续可以写成load函数,在加载时候开启
    f=open('libaray/uw', encoding='gbk')
    for line in f:
        get_tx=line.split(",")
        if un==get_tx[0]:
            dic = {'code': 201, 'msg':"用户已存在"}
            return json.dumps(dic, sort_keys=True,ensure_ascii= False,indent=4, separators=(',', ':'))
    f.close()
    f=open('libaray/uw','a+')
    f.write(un+","+pw+"\n")
    dic = {'code': 200, 'msg':"注册成功"}
    f.close()
    return json.dumps(dic, sort_keys=True,ensure_ascii= False,indent=4, separators=(',', ':'))
    
       
def checkpost(path,get_cmd): #查看post进来的数据
    if path=="/login":
        return login(get_cmd)

    if path=="/register":
        return register(get_cmd)
                   
def checkhead(head): #检查需要加密的接口,传进来的头
    print(token == head.get("Authorization"))
    if  token == head.get("Authorization"):
        return True
    else:
        return False


def checkget(get_cmd="",head=""): #查看get进来的数据
    if get_cmd[0:9]=="question=":
        if checkhead(head): 
            dic = {'code': 200, 'msg':get_answer(parse.unquote(get_cmd[9:])),"prompt":urllib.parse.unquote(get_cmd[9:])}
            return json.dumps(dic, sort_keys=True,ensure_ascii= False,indent=4, separators=(',', ':'))  
        else:
            dic = {'code': 401, 'msg':"没有权限"}
            return json.dumps(dic, sort_keys=True,ensure_ascii= False,indent=4, separators=(',', ':'))  
    if get_cmd[0:4]=="list": 
        if checkhead(head):
            return get_list(get_cmd[4:])
        else:
            dic = {'code': 401, 'msg':"没有权限"}
            return json.dumps(dic, sort_keys=True,ensure_ascii= False,indent=4, separators=(',', ':'))
        
    if get_cmd[0:6]=="gettop": 
        if checkhead(head):
            return get_top()
        else:
            dic = {'code': 401, 'msg':"没有权限"}
            return json.dumps(dic, sort_keys=True,ensure_ascii= False,indent=4, separators=(',', ':'))

    if get_cmd[0:7]=="weather": #免费api接口
        return get_weather()
            
    if get_cmd[0:6]=="login?": 
        gcmd=get_cmd[6:]
        return login(gcmd)

principal:
 

print("加载tokenizer中")
tokenizer = BloomTokenizerFast.from_pretrained('model/')   #路径以文件夹下的model为例
print("加载model中")
model = BloomForCausalLM.from_pretrained('model/')
model.eval()
device="cpu"
model = model.to(device) #用cuda或者cpu
print("tlc机器人已启动")
token=''.join(random.sample('abcdefghijklmnopqrstuvwxyzABCDEGHIJKLMNOPQRSTWVUXYZ!@#$%&',39))
print("加密为token=" + token) #这句加入是方便测试
local_ip="10.1.136.73" #local ip为服务器ip
server_address = (local_ip, 19999) 
httpd = http.server.HTTPServer(server_address, RequestHandlerImpl)
httpd.serve_forever()

Prueba de interfaz:

1. Ejecute el código:

Después de ejecutar el código, si el mensaje es como se muestra en la siguiente figura, no hay problema. Puede ver que hay un parámetro token=xxxx. Este parámetro es un token temporal generado aleatoriamente. La configuración actual es generarlo una vez. cada vez que se inicia el servidor. Aquí es conveniente imprimir la demostración. De hecho, debe iniciar sesión en la interfaz para obtenerla. Puede comentarla más tarde.

2. Pruebe si la interfaz está disponible:

Ingrese http://10.1.136.73:19999/question=<s>Hola</s></s> en cartero como se muestra a continuación

Dado que la salida de datos al modelo está formateada en el formato <s></s>, para facilitar que el cliente pase conversaciones históricas como promat, no formateé la cadena en Python, sino que la implementé en el cliente.

El mensaje 401 que aparece es que agregamos un encabezado y no pudimos pasar la verificación, pero puede demostrar que el servidor http puede ejecutarse normalmente.


 

3. Agregue el encabezado para continuar con la verificación:

Agregue un parámetro denominado Autorización al encabezado y ejecute el encabezado nuevamente con el valor del parámetro como el token generado temporalmente. Se descubre que es factible, como se muestra en la figura siguiente, se descubre que el cliente devuelve json normalmente.

 Parámetro de código: es normal cuando es 200, de lo contrario es anormal, el mensaje es el valor entrante y el mensaje es el valor saliente.

Múltiples rondas de diálogo:

En la prueba real, descubrimos que la versión Firefly1b4 también puede admitir múltiples rondas de diálogo, pero el efecto será peor: solo necesitamos formatear los datos externamente en la siguiente forma:

<s>Pregunta 1</s></s>Respuesta 1</s></s>Pregunta 2</s></s>Respuesta 2</s></s>Pregunta 3</s>< /s>Respuesta 3</s></s>

Los siguientes son ejemplos de efectos:

El mensaje entrante es <s>¿Conoces Beijing?</s></s> Beijing es la capital de China y está ubicada en el norte de China. </s></s>¿Qué delicias hay?</s></s>Pato asado, fideos con pasta de soja, jugo de judías, estofado de cordero, sesos de tofu, etc. </s></s>Qué lugares de entretenimiento hay</s></s>

La salida es la Gran Muralla, el Museo del Palacio, el Palacio de Verano, el Templo del Cielo, el Antiguo Palacio de Verano, etc.

 



Desarrollado por la Escuela Técnica y Vocacional de Ingeniería Mecánica y Eléctrica de Fuzhou.

Información de contacto por correo electrónico: [email protected]

Información de contacto QQ: 2151335401, 3135144152

Supongo que te gusta

Origin blog.csdn.net/m0_60277871/article/details/131437846
Recomendado
Clasificación