env cleanup, gated logs in debug mode, readme cleanup
This commit is contained in:
parent
f0a23e0333
commit
6e3c42e243
9 changed files with 96 additions and 79 deletions
|
|
@ -3,6 +3,11 @@ import cors from 'cors';
|
|||
|
||||
const app = express();
|
||||
const PORT = 3001;
|
||||
const DEBUG = process.env.REACT_APP_DEBUG_MODE === 'true';
|
||||
|
||||
function debugLog(...args) {
|
||||
if (DEBUG) console.log(...args);
|
||||
}
|
||||
|
||||
app.use(cors());
|
||||
// Increase payload limit to 10MB (default is 100kb)
|
||||
|
|
@ -13,11 +18,10 @@ app.post('/api/claude', async (req, res) => {
|
|||
try {
|
||||
const { messages, apiKey, model, maxTokens } = req.body;
|
||||
|
||||
console.log('=== Proxy received request ===');
|
||||
console.log('Model:', model);
|
||||
console.log('Max tokens:', maxTokens);
|
||||
console.log('Messages count:', messages?.length);
|
||||
console.log('API Key present:', !!apiKey);
|
||||
debugLog('=== Proxy received request ===');
|
||||
debugLog('Model:', model);
|
||||
debugLog('Max tokens:', maxTokens);
|
||||
debugLog('Messages count:', messages?.length);
|
||||
|
||||
const requestBody = {
|
||||
model: model,
|
||||
|
|
@ -25,7 +29,7 @@ app.post('/api/claude', async (req, res) => {
|
|||
messages: messages
|
||||
};
|
||||
|
||||
console.log('Request body:', JSON.stringify(requestBody, null, 2));
|
||||
debugLog('Request body:', JSON.stringify(requestBody, null, 2));
|
||||
|
||||
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
||||
method: 'POST',
|
||||
|
|
@ -37,7 +41,7 @@ app.post('/api/claude', async (req, res) => {
|
|||
body: JSON.stringify(requestBody)
|
||||
});
|
||||
|
||||
console.log('Claude API response status:', response.status);
|
||||
debugLog('Claude API response status:', response.status);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
|
|
@ -46,8 +50,8 @@ app.post('/api/claude', async (req, res) => {
|
|||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Claude API success, response content length:', data.content?.[0]?.text?.length);
|
||||
console.log('Token usage:', data.usage);
|
||||
debugLog('Claude API success, response content length:', data.content?.[0]?.text?.length);
|
||||
debugLog('Token usage:', data.usage);
|
||||
res.json(data);
|
||||
} catch (error) {
|
||||
console.error('Proxy error:', error);
|
||||
|
|
@ -64,8 +68,8 @@ app.get('/api/scrape', async (req, res) => {
|
|||
return res.status(400).json({ error: 'Missing url query parameter' });
|
||||
}
|
||||
|
||||
console.log('=== Scrape proxy request ===');
|
||||
console.log('URL:', url);
|
||||
debugLog('=== Scrape proxy request ===');
|
||||
debugLog('URL:', url);
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
|
|
@ -81,7 +85,7 @@ app.get('/api/scrape', async (req, res) => {
|
|||
}
|
||||
|
||||
const html = await response.text();
|
||||
console.log('Scraped HTML length:', html.length);
|
||||
debugLog('Scraped HTML length:', html.length);
|
||||
res.type('text/html').send(html);
|
||||
} catch (error) {
|
||||
console.error('Scrape proxy error:', error);
|
||||
|
|
@ -91,6 +95,4 @@ app.get('/api/scrape', async (req, res) => {
|
|||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Proxy server running on http://localhost:${PORT}`);
|
||||
console.log('This proxy allows the frontend to communicate with the Anthropic API');
|
||||
console.log('Scrape endpoint available at GET /api/scrape?url=...');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Brightness4, Brightness7, Refresh } from '@mui/icons-material';
|
|||
import { fetchAllSources } from '../services/dataFetcher';
|
||||
import { generateBriefing } from '../services/claudeService';
|
||||
import { saveBriefing, getPreviousBriefing, hasTodaysBriefing, getTodaysBriefing } from '../services/storageService';
|
||||
import { debugLog, debugWarn } from '../utils/constants';
|
||||
import BriefingWidget from './widgets/BriefingWidget';
|
||||
import WeatherWidget from './widgets/WeatherWidget';
|
||||
import NewsWidget from './widgets/NewsWidget';
|
||||
|
|
@ -23,29 +24,27 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
const isLoadingRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('=== Dashboard mounting, calling loadDashboard ===');
|
||||
debugLog('=== Dashboard mounting, calling loadDashboard ===');
|
||||
loadDashboard();
|
||||
}, []);
|
||||
|
||||
async function loadDashboard(forceRefresh = false) {
|
||||
// Prevent concurrent requests using ref for immediate check
|
||||
if (isLoadingRef.current) {
|
||||
console.log('=== loadDashboard SKIPPED - already in progress ===');
|
||||
console.log('Attempted at:', new Date().toISOString());
|
||||
debugLog('=== loadDashboard SKIPPED - already in progress ===');
|
||||
return;
|
||||
}
|
||||
|
||||
isLoadingRef.current = true;
|
||||
|
||||
try {
|
||||
console.log('=== loadDashboard called ===');
|
||||
console.log('Force refresh:', forceRefresh);
|
||||
console.log('Request timestamp:', new Date().toISOString());
|
||||
debugLog('=== loadDashboard called ===');
|
||||
debugLog('Force refresh:', forceRefresh);
|
||||
setError(null);
|
||||
|
||||
// Check if we already have today's briefing (unless forcing refresh)
|
||||
if (!forceRefresh && hasTodaysBriefing()) {
|
||||
console.log('Using cached briefing from today');
|
||||
debugLog('Using cached briefing from today');
|
||||
const todaysBriefing = getTodaysBriefing();
|
||||
setBriefing(todaysBriefing.briefing);
|
||||
setSourceData(todaysBriefing.sources || {});
|
||||
|
|
@ -66,13 +65,13 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('Fetching fresh data...');
|
||||
debugLog('Fetching fresh data...');
|
||||
setLoadingStatus('Fetching weather and news sources...');
|
||||
|
||||
// Fetch all configured sources
|
||||
const data = await fetchAllSources();
|
||||
console.log('Fetched sources:', Object.keys(data.sources || {}));
|
||||
console.log('Failed sources:', data.failed);
|
||||
debugLog('Fetched sources:', Object.keys(data.sources || {}));
|
||||
debugLog('Failed sources:', data.failed);
|
||||
setSourceData(data.sources || {});
|
||||
|
||||
// Track webpage summarization token usage
|
||||
|
|
@ -89,10 +88,9 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
|
||||
// Check if API key is configured
|
||||
const apiKey = import.meta.env.REACT_APP_ANTHROPIC_API_KEY;
|
||||
console.log('API key configured:', !!apiKey);
|
||||
|
||||
if (!apiKey || apiKey === 'sk-ant-your-key-here') {
|
||||
console.warn('API key not configured properly');
|
||||
debugWarn('API key not configured properly');
|
||||
setBriefing('Please add your Anthropic API key to .env.local to generate briefings.');
|
||||
setLoading(false);
|
||||
return;
|
||||
|
|
@ -100,25 +98,25 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
|
||||
// Get yesterday's briefing for comparison
|
||||
const previousBriefing = getPreviousBriefing(1);
|
||||
console.log('Previous briefing exists:', !!previousBriefing);
|
||||
debugLog('Previous briefing exists:', !!previousBriefing);
|
||||
|
||||
// Only generate briefing if we have some data
|
||||
if (Object.keys(data.sources || {}).length > 0) {
|
||||
console.log('Calling generateBriefing...');
|
||||
debugLog('Calling generateBriefing...');
|
||||
setLoadingStatus('Generating your personalized briefing with AI...');
|
||||
|
||||
try {
|
||||
// Generate today's briefing with Claude
|
||||
const result = await generateBriefing(data, previousBriefing);
|
||||
console.log('Briefing generated');
|
||||
console.log('Condensed summary:', result.condensedSummary?.substring(0, 100) + '...');
|
||||
debugLog('Briefing generated');
|
||||
debugLog('Condensed summary:', result.condensedSummary?.substring(0, 100) + '...');
|
||||
|
||||
// Handle result object with text, condensedSummary and usage
|
||||
if (result && typeof result === 'object' && result.text) {
|
||||
setBriefing(result.text);
|
||||
setBriefingTokenUsage(result.usage);
|
||||
setCacheInfo(null); // Clear cache info when generating fresh briefing
|
||||
console.log('Briefing token usage:', result.usage);
|
||||
debugLog('Briefing token usage:', result.usage);
|
||||
} else if (typeof result === 'string') {
|
||||
// Fallback for string responses
|
||||
setBriefing(result);
|
||||
|
|
@ -127,7 +125,7 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
|
||||
// Save to localStorage with condensed summary
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
console.log('Saving briefing for:', today);
|
||||
debugLog('Saving briefing for:', today);
|
||||
const briefingText = result?.text || result;
|
||||
const condensedSummary = result?.condensedSummary || null;
|
||||
saveBriefing(today, briefingText, data.sources, condensedSummary);
|
||||
|
|
@ -141,13 +139,12 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
|
||||
} catch (error) {
|
||||
console.error('Dashboard load error:', error);
|
||||
console.error('Error stack:', error.stack);
|
||||
setError(`Failed to load dashboard: ${error.message}`);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setRefreshing(false);
|
||||
isLoadingRef.current = false;
|
||||
console.log('=== loadDashboard completed at:', new Date().toISOString(), '===');
|
||||
debugLog('=== loadDashboard completed ===');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,4 +306,4 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
);
|
||||
}
|
||||
|
||||
export default Dashboard;
|
||||
export default Dashboard;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import {
|
||||
ANTHROPIC_API_URL,
|
||||
DEFAULT_CLAUDE_MODEL,
|
||||
MAX_TOKENS
|
||||
MAX_TOKENS,
|
||||
debugLog,
|
||||
debugWarn
|
||||
} from '../utils/constants';
|
||||
import { condenseSourcesForClaude } from './sourceParser';
|
||||
|
||||
|
|
@ -14,20 +16,16 @@ import { condenseSourcesForClaude } from './sourceParser';
|
|||
async function callClaude(prompt, messages = []) {
|
||||
const apiKey = import.meta.env.REACT_APP_ANTHROPIC_API_KEY;
|
||||
|
||||
console.log('=== callClaude function ===');
|
||||
console.log('API Key configured:', !!apiKey);
|
||||
console.log('API Key starts with:', apiKey?.substring(0, 15) + '...');
|
||||
|
||||
if (!apiKey || apiKey === 'sk-ant-your-key-here') {
|
||||
console.error('Anthropic API key not configured');
|
||||
return 'Please configure your Anthropic API key in .env.local';
|
||||
}
|
||||
|
||||
const model = import.meta.env.REACT_APP_CLAUDE_MODEL || DEFAULT_CLAUDE_MODEL;
|
||||
console.log('Using model:', model);
|
||||
console.log('Max tokens:', MAX_TOKENS);
|
||||
console.log('Prompt length:', prompt.length);
|
||||
console.log('Previous messages:', messages.length);
|
||||
debugLog('Using model:', model);
|
||||
debugLog('Max tokens:', MAX_TOKENS);
|
||||
debugLog('Prompt length:', prompt.length);
|
||||
debugLog('Previous messages:', messages.length);
|
||||
|
||||
try {
|
||||
const requestBody = {
|
||||
|
|
@ -40,8 +38,8 @@ async function callClaude(prompt, messages = []) {
|
|||
]
|
||||
};
|
||||
|
||||
console.log('Sending request to proxy...');
|
||||
console.log('Request messages:', requestBody.messages.map(m => ({ role: m.role, contentLength: m.content.length })));
|
||||
debugLog('Sending request to proxy...');
|
||||
debugLog('Request messages:', requestBody.messages.map(m => ({ role: m.role, contentLength: m.content.length })));
|
||||
|
||||
// Use local proxy server instead of direct API call
|
||||
const response = await fetch('http://localhost:3001/api/claude', {
|
||||
|
|
@ -52,7 +50,7 @@ async function callClaude(prompt, messages = []) {
|
|||
body: JSON.stringify(requestBody)
|
||||
});
|
||||
|
||||
console.log('Proxy response status:', response.status);
|
||||
debugLog('Proxy response status:', response.status);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
|
|
@ -61,9 +59,9 @@ async function callClaude(prompt, messages = []) {
|
|||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Response data structure:', Object.keys(data));
|
||||
console.log('Response content:', data.content?.[0]?.text?.substring(0, 200) + '...');
|
||||
console.log('Usage data:', data.usage);
|
||||
debugLog('Response data structure:', Object.keys(data));
|
||||
debugLog('Response content:', data.content?.[0]?.text?.substring(0, 200) + '...');
|
||||
debugLog('Usage data:', data.usage);
|
||||
|
||||
return {
|
||||
text: data.content[0].text,
|
||||
|
|
@ -98,9 +96,9 @@ CURRENT DATA:
|
|||
|
||||
// CONDENSE DATA BEFORE SENDING TO CLAUDE
|
||||
const condensedData = condenseSourcesForClaude(currentData.sources || currentData);
|
||||
console.log('Original data size:', JSON.stringify(currentData).length);
|
||||
console.log('Condensed data size:', JSON.stringify(condensedData).length);
|
||||
console.log('Size reduction:', Math.round((1 - JSON.stringify(condensedData).length / JSON.stringify(currentData).length) * 100) + '%');
|
||||
debugLog('Original data size:', JSON.stringify(currentData).length);
|
||||
debugLog('Condensed data size:', JSON.stringify(condensedData).length);
|
||||
debugLog('Size reduction:', Math.round((1 - JSON.stringify(condensedData).length / JSON.stringify(currentData).length) * 100) + '%');
|
||||
|
||||
// Add all condensed source data
|
||||
Object.entries(condensedData).forEach(([source, data]) => {
|
||||
|
|
@ -197,8 +195,8 @@ export async function generateBriefing(currentData, previousBriefing) {
|
|||
throw new Error('Invalid response structure from Claude');
|
||||
}
|
||||
|
||||
console.log('Successfully parsed briefing with condensed summary');
|
||||
console.log('Condensed summary:', parsed.condensedSummary.substring(0, 100) + '...');
|
||||
debugLog('Successfully parsed briefing with condensed summary');
|
||||
debugLog('Condensed summary:', parsed.condensedSummary.substring(0, 100) + '...');
|
||||
|
||||
return {
|
||||
text: parsed.fullBriefing,
|
||||
|
|
@ -210,7 +208,7 @@ export async function generateBriefing(currentData, previousBriefing) {
|
|||
|
||||
// Fallback: if JSON parsing fails, use the raw text and generate summary separately
|
||||
// This maintains backward compatibility but should rarely happen
|
||||
console.warn('Using fallback: generating condensed summary separately');
|
||||
debugWarn('Using fallback: generating condensed summary separately');
|
||||
const condensedSummary = await generateCondensedSummary(result.text);
|
||||
|
||||
return {
|
||||
|
|
@ -394,4 +392,4 @@ Be concise and focus on what would be most relevant to someone checking their da
|
|||
console.error(`Error summarizing ${dataType}:`, error);
|
||||
return `Unable to summarize ${dataType} data.`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ import {
|
|||
DEFAULT_DATA_SOURCES,
|
||||
WEATHER_API_BASE,
|
||||
DEFAULT_REFRESH_INTERVAL,
|
||||
DEFAULT_TEMPERATURE_UNIT
|
||||
DEFAULT_TEMPERATURE_UNIT,
|
||||
debugLog,
|
||||
debugWarn
|
||||
} from '../utils/constants';
|
||||
|
||||
/**
|
||||
|
|
@ -53,19 +55,19 @@ export async function fetchSingleSource(url) {
|
|||
// Check cache first
|
||||
const cached = getCachedData(cacheKey);
|
||||
if (cached) {
|
||||
console.log(`Using cached data for ${url}`);
|
||||
debugLog(`Using cached data for ${url}`);
|
||||
return cached;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`Fetching fresh data from ${url}`);
|
||||
debugLog(`Fetching fresh data from ${url}`);
|
||||
const data = await parseSource(url);
|
||||
let standardized = standardizeSourceData(data, url);
|
||||
let tokenUsage = null;
|
||||
|
||||
// If this is a webpage that needs Claude summarization, do it now
|
||||
if (standardized.type === 'webpage' && standardized.needsSummarization && standardized.cleanedText) {
|
||||
console.log(`Summarizing webpage content from ${url} with Claude...`);
|
||||
debugLog(`Summarizing webpage content from ${url} with Claude...`);
|
||||
try {
|
||||
const summary = await summarizeWebpage(standardized.cleanedText, url);
|
||||
standardized = {
|
||||
|
|
@ -80,9 +82,9 @@ export async function fetchSingleSource(url) {
|
|||
};
|
||||
// Track token usage from webpage summarization
|
||||
tokenUsage = summary.usage;
|
||||
console.log(`Webpage summarized: "${summary.title}" (${summary.items?.length || 0} items)`);
|
||||
debugLog(`Webpage summarized: "${summary.title}" (${summary.items?.length || 0} items)`);
|
||||
if (tokenUsage) {
|
||||
console.log(`Webpage summarization tokens: ${tokenUsage.input_tokens} input + ${tokenUsage.output_tokens} output`);
|
||||
debugLog(`Webpage summarization tokens: ${tokenUsage.input_tokens} input + ${tokenUsage.output_tokens} output`);
|
||||
}
|
||||
} catch (summaryError) {
|
||||
console.error(`Failed to summarize webpage ${url}:`, summaryError);
|
||||
|
|
@ -104,7 +106,7 @@ export async function fetchSingleSource(url) {
|
|||
// Try to return cached data even if expired
|
||||
const expiredCache = getCachedData(cacheKey);
|
||||
if (expiredCache) {
|
||||
console.log(`Returning expired cache for ${url} due to fetch error`);
|
||||
debugLog(`Returning expired cache for ${url} due to fetch error`);
|
||||
return expiredCache;
|
||||
}
|
||||
throw error;
|
||||
|
|
@ -118,7 +120,7 @@ export async function fetchSingleSource(url) {
|
|||
*/
|
||||
export async function fetchWeather(location) {
|
||||
if (!location) {
|
||||
console.warn('No location configured for weather');
|
||||
debugWarn('No location configured for weather');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -158,8 +160,8 @@ export async function fetchAllSources() {
|
|||
// Get location for weather
|
||||
const location = import.meta.env.REACT_APP_LOCATION;
|
||||
|
||||
console.log('Fetching from sources:', sources);
|
||||
console.log('Weather location:', location);
|
||||
debugLog('Fetching from sources:', sources);
|
||||
debugLog('Weather location:', location);
|
||||
|
||||
let sourcesByRow = {};
|
||||
let allUrls = [];
|
||||
|
|
@ -237,7 +239,7 @@ export async function fetchAllSources() {
|
|||
});
|
||||
|
||||
if (allTokenUsage.length > 0) {
|
||||
console.log(`Total webpage summarization usage: ${totalWebpageTokens.input_tokens} input + ${totalWebpageTokens.output_tokens} output tokens from ${allTokenUsage.length} source(s)`);
|
||||
debugLog(`Total webpage summarization usage: ${totalWebpageTokens.input_tokens} input + ${totalWebpageTokens.output_tokens} output tokens from ${allTokenUsage.length} source(s)`);
|
||||
}
|
||||
|
||||
// Organize data by rows
|
||||
|
|
@ -282,7 +284,7 @@ export async function fetchAllSources() {
|
|||
|
||||
// Log any errors
|
||||
if (errors.length > 0) {
|
||||
console.warn('Some sources failed to fetch:', errors);
|
||||
debugWarn('Some sources failed to fetch:', errors);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -294,4 +296,3 @@ export async function fetchAllSources() {
|
|||
webpageTokenUsage: allTokenUsage.length > 0 ? totalWebpageTokens : null
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { getCachedData, cacheSourceData } from './storageService';
|
||||
import { fetchWithCors } from '../utils/corsProxy';
|
||||
import { debugLog } from '../utils/constants';
|
||||
|
||||
// Weather code descriptions mapping (WMO Weather interpretation codes)
|
||||
const WEATHER_CODE_MAP = {
|
||||
|
|
@ -76,13 +77,13 @@ async function geocodeLocation(location) {
|
|||
// Check cache first (geocoding results are stable)
|
||||
const cached = getCachedData(cacheKey);
|
||||
if (cached) {
|
||||
console.log(`Using cached geocoding for ${locationStr}`);
|
||||
debugLog(`Using cached geocoding for ${locationStr}`);
|
||||
return cached;
|
||||
}
|
||||
|
||||
try {
|
||||
const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(locationStr)}&count=1&language=en&format=json`;
|
||||
console.log(`Geocoding location: ${locationStr}`);
|
||||
debugLog(`Geocoding location: ${locationStr}`);
|
||||
|
||||
const data = await fetchWithCors(url);
|
||||
|
||||
|
|
@ -129,7 +130,7 @@ async function fetchCurrentAndForecast(latitude, longitude, tempUnit = 'F') {
|
|||
`&timezone=auto` +
|
||||
`&forecast_days=5`;
|
||||
|
||||
console.log(`Fetching current weather and forecast for ${latitude}, ${longitude}`);
|
||||
debugLog(`Fetching current weather and forecast for ${latitude}, ${longitude}`);
|
||||
|
||||
const data = await fetchWithCors(url);
|
||||
return data;
|
||||
|
|
@ -161,7 +162,7 @@ async function fetchHistorical(latitude, longitude, tempUnit = 'F') {
|
|||
`&wind_speed_unit=${windUnitParam}` +
|
||||
`&timezone=auto`;
|
||||
|
||||
console.log(`Fetching historical weather for ${latitude}, ${longitude}`);
|
||||
debugLog(`Fetching historical weather for ${latitude}, ${longitude}`);
|
||||
|
||||
const data = await fetchWithCors(url);
|
||||
return data;
|
||||
|
|
@ -190,7 +191,7 @@ export async function fetchOpenMeteoWeather(location, tempUnit = 'F') {
|
|||
// Check cache first
|
||||
const cached = getCachedData(cacheKey);
|
||||
if (cached) {
|
||||
console.log(`Using cached Open-Meteo data for ${location}`);
|
||||
debugLog(`Using cached Open-Meteo data for ${location}`);
|
||||
return cached;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { fetchWithCors } from '../utils/corsProxy';
|
||||
import { RSS_TO_JSON_API } from '../utils/constants';
|
||||
import { RSS_TO_JSON_API, debugLog, debugWarn } from '../utils/constants';
|
||||
|
||||
/**
|
||||
* Determine source type from URL
|
||||
|
|
@ -126,7 +126,7 @@ export async function parseHTML(url, corsProxy) {
|
|||
|
||||
rawHTML = await response.text();
|
||||
} catch (proxyError) {
|
||||
console.warn(`Local scrape proxy failed for ${url}, falling back to CORS proxy:`, proxyError.message);
|
||||
debugWarn(`Local scrape proxy failed for ${url}, falling back to CORS proxy:`, proxyError.message);
|
||||
try {
|
||||
const html = await fetchWithCors(url);
|
||||
rawHTML = typeof html === 'string' ? html : JSON.stringify(html);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,20 @@
|
|||
// App constants
|
||||
export const STORAGE_KEY = 'claudash';
|
||||
export const DEBUG = import.meta.env.REACT_APP_DEBUG_MODE === 'true';
|
||||
|
||||
/**
|
||||
* Debug-gated console.log — only outputs when DEBUG mode is enabled
|
||||
*/
|
||||
export function debugLog(...args) {
|
||||
if (DEBUG) console.log(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug-gated console.warn — only outputs when DEBUG mode is enabled
|
||||
*/
|
||||
export function debugWarn(...args) {
|
||||
if (DEBUG) console.warn(...args);
|
||||
}
|
||||
|
||||
export const DEFAULT_REFRESH_INTERVAL = 15; // minutes
|
||||
export const DEFAULT_HISTORY_DAYS = 7;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { DEFAULT_CORS_PROXY } from './constants';
|
||||
import { DEFAULT_CORS_PROXY, debugWarn } from './constants';
|
||||
|
||||
/**
|
||||
* Fetch data with CORS proxy fallback
|
||||
|
|
@ -32,7 +32,7 @@ export async function fetchWithCors(url, options = {}) {
|
|||
}
|
||||
} catch (error) {
|
||||
// If CORS fails, try with proxy
|
||||
console.warn(`CORS failed for ${url}, trying proxy...`, error.message);
|
||||
debugWarn(`CORS failed for ${url}, trying proxy...`, error.message);
|
||||
|
||||
try {
|
||||
const proxiedUrl = `${proxy}${encodeURIComponent(url)}`;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ export default defineConfig(({ mode }) => {
|
|||
'import.meta.env.REACT_APP_CLAUDE_INSTRUCTIONS': JSON.stringify(env.REACT_APP_CLAUDE_INSTRUCTIONS),
|
||||
'import.meta.env.REACT_APP_DEBUG_MODE': JSON.stringify(env.REACT_APP_DEBUG_MODE),
|
||||
'import.meta.env.REACT_APP_QUICK_LINKS': JSON.stringify(env.REACT_APP_QUICK_LINKS),
|
||||
'import.meta.env.REACT_APP_TEMPERATURE_UNIT': JSON.stringify(env.REACT_APP_TEMPERATURE_UNIT),
|
||||
'import.meta.env.REACT_APP_CHART_DATE_FORMAT': JSON.stringify(env.REACT_APP_CHART_DATE_FORMAT),
|
||||
'import.meta.env.REACT_APP_TEXT_VOICE': JSON.stringify(env.REACT_APP_TEXT_VOICE),
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
Reference in a new issue