|
| 1 | +import { UserManager, ConsensusProvider } from "@elizaos/plugin-data-enrich"; |
| 2 | +import { |
| 3 | + avalanchePlugin |
| 4 | +} from "@elizaos/plugin-avalanche"; |
| 5 | +import { |
| 6 | + elizaLogger, |
| 7 | + generateText, |
| 8 | + IAgentRuntime, |
| 9 | + ModelClass, |
| 10 | +} from "@elizaos/core"; |
| 11 | +import { ClientBase } from "./base"; |
| 12 | +import { SearchMode } from "agent-twitter-client"; |
| 13 | +import { UserResponce } from "../../plugin-avalanche/src/types/index"; |
| 14 | + |
| 15 | +export const KEY_ARENA_CACHE_STR = "key_arena_res_cache_"; |
| 16 | + |
| 17 | +export class ArenaAnalysisObj { |
| 18 | + public coin_analysis: string; |
| 19 | + public coin_prediction: string; |
| 20 | + public timestamp: number; |
| 21 | + public token: string; |
| 22 | + constructor(token: string, analysis: string, prediction: string) { |
| 23 | + this.token = token; |
| 24 | + this.coin_analysis = analysis; |
| 25 | + this.coin_prediction = prediction; |
| 26 | + this.timestamp = Date.now(); |
| 27 | + } |
| 28 | +} |
| 29 | + |
| 30 | +export class ArenaClient { |
| 31 | + client: ClientBase; |
| 32 | + runtime: IAgentRuntime; |
| 33 | + userManager: UserManager; |
| 34 | + |
| 35 | + constructor(client: ClientBase, runtime: IAgentRuntime) { |
| 36 | + this.client = client; |
| 37 | + this.runtime = runtime; |
| 38 | + this.userManager = new UserManager(this.runtime.cacheManager); |
| 39 | + this.sendingTwitterDebug = false; |
| 40 | + } |
| 41 | + |
| 42 | + intervalId: NodeJS.Timeout; |
| 43 | + sendingTwitterDebug: boolean; |
| 44 | + |
| 45 | + async start() { |
| 46 | + console.log("Arena Query start"); |
| 47 | + if (!this.client.profile) { |
| 48 | + await this.client.init(); |
| 49 | + } |
| 50 | + } |
| 51 | + async sleep(ms) { |
| 52 | + return new Promise(resolve => setTimeout(resolve, ms)); |
| 53 | + } |
| 54 | + async extractBraceContent(input: string): Promise<string> { |
| 55 | + const regex = /\{.*\}/; |
| 56 | + const match = input.match(regex); |
| 57 | + return match ? match[0] : ''; |
| 58 | + } |
| 59 | + |
| 60 | + async arenaQuery(username: string, userId: any) { |
| 61 | + // 1. get param. 2 get prompt. 3. get tweet info. 4. get arena info. 5. get ai answer. |
| 62 | + |
| 63 | + console.log("arenaQuery, in arana. username: " + username); |
| 64 | + const promptHeader = "You are a cryptocurrency expert with extensive experience in cryptocurrency trading and frequently active in various cryptocurrency communities. You are now providing an analysis based on the following two social media platforms. The first one is some dynamics of X account, and the second one is the first web3 social media associated with X. I will first provide the updates of X account"; |
| 65 | + const promptFooter = " please use 100 - word English texts respectively to analyze the reasons for the current price trend. The response format should be formatted as a JSON block as follows: {\"coin_analysis\": \"{coin_analysis}\"}. No other text should be provided, No need to use markdown syntax, just return JSON directly."; |
| 66 | + |
| 67 | + const tweetsres = await this.client.fetchSearchTweets( |
| 68 | + username, |
| 69 | + 20, SearchMode.Latest |
| 70 | + ); |
| 71 | + const promptTweet = |
| 72 | + ` |
| 73 | +Here are some tweets/replied: |
| 74 | +${[...tweetsres?.tweets] |
| 75 | + .filter((tweet) => { |
| 76 | + // ignore tweets where any of the thread tweets contain a tweet by the bot |
| 77 | + const thread = tweet.thread; |
| 78 | + const botTweet = thread.find( |
| 79 | + (t) => |
| 80 | + t.username === |
| 81 | + this.runtime.getSetting("TWITTER_USERNAME") |
| 82 | + ); |
| 83 | + return !botTweet; |
| 84 | + }) |
| 85 | + .map( |
| 86 | + (tweet) => ` |
| 87 | +From: ${tweet.name} (@${tweet.username}) |
| 88 | +Text: ${tweet.text}\n |
| 89 | +Likes: ${tweet.likes}, Replies: ${tweet.replies}, Retweets: ${tweet.retweets}, |
| 90 | + ` |
| 91 | + ) |
| 92 | + .join("\n")} |
| 93 | +`; |
| 94 | + |
| 95 | + |
| 96 | + let promptArena = `There is another web3 social networking site based on X website below, with the same account. It can send content and also capture X's dynamics on the same account. The user associated with this account has corresponding cryptocurrency prices and user information, as shown below`; |
| 97 | + const { actions } = avalanchePlugin; |
| 98 | + let aranaQueryAction = null; |
| 99 | + actions.forEach(action => { |
| 100 | + // console.log( "arenaQuery, action.name: " + action.name ); |
| 101 | + if(action.name === 'PROFILE_CHECK') { |
| 102 | + aranaQueryAction = action; |
| 103 | + } |
| 104 | + }); |
| 105 | + |
| 106 | + const arenaOptions: Record<string, unknown> = { |
| 107 | + kolname: username, |
| 108 | + }; |
| 109 | + const data = await aranaQueryAction.handler(this.runtime, null, null, arenaOptions, null); |
| 110 | + |
| 111 | + if(data) { |
| 112 | + promptArena += JSON.stringify(data) |
| 113 | + } |
| 114 | + console.log("arenaQuery, in arenaQuery. promt:\npromptHeader" |
| 115 | + + promptHeader + "\n promptTweet " |
| 116 | + + promptTweet + "\n promptArena: " + promptArena + "\n promptFooter " + promptFooter); |
| 117 | + |
| 118 | + let responseStr = await generateText({ |
| 119 | + runtime: this.runtime, |
| 120 | + context: promptHeader + promptTweet + promptArena + promptFooter, |
| 121 | + modelClass: ModelClass.LARGE, |
| 122 | + }); |
| 123 | + console.log("arenaQuery, in arenaQuery. responseStr: ", responseStr); |
| 124 | + |
| 125 | + let responseObj = null; |
| 126 | + try { |
| 127 | + responseObj = JSON.parse(responseStr); |
| 128 | + } catch (error) { |
| 129 | + responseObj = null; |
| 130 | + console.error('JSON parse error: ', error.message); |
| 131 | + } |
| 132 | + if (responseObj) { |
| 133 | + const anaobj = new ArenaAnalysisObj(username, responseObj?.coin_analysis, "empty"); |
| 134 | + await this.runtime.cacheManager.set(KEY_ARENA_CACHE_STR + username, JSON.stringify(anaobj)); |
| 135 | + } |
| 136 | + } |
| 137 | +} |
0 commit comments