一 .准备工作
首先要拿到讯飞的语言大模型的api,可以从以下链接的方式获取(讯飞星火大模型-AI大语言模型-星火大模型-科大讯飞讯飞星火大模型,是由科大讯飞推出的新一代认知智能大模型,拥有跨领域的知识和语言理解能力,能够基于自然对话方式理解与执行任务,提供语言理解、知识问答、逻辑推理、数学题解答、代码理解与编写等多种能力。https://xinghuo.xfyun.cn/speechllm),目前这些都是免费。
二 . 演示
三 .代码
前端交互:
<!DOCTYPE html>
<html lang="en">
<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;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
.container {
max-width: 800px;
margin: 20px auto;
padding: 20px;
background-color: #ffffff;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.chat-header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.chat-avatar {
font-size: 24px;
margin-right: 10px;
}
.chat-name {
font-size: 20px;
color: #333;
}
.chat-messages {
list-style-type: none;
padding: 0;
margin: 0;
}
.chat-messages .message {
display: flex;
align-items: center;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
word-wrap: break-word;
}
.chat-messages .message .message-avatar {
font-size: 24px;
margin-right: 10px;
}
.chat-messages .message .message-content {
white-space: pre-wrap;
}
.chat-messages .message.right {
justify-content: flex-end;
background-color: #cfe8fc;
}
.chat-messages .message.left {
justify-content: flex-start;
background-color: #e0e0e0;
}
.chat-messages .message.right .message-avatar {
margin-left: 10px;
margin-right: 0;
}
.chat-messages .message.right .message-content {
text-align: right;
}
.chat-messages .message.left .message-content {
text-align: left;
}
.chat-input {
display: flex;
margin-top: 20px;
}
.chat-input input[type="text"] {
flex: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
margin-right: 10px;
}
.chat-input button {
padding: 10px 20px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
.chat-input button:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="container">
<div class="chat-header">
<div class="chat-avatar">
🤖
</div>
<span class="chat-name">ChatBot</span>
</div>
<ul class="chat-messages" id="chatMessages">
</ul>
<form class="chat-input" id="myform">
<input type="text" id="chat-message" placeholder="输入你的消息...">
<button type="submit">发送</button>
</form>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('myform');
const chatMessageInput = document.getElementById('chat-message');
const chatAnswerDiv = document.getElementById('chatMessages');
function createChatBubble(content, className, avatarClass) {
const bubble = document.createElement('div');
bubble.className = 'message ' + className;
bubble.innerHTML = `
<div class="message-avatar ${avatarClass}"></div>
<div class="message-content">${content}</div>
`;
return bubble;
}
form.addEventListener('submit', async function(event) {
event.preventDefault();
const message = chatMessageInput.value.trim();
if (!message) return;
chatMessageInput.value = '';
const userMessageElement = createChatBubble(message, 'right', 'user');
chatAnswerDiv.appendChild(userMessageElement);
const loadingMessage = createChatBubble('正在调用工作流...', 'left', 'assistant');
chatAnswerDiv.appendChild(loadingMessage);
try {
const response = await fetch('/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ input: message, isNewConversation: true })
});
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
const data = await response.json();
chatAnswerDiv.removeChild(loadingMessage);
const assistantMessageText = data.response.replace(/\n/g, '<br>');
const assistantMessageElement = createChatBubble(assistantMessageText, 'left', 'assistant');
chatAnswerDiv.appendChild(assistantMessageElement);
} catch (error) {
console.error('Error:', error);
chatAnswerDiv.removeChild(loadingMessage);
const errorMessageElement = createChatBubble('Sorry, there was an error processing your request.', 'left', 'assistant');
chatAnswerDiv.appendChild(errorMessageElement);
}
});
});
</script>
</body>
</html>
后端flask框架
SparkApi.py
import _thread as thread
import base64
import datetime
import hashlib
import hmac
import json
import threading
from urllib.parse import urlparse
import ssl
from datetime import datetime
from time import mktime
from urllib.parse import urlencode
from wsgiref.handlers import format_date_time
import websocket # 使用websocket_client
answer = ""
class Ws_Param(object):
# 初始化
def __init__(self, APPID, APIKey, APISecret, gpt_url):
self.APPID = APPID
self.APIKey = APIKey
self.APISecret = APISecret
self.host = urlparse(gpt_url).netloc
self.path = urlparse(gpt_url).path
self.gpt_url = gpt_url # 注意这里使用 gpt_url
# 生成url
def create_url(self):
# 生成RFC1123格式的时间戳
now = datetime.now()
date = format_date_time(mktime(now.timetuple()))
# 拼接字符串
signature_origin = "host: " + self.host + "\n"
signature_origin += "date: " + date + "\n"
signature_origin += "GET " + self.path + " HTTP/1.1"
# 进行hmac-sha256进行加密
signature_sha = hmac.new(self.APISecret.encode('utf-8'), signature_origin.encode('utf-8'),
digestmod=hashlib.sha256).digest()
signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8')
authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'
authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
# 将请求的鉴权参数组合为字典
v = {
"authorization": authorization,
"date": date,
"host": self.host
}
# 拼接鉴权参数,生成url
url = self.gpt_url + '?' + urlencode(v) # 注意这里使用 gpt_url
return url
# 收到websocket错误的处理
def on_error(ws, error):
print("### error:", error)
def on_close(ws, one, two):
print(" ")
# 收到websocket连接建立的处理
def on_open(ws):
thread.start_new_thread(run, (ws,))
def run(ws, *args):
data = json.dumps(gen_params(appid=ws.appid, domain=ws.domain, question=ws.question))
ws.send(data)
def run_websocket(ws):
try:
ws.run_forever()
except websocket._exceptions.WebSocketConnectionClosedException:
print("WebSocket connection closed")
def on_message(ws, message):
print("Received message:", message)
# 解析JSON消息并处理
data = json.loads(message)
code = data['header']['code']
if code != 0:
print(f'请求错误: {code}, {data}')
ws.close()
else:
choices = data["payload"]["choices"]
status = choices["status"]
content = choices["text"][0]["content"]
print(content, end="")
global answer
answer += content
if status == 2:
ws.close()
def gen_params(appid, domain, question):
data = {
# "header": {
# "app_id": appid,
# "uid": "1234"
#
# },
"header": {
"app_id": appid,
"uid": "1234"
},
"parameter": {
"chat": {
"domain": domain,
"temperature": 0.3,
"max_tokens": 1000,
# "top-k": 4
}
},
"payload": {
"message": {
# "text": question
"text": [
{"role": "system", "content": "我是一个抑郁症助手"},
{"role": "user", "content": "你要帮助患者判断是否患有抑郁症并且提出建议"},
{"role": "user", "content": question}]
}
}
}
return data
def main(appid, api_key, api_secret, Spark_url, domain, question):
# print("星火:")
wsParam = Ws_Param(appid, api_key, api_secret, Spark_url)
websocket.enableTrace(False)
wsUrl = wsParam.create_url()
ws = websocket.WebSocketApp(wsUrl, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open)
ws.appid = appid
ws.question = question
ws.domain = domain
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
def getText(role, content):
text = []
jsoncon = {}
jsoncon["role"] = role
jsoncon["content"] = content
text.append(jsoncon)
return text
def getlength(text):
length = 0
for content in text:
# temp = content["content"]
temp = content
leng = len(temp)
length += leng
return length
def checklen(text):
while (getlength(text) > 8000):
del text[0]
return text
def config():
config = {}
config["appid"] = "xxx"
config["api_secret"] = "xxx"
config["api_key"] = "xxx"
config["domain"] = "xxx"
config["Spark_url"] = "xxx"
return config
注意:在config里面放入自己的appid及相关配置
main.py
app = Flask(__name__)
CORS(app, resources={r"/*": {"origins": "*"}})
app.config.from_object('SparkEdit')
@app.route("/", methods=["GET", "POST"])
def xin_info():
if request.method == "GET":
return render_template('index.html')
elif request.method == "POST":
try:
# 重置 SparkApi.answer 在每次请求开始时
SparkApi.answer = ""
# 获取请求的JSON数据
req_data = request.get_json(silent=True) # silent=True 避免请求体不是JSON时引发异常
if not req_data or 'input' not in req_data:
return jsonify({'error': 'Invalid request data'}), 400
Input = req_data['input']
# 获取配置信息
appid = SparkApi.config()["appid"]
api_secret = SparkApi.config()["api_secret"]
api_key = SparkApi.config()["api_key"]
domain = SparkApi.config()["domain"]
Spark_url = SparkApi.config()["Spark_url"]
# 处理请求并获取回答
question = SparkApi.checklen(Input)
SparkApi.main(appid, api_key, api_secret, Spark_url, domain, question)
answer_txt = SparkApi.getText("assistant", SparkApi.answer)[0]["content"]
# 返回JSON响应
return jsonify({'response': answer_txt})
except Exception as e:
# 错误信息处理
error_message = "An error occurred while processing your request."
app.logger.error(f"Error processing request: {e}") # 记录错误信息到日志
return jsonify({'error': error_message}), 500