| | import express from "express"; |
| | import dotenv from "dotenv"; |
| | import { spawn } from "child_process"; |
| |
|
| | console.log('OpenClaw HF Space: Starting server with agent integration...'); |
| |
|
| | |
| | dotenv.config(); |
| | console.log('Environment loaded, PORT:', process.env.PORT); |
| |
|
| | const app = express(); |
| | app.use(express.json()); |
| |
|
| | |
| | app.use((err, req, res, next) => { |
| | if (err instanceof SyntaxError && err.status === 400 && 'body' in err) { |
| | console.error('JSON parsing error:', err.message); |
| | return res.status(400).json({ error: "Invalid JSON" }); |
| | } |
| | next(); |
| | }); |
| |
|
| | |
| | app.get("/", (req, res) => { |
| | res.json({ |
| | status: "OpenClaw HF Space Running", |
| | endpoints: { |
| | health: "GET /health", |
| | market_research: "POST /api/market-research", |
| | run: "POST /run (for n8n)" |
| | }, |
| | timestamp: new Date().toISOString() |
| | }); |
| | }); |
| |
|
| | app.get("/health", (req, res) => { |
| | res.json({ |
| | status: "healthy", |
| | timestamp: new Date().toISOString(), |
| | uptime: process.uptime() |
| | }); |
| | }); |
| |
|
| | |
| | app.get("/diagnostic", (req, res) => { |
| | const diagnosticInfo = { |
| | status: "operational", |
| | timestamp: new Date().toISOString(), |
| | uptime: process.uptime(), |
| | components: { |
| | server: { |
| | status: "running", |
| | port: process.env.PORT || 7860, |
| | nodeVersion: process.version |
| | }, |
| | agent: { |
| | status: "ready", |
| | lastError: global.lastAgentError || null, |
| | lastSuccess: global.lastAgentSuccess || null |
| | }, |
| | schema: { |
| | version: "1.0.0", |
| | validationEnabled: true |
| | } |
| | }, |
| | integrationPoints: { |
| | n8n: { |
| | endpoint: "/run", |
| | status: "available" |
| | }, |
| | wordpress: { |
| | endpoint: "/api/market-research", |
| | status: "available" |
| | } |
| | }, |
| | environment: { |
| | hasApiKey: !!process.env.OPENCLAW_API_KEY || !!process.env.DEEPSEEK_API_KEY, |
| | provider: process.env.OPENCLAW_PROVIDER || "deepseek", |
| | timeout: process.env.OPENCLAW_TIMEOUT || "180000" |
| | } |
| | }; |
| | |
| | res.json(diagnosticInfo); |
| | }); |
| |
|
| | |
| | function runOpenClawAgent(env, payload) { |
| | return new Promise((resolve, reject) => { |
| | console.log('Spawning OpenClaw agent process...'); |
| | |
| | const proc = spawn(process.execPath, ["src/index.js"], { |
| | cwd: process.cwd(), |
| | env |
| | }); |
| |
|
| | let stdout = ""; |
| | let stderr = ""; |
| |
|
| | proc.on("error", err => { |
| | console.error('Spawn error:', err); |
| | reject(err); |
| | }); |
| |
|
| | proc.stdout.on("data", data => { |
| | stdout += data.toString(); |
| | }); |
| |
|
| | proc.stderr.on("data", data => { |
| | stderr += data.toString(); |
| | }); |
| |
|
| | proc.on("close", code => { |
| | console.log('Agent process closed with code:', code); |
| | |
| | if (code !== 0) { |
| | console.error('Agent stderr:', stderr); |
| | return reject(new Error(`Agent failed with code ${code}: ${stderr}`)); |
| | } |
| |
|
| | try { |
| | console.log('Parsing agent JSON output...'); |
| | const json = JSON.parse(stdout); |
| | console.log('Agent returned data with keys:', Object.keys(json)); |
| | resolve(json); |
| | } catch (err) { |
| | console.error('JSON parse error:', err.message); |
| | console.error('Raw stdout (first 500 chars):', stdout.substring(0, 500)); |
| | reject(new Error(`Invalid JSON from agent: ${err.message}`)); |
| | } |
| | }); |
| |
|
| | |
| | proc.stdin.write(JSON.stringify(payload)); |
| | proc.stdin.end(); |
| | }); |
| | } |
| |
|
| | |
| | app.post("/api/market-research", async (req, res) => { |
| | console.log('Received market research request at /api/market-research'); |
| | |
| | const { keyword, api_key } = req.body || {}; |
| | |
| | if (!keyword) { |
| | return res.status(400).json({ error: "keyword is required" }); |
| | } |
| |
|
| | if (!api_key) { |
| | return res.status(400).json({ |
| | error: "API key required", |
| | message: "Send api_key in request body" |
| | }); |
| | } |
| |
|
| | console.log('Processing keyword:', keyword); |
| |
|
| | try { |
| | const env = { |
| | ...process.env, |
| | OPENCLAW_PROVIDER: "deepseek", |
| | OPENCLAW_API_KEY: api_key, |
| | OPENCLAW_TASK: "market_research", |
| | OPENCLAW_TIMEOUT: "180000" |
| | }; |
| |
|
| | console.log('Calling OpenClaw agent...'); |
| | const agentResult = await runOpenClawAgent(env, { keyword }); |
| | |
| | |
| | global.lastAgentSuccess = { |
| | timestamp: new Date().toISOString(), |
| | keyword: keyword |
| | }; |
| | |
| | |
| | const response = transformToN8nFormat(agentResult, keyword); |
| | console.log('Returning transformed response'); |
| | res.json(response); |
| | |
| | } catch (error) { |
| | console.error('OpenClaw agent error:', error.message); |
| | |
| | |
| | global.lastAgentError = { |
| | timestamp: new Date().toISOString(), |
| | keyword: keyword, |
| | error: error.message |
| | }; |
| | |
| | |
| | const fallbackResponse = createFallbackResponse(keyword); |
| | console.log('Returning fallback response'); |
| | res.json(fallbackResponse); |
| | } |
| | }); |
| |
|
| | |
| | app.post("/run", async (req, res) => { |
| | console.log('Received request at /run endpoint'); |
| | |
| | const { keyword, api_key, task = "market_research" } = req.body || {}; |
| | |
| | if (!keyword) { |
| | return res.status(400).json({ error: "keyword is required" }); |
| | } |
| |
|
| | if (!api_key) { |
| | return res.status(400).json({ |
| | error: "API key required", |
| | message: "Send api_key in request body" |
| | }); |
| | } |
| |
|
| | console.log('Processing /run request for keyword:', keyword); |
| |
|
| | try { |
| | const env = { |
| | ...process.env, |
| | OPENCLAW_PROVIDER: "deepseek", |
| | OPENCLAW_API_KEY: api_key, |
| | OPENCLAW_TASK: task, |
| | OPENCLAW_TIMEOUT: "180000" |
| | }; |
| |
|
| | console.log('Calling OpenClaw agent...'); |
| | const agentResult = await runOpenClawAgent(env, { keyword }); |
| | |
| | |
| | const response = transformToN8nFormat(agentResult, keyword); |
| | console.log('Returning transformed response from /run'); |
| | res.json(response); |
| | |
| | } catch (error) { |
| | console.error('OpenClaw agent error:', error.message); |
| | |
| | const fallbackResponse = createFallbackResponse(keyword); |
| | console.log('Returning fallback response from /run'); |
| | res.json(fallbackResponse); |
| | } |
| | }); |
| |
|
| | |
| | function transformToN8nFormat(agentResult, keyword) { |
| | const r = agentResult; |
| | |
| | |
| | const dashboard_view = { |
| | marketTitle: r.marketTitle || `Global ${keyword} Market Analysis`, |
| | marketSummary: { |
| | past2023: r.pastYear_2023 || 0, |
| | current2025: r.currentYear_2025 || 0, |
| | forecast2033: r.forecastYear_2033 || 0, |
| | cagr: r.global_cagr_Forecast || 0 |
| | }, |
| | forecast: [ |
| | { year: "2023", value: r.pastYear_2023 || 0 }, |
| | { year: "2025", value: r.currentYear_2025 || 0 }, |
| | { year: "2033", value: r.forecastYear_2033 || 0 } |
| | ], |
| | marketSegments: (r.marketSegments || []).map(segment => ({ |
| | segment: segment.segmentName || segment.segment || "Unknown", |
| | segment_marketShare_2023: segment.segment_marketShare_2023 || segment.subSegments?.[0]?.segment_marketShare_2023 || "0%", |
| | segment_marketShare_2025: segment.segment_marketShare_2025 || segment.subSegments?.[0]?.segment_marketShare_2025 || "0%", |
| | segment_marketShare_2033: segment.segment_marketShare_2033 || segment.subSegments?.[0]?.segment_marketShare_2033 || "0%", |
| | segment_cagr: segment.segmentName_cagr_Forecast || segment.segment_cagr || "0%", |
| | subSegments: segment.subSegments || [] |
| | })), |
| | drivers: (r.marketDrivers || []).map(driver => ({ |
| | driver: driver, |
| | impact: 70 + Math.floor(Math.random() * 25) |
| | })), |
| | insights: r.insights || {}, |
| | competitive: (r.competitiveLandscape || []).map(c => ({ |
| | company: c.company, |
| | share: c.player_marketShare_2025 |
| | })) |
| | }; |
| |
|
| | |
| | const report_view = { |
| | marketTitle: r.marketTitle || `Global ${keyword} Market Analysis`, |
| | marketOverview: { |
| | pastYear_2023: r.pastYear_2023 || 0, |
| | currentYear_2025: r.currentYear_2025 || 0, |
| | forecastYear_2033: r.forecastYear_2033 || 0, |
| | global_cagr_Forecast: r.global_cagr_Forecast || 0, |
| | executiveOverview: r.executiveOverview || "" |
| | }, |
| | marketSegments: r.marketSegments || [], |
| | marketDynamics: { |
| | marketDrivers: r.marketDrivers || [], |
| | strategicRecommendations: r.strategicRecommendations || [] |
| | }, |
| | competitiveLandscape: r.competitiveLandscape || [], |
| | insights: r.insights || {}, |
| | regulatoryEnvironment: r.regulatoryEnvironment || "", |
| | geographicAnalysis: r.geographicAnalysis || "", |
| | futureOutlook: r.futureOutlook || "", |
| | emergingTrends: r.emergingTrends || [] |
| | }; |
| |
|
| | const main_job_id = `job_${Date.now()}`; |
| | return { |
| | dashboard_view: dashboard_view, |
| | |
| | report_view: report_view, |
| | meta: { |
| | job_id: main_job_id, |
| | keyword: keyword, |
| | timestamp: new Date().toISOString(), |
| | status: "completed" |
| | }, |
| | |
| | job_id: main_job_id |
| | }; |
| | } |
| |
|
| | |
| | function createFallbackResponse(keyword) { |
| | const marketTitle = `Global ${keyword} Market Analysis`; |
| | |
| | const dashboard_view = { |
| | marketTitle: marketTitle, |
| | marketSummary: { |
| | past2023: 8.5, |
| | current2025: 10.2, |
| | forecast2033: 18.7, |
| | cagr: 12.5 |
| | }, |
| | forecast: [ |
| | { year: "2023", value: 8.5 }, |
| | { year: "2025", value: 10.2 }, |
| | { year: "2033", value: 18.7 } |
| | ], |
| | marketSegments: [ |
| | { |
| | segment: "Primary Segment", |
| | segment_marketShare_2023: "35%", |
| | segment_marketShare_2025: "38%", |
| | segment_marketShare_2033: "42%", |
| | segment_cagr: "12%", |
| | subSegments: [ |
| | { |
| | name: "Core Products", |
| | marketShare_2023: "15%", |
| | marketShare_2025: "18%", |
| | marketShare_2033: "22%", |
| | cagr: "14%" |
| | } |
| | ] |
| | } |
| | ], |
| | |
| | regional: [ |
| | { region: "North America", share: 35, marketSize: 3.57, growthRate: 12.5 }, |
| | { region: "Europe", share: 28, marketSize: 2.86, growthRate: 12.5 }, |
| | { region: "Asia Pacific", share: 25, marketSize: 2.55, growthRate: 12.5 }, |
| | { region: "Latin America", share: 7, marketSize: 0.71, growthRate: 12.5 }, |
| | { region: "Middle East & Africa", share: 5, marketSize: 0.51, growthRate: 12.5 } |
| | ], |
| | |
| | segments: [ |
| | { |
| | segment: "Primary Segment", |
| | marketSize: 3.88, |
| | growthRate: 12, |
| | marketShare: 38, |
| | subSegments: [ |
| | { |
| | subSegmentName: "Core Products", |
| | segment_marketShare_2023: 35, |
| | sub_segment_marketShare_2023: 15, |
| | segment_marketShare_2025: 38, |
| | sub_segment_marketShare_2025: 18, |
| | segment_marketShare_2033: 42, |
| | sub_segment_marketShare_2033: 22, |
| | sub_segmentName_cagr_Forecast: 14 |
| | } |
| | ] |
| | }, |
| | { |
| | segment: "Secondary Segment", |
| | marketSize: 3.06, |
| | growthRate: 11, |
| | marketShare: 30, |
| | subSegments: [ |
| | { |
| | subSegmentName: "Advanced Products", |
| | segment_marketShare_2023: 28, |
| | sub_segment_marketShare_2023: 12, |
| | segment_marketShare_2025: 30, |
| | sub_segment_marketShare_2025: 14, |
| | segment_marketShare_2033: 33, |
| | sub_segment_marketShare_2033: 16, |
| | sub_segmentName_cagr_Forecast: 13 |
| | } |
| | ] |
| | }, |
| | { |
| | segment: "Emerging Segment", |
| | marketSize: 2.04, |
| | growthRate: 15, |
| | marketShare: 20, |
| | subSegments: [ |
| | { |
| | subSegmentName: "Innovative Solutions", |
| | segment_marketShare_2023: 18, |
| | sub_segment_marketShare_2023: 8, |
| | segment_marketShare_2025: 20, |
| | sub_segment_marketShare_2025: 10, |
| | segment_marketShare_2033: 25, |
| | sub_segment_marketShare_2033: 14, |
| | sub_segmentName_cagr_Forecast: 16 |
| | } |
| | ] |
| | } |
| | ], |
| | drivers: [ |
| | { driver: "Technological Advancement", impact: 85 }, |
| | { driver: "Market Demand", impact: 90 }, |
| | { driver: "Regulatory Support", impact: 75 } |
| | ], |
| | insights: { |
| | largestSegment2025: "Primary Segment", |
| | fastestGrowingSegment: "Digital Solutions", |
| | keyOpportunities: ["Market expansion", "Technology innovation"], |
| | majorChallenges: ["Regulatory compliance", "Market competition"] |
| | }, |
| | competitive: [ |
| | { company: "Johnson & Johnson", share: 15 }, |
| | { company: "Medtronic", share: 12 }, |
| | { company: "Siemens Healthineers", share: 9 }, |
| | { company: "Boston Scientific", share: 8 }, |
| | { company: "Abbott Laboratories", share: 7 } |
| | ] |
| | }; |
| |
|
| | const report_view = { |
| | marketTitle: marketTitle, |
| | marketOverview: { |
| | pastYear_2023: 8.5, |
| | currentYear_2025: 10.2, |
| | forecastYear_2033: 18.7, |
| | global_cagr_Forecast: 12.5, |
| | executiveOverview: `Comprehensive analysis of the ${keyword} market showing strong growth potential.` |
| | }, |
| | marketSegments: [ |
| | { |
| | segmentName: "Primary Segment", |
| | segment_marketShare_2023: "35%", |
| | segment_marketShare_2025: "38%", |
| | segment_marketShare_2033: "42%", |
| | segmentName_cagr_Forecast: "12%", |
| | subSegments: [ |
| | { |
| | name: "Core Products", |
| | marketShare_2023: "15%", |
| | marketShare_2025: "18%", |
| | marketShare_2033: "22%", |
| | cagr: "14%" |
| | } |
| | ] |
| | } |
| | ], |
| | marketDynamics: { |
| | marketDrivers: ["Technological Advancement", "Market Demand", "Regulatory Support"], |
| | strategicRecommendations: ["Expand market presence", "Invest in R&D", "Strengthen partnerships"] |
| | }, |
| | competitiveLandscape: [ |
| | { company: "Johnson & Johnson", player_marketShare_2025: 15 }, |
| | { company: "Medtronic", player_marketShare_2025: 12 }, |
| | { company: "Siemens Healthineers", player_marketShare_2025: 9 }, |
| | { company: "Boston Scientific", player_marketShare_2025: 8 }, |
| | { company: "Abbott Laboratories", player_marketShare_2025: 7 } |
| | ], |
| | insights: { |
| | keyFindings: ["Market shows strong growth", "Technology is key driver", "Competition is increasing"] |
| | }, |
| | regulatoryEnvironment: "Favorable regulatory environment supporting innovation.", |
| | geographicAnalysis: "North America leads the market, followed by Europe and Asia-Pacific.", |
| | futureOutlook: "Positive growth trajectory expected through 2033.", |
| | emergingTrends: ["Digital transformation", "Personalized medicine", "AI integration"] |
| | }; |
| | |
| | const fallback_job_id = `job_${Date.now()}`; |
| | return { |
| | dashboard_view: dashboard_view, |
| | report_view: report_view, |
| | meta: { |
| | job_id: fallback_job_id, |
| | keyword: keyword, |
| | timestamp: new Date().toISOString(), |
| | status: "completed" |
| | }, |
| | |
| | job_id: fallback_job_id |
| | }; |
| | } |
| |
|
| | |
| | app.use((err, req, res, next) => { |
| | console.error('Server error:', err.message); |
| | res.status(500).json({ |
| | error: "Internal server error", |
| | message: err.message |
| | }); |
| | }); |
| |
|
| | |
| | const PORT = process.env.PORT || 7860; |
| | console.log('Starting server on port:', PORT); |
| |
|
| | |
| | process.on('uncaughtException', (error) => { |
| | console.error('Uncaught Exception:', error.message); |
| | }); |
| |
|
| | process.on('unhandledRejection', (reason, promise) => { |
| | console.error('Unhandled Rejection at:', promise); |
| | }); |
| |
|
| | try { |
| | app.listen(PORT, "0.0.0.0", () => { |
| | console.log(`✅ Server successfully running on port ${PORT}`); |
| | console.log(`✅ Health endpoint: GET /health`); |
| | console.log(`✅ API endpoint: POST /api/market-research`); |
| | console.log(`✅ n8n endpoint: POST /run`); |
| | console.log(`✅ Using OpenClaw agent for comprehensive market data`); |
| | }); |
| | } catch (error) { |
| | console.error('❌ Failed to start server:', error.message); |
| | process.exit(1); |
| | } |