首先新建一个Go项目
接着新建一个index文件,用于编写网页样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web App</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.26.0/themes/prism.min.css" rel="stylesheet" />
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
height: 100vh;
display: flex;
flex-direction: column;
}
.container {
width: 90%;
margin: 0 auto;
padding: 20px;
flex-grow: 1;
display: flex;
flex-direction: column;
}
input[type="text"] {
width: 100%;
padding: 10px;
box-sizing: border-box;
margin-bottom: 20px;
}
pre {
width: 100%;
padding: 10px;
box-sizing: border-box;
overflow: auto;
flex-grow: 1;
white-space: pre;
}
.copy-button {
position: absolute;
top: 0;
right: 0;
background-color: #4CAF50;
border: none;
color: white;
padding: 5px 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
欢迎使用碳链记智能合约生成助手。请问您有什么合约需求?
<input type="text" id="inputText" placeholder="请输入内容并按回车键">
<pre id="outputText" class="language-go" style="position: relative;">
<code contenteditable="true"></code>
<button class="copy-button" id="copyButton">复制</button>
</pre>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.26.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.26.0/components/prism-go.min.js"></script>
<script>
const inputText = document.getElementById("inputText");
const outputText = document.getElementById("outputText");
const copyButton = document.getElementById("copyButton");
inputText.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
event.preventDefault();
sendDataToServer(inputText.value);
outputText.querySelector('code').textContent = ""; // 清空大文本框的内容
}
});
copyButton.addEventListener("click", function() {
navigator.clipboard.writeText(outputText.querySelector('code').textContent).then(function() {
console.log("Copying to clipboard was successful!");
}, function(err) {
console.error("Could not copy text: ", err);
});
});
function sendDataToServer(data) {
// 获取当前页面的URL,然后将其更改为WebSocket URL并添加查询参数
const baseUrl = new URL(window.location.href);
baseUrl.protocol = baseUrl.protocol.replace("http", "ws");
baseUrl.pathname = "/api";
baseUrl.search = "?text=" + encodeURIComponent(data);
const ws = new WebSocket(baseUrl.toString());
ws.onmessage = function (event) {
let formattedData = event.data;
outputText.querySelector('code').textContent += formattedData;
Prism.highlightElement(outputText.querySelector('code'));
outputText.scrollTop = outputText.querySelector('code').scrollHeight;
};
ws.onerror = function (error) {
console.error("Error:", error);
ws.close();
};
}
</script>
</body>
</html>
然后在main.go中编写如下代码
package main
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/tmc/langchaingo/llms"
"github.com/tmc/langchaingo/llms/openai"
"github.com/tmc/langchaingo/schema"
"log"
"net/http"
)
var sysMessage = `你是一个Golang程序员,只输出代码,不要输出除代码以外的任何其他话。以下是已知的接口可被调用:
type SDKInterface interface {
// GetArgs get arg from transaction parameters
// @return: 参数map
GetArgs() map[string][]byte
// GetStateByte get [key, field] from chain
// @param key: 获取的参数名
// @param field: 获取的参数名
// @return1: 获取结果,格式为[]byte, nil表示不存在
// @return2: 获取错误信息
GetStateByte(key, field string) ([]byte, error)
// PutStateByte put [key, field, value] to chain
// @param1 key: 参数名
// @param1 field: 参数名
// @param2 value: 参数值,类型为[]byte
// @return1: 上传参数错误信息
PutStateByte(key, field string, value []byte) error
// DelState delete [key, field] to chain
// @param1 key: 删除的参数名
// @param1 field: 删除的参数名
// @return1:删除参数的错误信息
DelState(key, field string) error
// EmitEvent emit event, you can subscribe to the event using the SDK
// @param1 topic: 合约事件的主题
// @param2 data: 合约事件的数据
EmitEvent(topic string, data []string)
// GetTxTimeStamp 获得交易的时间戳
GetTxTimeStamp() (string, error)
// CallContract 跨合约调用另一个合约
CallContract(contractName, method string, args map[string][]byte) protogo.Response
// Sender 获得交易发送者的地址
Sender() (string, error)
}
通过sdk.Instance可以使用上述接口的函数,另外还有sdk.Success(payload []byte) protogo.Response表示成功的返回,sdk.Error(msg string) protogo.Response表示失败的返回,sdk包下没有其他方法了。
我们就可以编写类似Fabric ChainCode的合约,只是合约格式有所不同,另外一定要注意:在代码中绝对不能出现time.Now(),随机数等不确定性的函数,获取时间用sdk.Instance.GetTxTimeStamp()函数。以下是一个最简单的存证数据的合约代码:
package main
import (
"crypto/sha256"
"encoding/hex"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
// EvidenceContract 存证合约实现
type EvidenceContract struct {
}
// InitContract 初始化合约,必须实现的接口
func (e *EvidenceContract) InitContract() protogo.Response {
return sdk.SuccessResponse
}
// UpgradeContract 升级合约,必须实现的接口
func (e *EvidenceContract) UpgradeContract() protogo.Response {
return sdk.SuccessResponse
}
// InvokeContract 调用合约,必须实现的接口
func (e *EvidenceContract) InvokeContract(method string) (result protogo.Response) {
// 记录异常结果日志
defer func() {
if result.Status != 0 {
sdk.Instance.Warnf(result.Message)
}
}()
switch method {
case "PutEvidence":
return e.PutEvidence()
//其他case ...
default:
return sdk.Error("invalid method")
}
}
func (e *EvidenceContract) PutEvidence() protogo.Response {
params := sdk.Instance.GetArgs()
// 获取参数
data := params["data"]
hash:=sha256.Sum256(data)
err := sdk.Instance.PutStateByte(hex.EncodeToString( hash[:]), "data",data)
if err != nil {
return sdk.Error(err.Error())
}
// 返回OK
return sdk.SuccessResponse
}
func main() {
err := sandbox.Start(new(EvidenceContract))
if err != nil {
sdk.Instance.Errorf(err.Error())
}
}
根据以上内容,请仅提供Go代码,不要包含任何Markdown标记,也不要有任何其他文字,只要代码,满足用户的要求:`
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
http.ServeFile(c.Writer, c.Request, "index.html")
})
router.GET("/api", func(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
fmt.Println("Failed to upgrade connection:", err)
return
}
defer conn.Close()
// Get the "text" parameter from the query string
inputText := c.Query("text")
fmt.Println("Received text:", inputText)
// 将这里的OPENAI_API_BASE和OPENAI_API_KEY替换为你的实际值
llm, err := openai.NewChat(
openai.WithEmbeddingModel("text-embedding-ada-002"),
openai.WithAPIVersion("2023-07-01-preview"),
openai.WithAPIType(openai.APITypeAzure),
openai.WithBaseURL("API地址"), // 你的API基础URL
openai.WithToken("API密钥"), // 你的API密钥
openai.WithModel("API调用的名字,由AZURE新建Model时创建"))
if err != nil {
log.Fatal(err)
}
var humanMessage = c.Query("text")
ctx := context.Background()
_, err = llm.Call(ctx, []schema.ChatMessage{
schema.SystemChatMessage{Content: sysMessage},
schema.HumanChatMessage{Content: humanMessage},
}, llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error {
err = conn.WriteMessage(websocket.TextMessage, chunk)
if err != nil {
fmt.Println("Failed to write message:", err)
return err
}
return nil
}),
)
if err != nil {
log.Fatal(err)
}
})
router.Run(":8085")
}
对于go代码中的
// 将这里的OPENAI_API_BASE和OPENAI_API_KEY替换为你的实际值
llm, err := openai.NewChat(
openai.WithEmbeddingModel("text-embedding-ada-002"),
openai.WithAPIVersion("2023-07-01-preview"),
openai.WithAPIType(openai.APITypeAzure),
openai.WithBaseURL("API地址"), // 你的API基础URL
openai.WithToken("API密钥"), // 你的API密钥
openai.WithModel("API调用的名字,由AZURE新建Model时创建"))
if err != nil {
log.Fatal(err)
}
这里需要重点注意,使用的AZURE链接如下:
https://azure.microsoft.com/zh-cn/
需要在Azure里获取API地址,API密钥,API名放入代码中,即可实现效果
最后运行可实现如下效果,极大增加了代码编写效率