backend -
// server.js
const express = require('express');
const fetch = require('node-fetch'); // v2 syntax; if using node-fetch v3, adjust imports accordingly
const app = express();
const PORT = process.env.PORT || 3000;
// Serve static files (our frontend) from the "public" directory
app.use(express.static('public'));
app.use(express.json());
// Replace with your actual Twitter Bearer token
const TWITTER_BEARER_TOKEN = 'YOUR_TWITTER_BEARER_TOKEN';
// For demonstration, a simple coin symbol → CoinGecko coin id mapping.
const coinMapping = {
"BTC": "bitcoin",
"ETH": "ethereum",
"DOGE": "dogecoin"
// Add more mappings as needed...
};
// Utility function: Fetch tweets for a given handle and timeframe using Twitter API v2
async function fetchTweets(handle, startTime, endTime) {
// The Twitter API “recent search” endpoint (only returns tweets from the last 7 days)
const url = new URL('https://api.twitter.com/2/tweets/search/recent');
// Query: from:handle and must include a '$' (cashtag) so we only get coin mentions.
url.searchParams.append('query', `from:${handle} $`);
url.searchParams.append('start_time', startTime);
url.searchParams.append('end_time', endTime);
url.searchParams.append('max_results', '100'); // maximum allowed
const response = await fetch(url.toString(), {
headers: {
'Authorization': `Bearer ${TWITTER_BEARER_TOKEN}`
}
});
if (!response.ok) {
throw new Error(`Twitter API error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
return http://data.data || [];
}
// Utility function: Fetch historical price for a coin from CoinGecko
// date should be in "YYYY-MM-DD" format; we reformat it as "dd-mm-yyyy" for CoinGecko.
async function fetchHistoricalPrice(coinId, date) {
const [year, month, day] = date.split('-');
const formattedDate = `${day}-${month}-${year}`; // dd-mm-yyyy
const url = `https://api.coingecko.com/api/v3/coins/${coinId}/history?date=${formattedDate}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`CoinGecko API error (historical): ${response.status} ${response.statusText}`);
}
const data = await response.json();
return http://data.market_data?.current_price?.usd;
}
// Utility function: Fetch current price for a coin from CoinGecko
async function fetchCurrentPrice(coinId) {
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coinId}&vs_currencies=usd`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`CoinGecko API error (current): ${response.status} ${response.statusText}`);
}
const data = await response.json();
return data[coinId]?.usd;
}
// API endpoint: /api/check?handle=twitter_handle&start=YYYY-MM-DDTHH:mm:ssZ&end=YYYY-MM-DDTHH:mm:ssZ
app.get('/api/check', async (req, res) => {
const { handle, start, end } = req.query;
if (!handle || !start || !end) {
return res.status(400).json({ error: 'Missing required parameters: handle, start, end' });
}
try {
// Fetch tweets from Twitter
const tweets = await fetchTweets(handle, start, end);
const analysisResults = [];
// Regex to capture cashtags (e.g. $BTC, $ETH)
const regex = /\$([A-Z]{2,5})/g;
for (const tweet of tweets) {
const text = tweet.text;
let match;
while ((match = regex.exec(text)) !== null) {
const symbol = match[1];
// Map the symbol to a CoinGecko coin id
const coinId = coinMapping[symbol];
if (!coinId) continue; // skip if we have no mapping
// Extract the tweet creation date (format: YYYY-MM-DD)
// Note: The Twitter API returns created_at in ISO format.
const tweetDate = tweet.created_at.substring(0, 10);
let historicalPrice, currentPrice;
try {
historicalPrice = await fetchHistoricalPrice(coinId, tweetDate);
} catch (err) {
console.error(`Error fetching historical price for ${coinId} on ${tweetDate}: ${err.message}`);
continue;
}
if (!historicalPrice) continue;
try {
currentPrice = await fetchCurrentPrice(coinId);
} catch (err) {
console.error(`Error fetching current price for ${coinId}: ${err.message}`);
continue;
}
if (!currentPrice) continue;
// Calculate percentage change
const change = ((currentPrice - historicalPrice) / historicalPrice) * 100;
analysisResults.push({
tweet: tweet.text,
coin: symbol,
tweetDate,
historicalPrice,
currentPrice,
change: change.toFixed(2)
});
}
}
res.json({ results: analysisResults });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
front end -
CT Influencer Check