-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
12fe30f
commit 07afff3
Showing
12 changed files
with
770 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.9; | ||
|
||
// Uncomment this line to use console.log | ||
// import "hardhat/console.sol"; | ||
import "./interfaces/IOracle.sol"; | ||
|
||
contract OpenAiChatGptVision { | ||
|
||
struct ChatRun { | ||
address owner; | ||
IOracle.Message[] messages; | ||
uint messagesCount; | ||
} | ||
|
||
mapping(uint => ChatRun) public chatRuns; | ||
uint private chatRunsCount; | ||
|
||
event ChatCreated(address indexed owner, uint indexed chatId); | ||
|
||
address private owner; | ||
address public oracleAddress; | ||
|
||
event OracleAddressUpdated(address indexed newOracleAddress); | ||
|
||
IOracle.OpenAiRequest private config; | ||
|
||
constructor(address initialOracleAddress) { | ||
owner = msg.sender; | ||
oracleAddress = initialOracleAddress; | ||
chatRunsCount = 0; | ||
|
||
config = IOracle.OpenAiRequest({ | ||
model : "gpt-4-turbo", | ||
frequencyPenalty : 21, // > 20 for null | ||
logitBias : "", // empty str for null | ||
maxTokens : 1000, // 0 for null | ||
presencePenalty : 21, // > 20 for null | ||
responseFormat : "{\"type\":\"text\"}", | ||
seed : 0, // null | ||
stop : "", // null | ||
temperature : 10, // Example temperature (scaled up, 10 means 1.0), > 20 means null | ||
topP : 101, // Percentage 0-100, > 100 means null | ||
tools : "", | ||
toolChoice : "", // "none" or "auto" | ||
user : "" // null | ||
}); | ||
} | ||
|
||
modifier onlyOwner() { | ||
require(msg.sender == owner, "Caller is not owner"); | ||
_; | ||
} | ||
|
||
modifier onlyOracle() { | ||
require(msg.sender == oracleAddress, "Caller is not oracle"); | ||
_; | ||
} | ||
|
||
function setOracleAddress(address newOracleAddress) public onlyOwner { | ||
oracleAddress = newOracleAddress; | ||
emit OracleAddressUpdated(newOracleAddress); | ||
} | ||
|
||
function startChat(string memory message, string memory imageUrl) public returns (uint i) { | ||
ChatRun storage run = chatRuns[chatRunsCount]; | ||
|
||
run.owner = msg.sender; | ||
IOracle.Message memory newMessage = IOracle.Message({ | ||
role: "user", | ||
content: new IOracle.Content[](2) | ||
}); | ||
newMessage.content[0] = IOracle.Content({ | ||
contentType: "text", | ||
value: message | ||
}); | ||
newMessage.content[1] = IOracle.Content({ | ||
contentType: "image_url", | ||
value: imageUrl | ||
}); | ||
run.messages.push(newMessage); | ||
run.messagesCount = 1; | ||
|
||
uint currentId = chatRunsCount; | ||
chatRunsCount = chatRunsCount + 1; | ||
|
||
IOracle(oracleAddress).createOpenAiLlmCall(currentId, config); | ||
emit ChatCreated(msg.sender, currentId); | ||
|
||
return currentId; | ||
} | ||
|
||
function onOracleOpenAiLlmResponse( | ||
uint runId, | ||
IOracle.OpenAiResponse memory response, | ||
string memory errorMessage | ||
) public onlyOracle { | ||
ChatRun storage run = chatRuns[runId]; | ||
require( | ||
keccak256(abi.encodePacked(run.messages[run.messagesCount - 1].role)) == keccak256(abi.encodePacked("user")), | ||
"No message to respond to" | ||
); | ||
|
||
if (!compareStrings(errorMessage, "")) { | ||
IOracle.Message memory newMessage = IOracle.Message({ | ||
role: "assistant", | ||
content: new IOracle.Content[](1) | ||
}); | ||
newMessage.content[0].contentType = "text"; | ||
newMessage.content[0].value = errorMessage; | ||
run.messages.push(newMessage); | ||
run.messagesCount++; | ||
} else { | ||
if (compareStrings(response.content, "")) { | ||
IOracle(oracleAddress).createFunctionCall(runId, response.functionName, response.functionArguments); | ||
} else { | ||
IOracle.Message memory newMessage = IOracle.Message({ | ||
role: "assistant", | ||
content: new IOracle.Content[](1) | ||
}); | ||
newMessage.content[0].contentType = "text"; | ||
newMessage.content[0].value = response.content; | ||
run.messages.push(newMessage); | ||
run.messagesCount++; | ||
} | ||
} | ||
} | ||
|
||
function onOracleFunctionResponse( | ||
uint runId, | ||
string memory response, | ||
string memory errorMessage | ||
) public onlyOracle { | ||
ChatRun storage run = chatRuns[runId]; | ||
require( | ||
compareStrings(run.messages[run.messagesCount - 1].role, "user"), | ||
"No function to respond to" | ||
); | ||
if (compareStrings(errorMessage, "")) { | ||
IOracle.Message memory newMessage = IOracle.Message({ | ||
role: "assistant", | ||
content: new IOracle.Content[](1) | ||
}); | ||
newMessage.content[0].contentType = "text"; | ||
newMessage.content[0].value = response; | ||
run.messages.push(newMessage); | ||
run.messagesCount++; | ||
IOracle(oracleAddress).createOpenAiLlmCall(runId, config); | ||
} | ||
} | ||
|
||
function addMessage(string memory message, uint runId) public { | ||
ChatRun storage run = chatRuns[runId]; | ||
require( | ||
keccak256(abi.encodePacked(run.messages[run.messagesCount - 1].role)) == keccak256(abi.encodePacked("assistant")), | ||
"No response to previous message" | ||
); | ||
require( | ||
run.owner == msg.sender, "Only chat owner can add messages" | ||
); | ||
|
||
IOracle.Message memory newMessage = IOracle.Message({ | ||
role: "user", | ||
content: new IOracle.Content[](1) | ||
}); | ||
newMessage.content[0].contentType = "text"; | ||
newMessage.content[0].value = message; | ||
run.messages.push(newMessage); | ||
run.messagesCount++; | ||
|
||
IOracle(oracleAddress).createOpenAiLlmCall(runId, config); | ||
} | ||
|
||
function getMessageHistory(uint chatId) public view returns (IOracle.Message[] memory) { | ||
return chatRuns[chatId].messages; | ||
} | ||
|
||
function compareStrings(string memory a, string memory b) private pure returns (bool) { | ||
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.