前言
作为一名独立开发者,相信大家都有过这样的经历:技术没问题,能力也到位,但就是不知道做什么项目。在各种论坛找灵感,看到的都是"求推荐项目"、"有什么好做的"这样的帖子。
我被这个问题困扰了很久,最后决定用技术解决技术人的问题,做了 builtwhat.app —— 一个用AI分析社交平台用户抱怨,然后转化成产品机会的平台。
今天分享一下技术实现过程。
核心思路
传统找项目的方式是主动搜索,效率低且容易陷入分析瘫痪。我的想法是:
用户的抱怨 = 产品的机会
社交平台上用户的真实抱怨往往代表着未被满足的需求,如果能系统性地分析这些抱怨,就能发现真正有价值的产品方向。
技术架构
总体架构图
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐│ 数据采集层 │────│ AI分析层 │────│ 应用服务层 ││ │ │ │ │ ││ • Reddit API │ │ • 情感分析 │ │ • Next.js 15 ││ • Twitter API │ │ • 关键词提取 │ │ • React 19 ││ • 爬虫系统 │ │ • 趋势分析 │ │ • TypeScript ││ │ │ • GPT-4 处理 │ │ │└─────────────────┘ └──────────────────┘ └─────────────────┘ │ │ │ │ ┌──────────────────┐ │ └──────────────│ Cloudflare │──────────────┘ │ │ │ • Workers │ │ • KV Storage │ │ • D1 Database │ └──────────────────┘
技术栈选择
前端:Next.js 15 + React 19
{ "next": "15.3.3", "react": "19.0.0", "typescript": "5.8.3"}
选择最新版本主要考虑:
- React 19的并发特性提升用户体验Next.js 15的app router更好的SEO支持TypeScript保证代码质量
后端:Cloudflare Workers + Hono
// workers/api.tsimport { Hono } from 'hono'import { cors } from 'hono/cors'const app = new Hono()app.use('*', cors({ origin: ['https://builtwhat.app'], allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],}))app.get('/api/inspiration/daily', async (c) => { // 获取每日灵感逻辑})export default app
Cloudflare Workers的优势:
- 全球边缘部署,中美用户访问都很快按需付费,成本可控与其他Cloudflare服务集成度高
数据存储:PostgreSQL + Redis
- PostgreSQL:主要数据存储Redis:缓存和会话管理Cloudflare KV:静态数据缓存
核心功能实现
1. 数据采集系统
这是整个系统的基础,需要从多个平台采集用户抱怨数据。
# 数据采集示例 (Python)import asyncioimport aiohttpfrom dataclasses import dataclassfrom typing import List@dataclassclass UserComplaint: platform: str content: str author: str timestamp: str engagement: intclass SocialMediaCollector: def __init__(self): self.platforms = ['reddit', 'twitter', 'hackernews'] async def collect_complaints(self) -> List[UserComplaint]: tasks = [] async with aiohttp.ClientSession() as session: for platform in self.platforms: tasks.append(self._collect_from_platform(session, platform)) results = await asyncio.gather(*tasks) return [item for sublist in results for item in sublist] async def _collect_from_platform(self, session, platform): # 具体的平台采集逻辑 # 使用合规的API或公开数据 pass
采集策略:
- 重点关注技术、产品、创业相关讨论设置关键词过滤器提高数据质量遵守各平台的API使用规范
2. AI分析引擎
这是核心的价值创造环节,需要从海量抱怨中识别真正的产品机会。
// AI分析流程export class AIAnalysisEngine { async analyzeComplaints(complaints) { // 1. 情感分析 const sentimentResults = await this.sentimentAnalysis(complaints) // 2. 关键词提取和聚类 const keywordClusters = await this.extractKeywords(complaints) // 3. 市场潜力评估 const marketPotential = await this.assessMarketPotential(keywordClusters) // 4. 产品机会生成 const opportunities = await this.generateOpportunities( sentimentResults, keywordClusters, marketPotential ) return opportunities } async sentimentAnalysis(complaints) { // 使用预训练模型进行情感分析 const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gpt-4', messages: [{ role: 'system', content: 'You are a sentiment analysis expert. Analyze the frustration level and market potential of user complaints.' }, { role: 'user', content: `Analyze these complaints: ${complaints.slice(0, 10).join('\n')}` }], }) }) return await response.json() }}
分析维度:
- 情感强度:抱怨的激烈程度频次统计:同类问题出现的频率用户画像:抱怨用户的背景分析解决难度:技术实现的可行性评估
3. 内容策划系统
分析完成后,需要将原始数据包装成可读性强的产品机会描述。
// 内容生成器export class ContentGenerator { async generateInspiration(opportunity) { const prompt = this.buildPrompt(opportunity) const response = await this.callGPT4(prompt) return { title: response.title, description: response.description, painPoint: response.painPoint, solution: response.solution, marketSize: response.marketSize, technicalRequirements: response.technicalRequirements, competitorAnalysis: response.competitorAnalysis, implementationSuggestions: response.implementationSuggestions } } buildPrompt(opportunity) { return ` Based on the following user complaints and analysis: Raw Data: ${opportunity.rawComplaints} Sentiment Score: ${opportunity.sentimentScore} Frequency: ${opportunity.frequency} User Demographics: ${opportunity.demographics} Generate a comprehensive product opportunity including: 1. Clear problem statement 2. Proposed solution approach 3. Market size estimation 4. Technical implementation guidance 5. Potential competitors 6. Go-to-market suggestions Format the response as JSON with the specified fields. ` }}
4. 用户界面实现
使用现代React技术栈构建用户友好的界面。
// components/DailyInspiration.tsx'use client'import { useState, useEffect } from 'react'import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'import { Badge } from '@/components/ui/badge'import { Button } from '@/components/ui/button'interface Inspiration { id: string title: string description: string painPoint: string tags: string[] difficulty: 'Easy' | 'Medium' | 'Hard' marketSize: string}export function DailyInspiration() { const [inspiration, setInspiration] = useState<Inspiration | null>(null) const [loading, setLoading] = useState(true) useEffect(() => { fetchDailyInspiration() }, []) const fetchDailyInspiration = async () => { try { const response = await fetch('/api/inspiration/daily') const data = await response.json() setInspiration(data) } catch (error) { console.error('Failed to fetch inspiration:', error) } finally { setLoading(false) } } if (loading) { return <div className="flex justify-center p-8">Loading...</div> } if (!inspiration) { return <div>No inspiration available</div> } return ( <Card className="max-w-2xl mx-auto"> <CardHeader> <CardTitle className="flex items-center justify-between"> {inspiration.title} <Badge variant={ inspiration.difficulty === 'Easy' ? 'secondary' : inspiration.difficulty === 'Medium' ? 'default' : 'destructive' }> {inspiration.difficulty} </Badge> </CardTitle> </CardHeader> <CardContent> <div className="space-y-4"> <div> <h3 className="font-semibold text-red-600">痛点分析</h3> <p className="text-gray-700">{inspiration.painPoint}</p> </div> <div> <h3 className="font-semibold text-blue-600">解决方案</h3> <p className="text-gray-700">{inspiration.description}</p> </div> <div className="flex flex-wrap gap-2"> {inspiration.tags.map((tag) => ( <Badge key={tag} variant="outline">{tag}</Badge> ))} </div> <div className="flex gap-2"> <Button size="sm">保存想法</Button> <Button size="sm" variant="outline">分享讨论</Button> </div> </div> </CardContent> </Card> )}
遇到的技术挑战
1. 数据采集的限制
问题: 各大平台对API访问都有严格限制
解决方案:
- 分散请求时间,避免触发速率限制使用多个数据源,降低单一平台依赖实现智能重试机制和降级策略
// 智能重试机制class RateLimitHandler { constructor() { this.retryDelays = [1000, 2000, 5000, 10000] // 指数退避 } async fetchWithRetry(url, options, maxRetries = 4) { for (let i = 0; i < maxRetries; i++) { try { const response = await fetch(url, options) if (response.status === 429) { // Rate limited await this.delay(this.retryDelays[i]) continue } return response } catch (error) { if (i === maxRetries - 1) throw error await this.delay(this.retryDelays[i]) } } } delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)) }}
2. AI分析的准确性
问题: 如何确保AI分析的质量和相关性
解决方案:
- 建立多层过滤机制人工审核关键环节持续优化提示词工程
// 质量评分系统class QualityAssessment { assessOpportunity(opportunity) { let score = 0 // 1. 痛点明确性 (0-25分) score += this.assessPainPointClarity(opportunity.painPoint) // 2. 解决方案可行性 (0-25分) score += this.assessSolutionFeasibility(opportunity.solution) // 3. 市场需求验证 (0-25分) score += this.assessMarketDemand(opportunity.marketData) // 4. 技术实现难度 (0-25分) score += this.assessTechnicalFeasibility(opportunity.technicalRequirements) return { score, shouldPublish: score >= 70, feedback: this.generateFeedback(score) } }}
3. 性能优化
问题: 用户增长后的性能和成本控制
解决方案:
// 缓存策略export class CacheManager { constructor() { this.cache = new Map() this.ttl = 24 * 60 * 60 * 1000 // 24小时缓存 } async getDailyInspiration(date) { const cacheKey = `daily_inspiration_${date}` // 检查内存缓存 if (this.cache.has(cacheKey)) { const cached = this.cache.get(cacheKey) if (Date.now() - cached.timestamp < this.ttl) { return cached.data } } // 检查Cloudflare KV const kvCached = await KV.get(cacheKey) if (kvCached) { const data = JSON.parse(kvCached) this.cache.set(cacheKey, { data, timestamp: Date.now() }) return data } // 生成新数据 const freshData = await this.generateDailyInspiration(date) // 存储到多级缓存 this.cache.set(cacheKey, { data: freshData, timestamp: Date.now() }) await KV.put(cacheKey, JSON.stringify(freshData), { expirationTtl: this.ttl / 1000 }) return freshData }}