
如何快速實現(xiàn)REST API集成以優(yōu)化業(yè)務(wù)流程
接下來一步一步實現(xiàn):
為了統(tǒng)一使用體驗,我們后端使用 LangChain 來對接,先不用 OpenAI 的原生接口,稍微復(fù)雜一點, 但是也沒復(fù)雜多少。
首先安裝 LangChain:
pip install langchain
增加接口,使用 LangChain 的?ChatOpenAI
來實現(xiàn)問答:
@app.get("/chat/openai")
def ask(prompt: str = Query(..., max_length=40)):
from langchain.schema import AIMessage, HumanMessage, SystemMessage
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
messages = [
SystemMessage(content="簡單回答,使用中文"),
HumanMessage(content=prompt)
]
return TextMessage(chat(messages))
用 PostMan 測試下,效果很好:
我們使用開源的?claude-api
?來模擬調(diào)用 Claude 2 的 Web 接口。
先安裝:
pip install claude-api
https://github.com/KoushikNavuluri/Claude-API
獲取 Cookie,
把 Cookie 存儲到 環(huán)境變量里面,后面用。
我們編寫?claude.py
?來測試下接口:
from claude_api import Client
import os
cookie = os.environ.get('CLAUDE_COOKIE')
claude_api = Client(cookie)
conversation_id = claude_api.create_new_chat()['uuid']
def chat(prompt):
response = claude_api.send_message(prompt, conversation_id)
print(response)
return response
if __name__ == '__main__':
chat('幫我根據(jù)顏色 # 389e0d 生成一組顏色,只返回 json')
接口連接成功,得到如下輸出:
接下來我們參考?ChatOpenAI
?實現(xiàn)?ChatClaude
。
先安裝 pydantic, 代碼里面用的到:
pip install pydantic
首先引入需要的包:
from pydantic import Field, root_validator
from langchain.schema.language_model import BaseLanguageModel
from langchain.utils import (
get_from_dict_or_env,
)
from typing import Any, AsyncIterator, Dict, Iterator, List, Optional
from langchain.callbacks.manager import (
CallbackManagerForLLMRun,
)
from langchain.chat_models.base import BaseChatModel
from langchain.schema import (
ChatGeneration,
ChatResult,
)
from langchain.schema.messages import (
AIMessage,
BaseMessage,
ChatMessage,
HumanMessage,
SystemMessage,
)
然后實現(xiàn)基礎(chǔ)類?_ClaudeCommon
:
class _ClaudeCommon(BaseLanguageModel):
HUMAN_PROMPT: Optional[str] = ''
AI_PROMPT: Optional[str] = '簡單回答'
@property
def lc_secrets(self) -> Dict[str, str]:
return {"claude_cookie": "CLAUDE_COOKIE"}
@property
def lc_serializable(self) -> bool:
return True
@root_validator()
def validate_environment(cls, values: Dict) -> Dict:
values["claude_cookie"] = get_from_dict_or_env(values, "claude_cookie", "CLAUDE_COOKIE")
values["conversation_id"] = get_from_dict_or_env(values, "conversation_id", "CONVERSATION_ID")
try:
from claude_api import Client
claude_api = Client(values["claude_cookie"])
values["client"] = claude_api
except ImportError:
raise ImportError(
"Could not import ChatClaude python package. "
)
return values
實現(xiàn)?ChatClaude
?類:
class ChatClaude(BaseChatModel, _ClaudeCommon):
@property
def _llm_type(self) -> str:
"""Return type of chat model."""
return "claude-chat"
def _convert_messages_to_text(self, messages: List[BaseMessage]) -> str:
return "".join(
self._convert_one_message_to_text(message) for message in messages
)
def _convert_messages_to_prompt(self, messages: List[BaseMessage]) -> str:
messages = messages.copy() # don't mutate the original list
if not isinstance(messages[-1], AIMessage):
messages.append(AIMessage(content=""))
text = self._convert_messages_to_text(messages)
return (
text.rstrip()
) # trim off the trailing ' ' that might come from the "Assistant: "
def _generate(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> ChatResult:
prompt = self._convert_messages_to_prompt(messages)
completion = self.client.send_message(prompt, self.conversation_id)
print(completion)
message = AIMessage(content=completion)
return ChatResult(generations=[ChatGeneration(message=message)])
增加 Claude 的接口如下:
@app.get("/chat/claude")
def ask(prompt: str = Query(..., max_length=40)):
from langchain.schema import AIMessage, HumanMessage, SystemMessage
from chat_models import ChatClaude
chat = ChatClaude()
messages = [
SystemMessage(content="簡單回答,使用中文"),
HumanMessage(content=prompt)
]
return TextMessage(chat(messages))
使用下面的地址測試:
http://127.0.0.1:8000/chat/claude?prompt=中國的首都是哪里
結(jié)果完美。
后端好了,那我們來改造后前端。
當(dāng)然昨天的 OpenAI 成果是還要留著,我們增加一個按鈕來切換 OpenAI 和 Claude 2 的使用。
先增加兩個按鈕,用來切換 Claude 和 OpenAI,
<div class="div">
<button class="button" onclick="claude('OpenAI')">OpenAI</button>
<button class="button" onclick="claude('Claude')">Claude</button>
</div>
如下:
然后修改下樣式,稍微好看點兒:
.div {
position: fixed;
top: 10px;
right: 40px;
z-index: 9999;
}
.button {
background-image: linear-gradient(135deg, #42e695, #3bb2b8);
border: 0;
color: white;
width: 100px;
height: 40px;
display: block;
margin-bottom: 10px;
border-radius: 20px;
font-weight: 200;
}
.button:last-child {
background-image: linear-gradient(135deg, #f97794, #623aa2);
}
由于 ChatUI 的文檔和 API 不全,我們簡單點,直接用?localStorage
?+?reload
?來實現(xiàn):
function claude(llm) {
localStorage.setItem('llm', llm)
window.location.reload()
}
修改?setup.js
,定義相關(guān)變量給后面用:
const llm = localStorage.getItem('llm') || 'OpenAI'
const url = llm === 'OpenAI' ? 'http://localhost:8000/chat/openai/' : 'http://localhost:8000/chat/claude/'
const welcome1 = '小翼 已鏈接 ' + llm
const welcome2 = 我是小翼的 ${llm} 分身,請問有什么可以幫您?
然后刷新頁面看看效果,點擊 Claude 成功切換,:
本文章轉(zhuǎn)載微信公眾號@數(shù)翼