Skip to content

Commit 13658b6

Browse files
File changes
1 parent bdde048 commit 13658b6

File tree

1 file changed

+266
-0
lines changed

1 file changed

+266
-0
lines changed
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
import React, { useState } from 'react';
2+
import { useMutation } from '@tanstack/react-query';
3+
import { base44 } from '@/api/base44Client';
4+
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
5+
import { Button } from '@/components/ui/button';
6+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
7+
import { Badge } from '@/components/ui/badge';
8+
import { Sparkles, FileText, Loader2, ChevronDown, ChevronUp, Copy, Check } from 'lucide-react';
9+
import { toast } from 'sonner';
10+
import ReactMarkdown from 'react-markdown';
11+
12+
const AVAILABLE_DOCS = [
13+
{ value: 'ARCHITECTURE.md', label: 'Architecture Overview', category: 'Technical' },
14+
{ value: 'PRD_MASTER.md', label: 'Product Requirements', category: 'Product' },
15+
{ value: 'API_REFERENCE.md', label: 'API Reference', category: 'Technical' },
16+
{ value: 'SECURITY.md', label: 'Security Documentation', category: 'Technical' },
17+
{ value: 'FEATURE_SPECS.md', label: 'Feature Specifications', category: 'Product' },
18+
{ value: 'ONBOARDING_SPEC.md', label: 'Onboarding System', category: 'Product' },
19+
{ value: 'GAMIFICATION_ADMIN_GUIDE.md', label: 'Gamification Guide', category: 'Admin' },
20+
{ value: 'AI_FEATURES_DOCUMENTATION.md', label: 'AI Features', category: 'Technical' },
21+
{ value: 'DATABASE_SCHEMA_TECHNICAL_SPEC.md', label: 'Database Schema', category: 'Technical' },
22+
{ value: 'DEPLOYMENT_GUIDE.md', label: 'Deployment Guide', category: 'Operations' },
23+
{ value: 'QUICK_START_GUIDE.md', label: 'Quick Start Guide', category: 'Getting Started' },
24+
{ value: 'USER_FLOWS.md', label: 'User Flows', category: 'Product' },
25+
];
26+
27+
export default function DocSummarizer() {
28+
const [selectedDoc, setSelectedDoc] = useState('');
29+
const [summary, setSummary] = useState(null);
30+
const [fullContent, setFullContent] = useState('');
31+
const [showFull, setShowFull] = useState(false);
32+
const [copied, setCopied] = useState(false);
33+
34+
const summarizeMutation = useMutation({
35+
mutationFn: async (docName) => {
36+
// Fetch the documentation file content
37+
const response = await fetch(`/components/docs/${docName}`);
38+
if (!response.ok) {
39+
throw new Error('Failed to fetch documentation');
40+
}
41+
const content = await response.text();
42+
setFullContent(content);
43+
44+
// Generate AI summary
45+
const aiResponse = await base44.integrations.Core.InvokeLLM({
46+
prompt: `Summarize the following documentation in a concise, structured format. Include:
47+
1. **Purpose** (1-2 sentences)
48+
2. **Key Points** (3-5 bullet points)
49+
3. **Target Audience** (who should read this)
50+
4. **Quick Takeaways** (2-3 actionable insights)
51+
52+
Keep the summary under 200 words and make it scannable.
53+
54+
Documentation Content:
55+
${content}`,
56+
response_json_schema: {
57+
type: 'object',
58+
properties: {
59+
purpose: { type: 'string' },
60+
key_points: { type: 'array', items: { type: 'string' } },
61+
target_audience: { type: 'string' },
62+
quick_takeaways: { type: 'array', items: { type: 'string' } },
63+
estimated_read_time: { type: 'string' }
64+
}
65+
}
66+
});
67+
68+
return aiResponse;
69+
},
70+
onSuccess: (data) => {
71+
setSummary(data);
72+
toast.success('Summary generated!');
73+
},
74+
onError: (error) => {
75+
toast.error('Failed to generate summary: ' + error.message);
76+
}
77+
});
78+
79+
const handleCopy = (text) => {
80+
navigator.clipboard.writeText(text);
81+
setCopied(true);
82+
toast.success('Copied to clipboard');
83+
setTimeout(() => setCopied(false), 2000);
84+
};
85+
86+
const selectedDocInfo = AVAILABLE_DOCS.find(doc => doc.value === selectedDoc);
87+
88+
return (
89+
<div className="space-y-6">
90+
<Card className="border-purple-200 bg-gradient-to-br from-purple-50 to-blue-50">
91+
<CardHeader>
92+
<CardTitle className="flex items-center gap-2">
93+
<Sparkles className="h-6 w-6 text-purple-600" />
94+
AI Documentation Summarizer
95+
</CardTitle>
96+
<CardDescription>
97+
Get concise, AI-generated overviews of lengthy documentation
98+
</CardDescription>
99+
</CardHeader>
100+
<CardContent className="space-y-4">
101+
<div className="flex gap-3">
102+
<Select value={selectedDoc} onValueChange={setSelectedDoc}>
103+
<SelectTrigger className="flex-1">
104+
<SelectValue placeholder="Select a document to summarize..." />
105+
</SelectTrigger>
106+
<SelectContent>
107+
{['Technical', 'Product', 'Admin', 'Operations', 'Getting Started'].map(category => (
108+
<React.Fragment key={category}>
109+
<div className="px-2 py-1.5 text-xs font-semibold text-slate-500">
110+
{category}
111+
</div>
112+
{AVAILABLE_DOCS
113+
.filter(doc => doc.category === category)
114+
.map(doc => (
115+
<SelectItem key={doc.value} value={doc.value}>
116+
{doc.label}
117+
</SelectItem>
118+
))}
119+
</React.Fragment>
120+
))}
121+
</SelectContent>
122+
</Select>
123+
124+
<Button
125+
onClick={() => summarizeMutation.mutate(selectedDoc)}
126+
disabled={!selectedDoc || summarizeMutation.isPending}
127+
className="bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700"
128+
>
129+
{summarizeMutation.isPending ? (
130+
<>
131+
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
132+
Summarizing...
133+
</>
134+
) : (
135+
<>
136+
<Sparkles className="h-4 w-4 mr-2" />
137+
Summarize
138+
</>
139+
)}
140+
</Button>
141+
</div>
142+
143+
{selectedDocInfo && (
144+
<div className="flex gap-2">
145+
<Badge variant="outline">{selectedDocInfo.category}</Badge>
146+
<Badge variant="outline">
147+
<FileText className="h-3 w-3 mr-1" />
148+
{selectedDocInfo.value}
149+
</Badge>
150+
</div>
151+
)}
152+
</CardContent>
153+
</Card>
154+
155+
{summary && (
156+
<Card>
157+
<CardHeader>
158+
<div className="flex items-start justify-between">
159+
<div>
160+
<CardTitle className="text-lg">
161+
Summary: {selectedDocInfo?.label}
162+
</CardTitle>
163+
{summary.estimated_read_time && (
164+
<CardDescription>
165+
Full doc read time: {summary.estimated_read_time}
166+
</CardDescription>
167+
)}
168+
</div>
169+
<Button
170+
variant="ghost"
171+
size="sm"
172+
onClick={() => handleCopy(JSON.stringify(summary, null, 2))}
173+
>
174+
{copied ? (
175+
<Check className="h-4 w-4 text-green-600" />
176+
) : (
177+
<Copy className="h-4 w-4" />
178+
)}
179+
</Button>
180+
</div>
181+
</CardHeader>
182+
<CardContent className="space-y-4">
183+
{/* Purpose */}
184+
<div>
185+
<h3 className="text-sm font-semibold text-slate-700 mb-2">📋 Purpose</h3>
186+
<p className="text-sm text-slate-600 leading-relaxed">{summary.purpose}</p>
187+
</div>
188+
189+
{/* Key Points */}
190+
<div>
191+
<h3 className="text-sm font-semibold text-slate-700 mb-2">🔑 Key Points</h3>
192+
<ul className="space-y-1.5">
193+
{summary.key_points?.map((point, idx) => (
194+
<li key={idx} className="text-sm text-slate-600 flex items-start gap-2">
195+
<span className="text-purple-600 mt-1"></span>
196+
<span>{point}</span>
197+
</li>
198+
))}
199+
</ul>
200+
</div>
201+
202+
{/* Target Audience */}
203+
<div>
204+
<h3 className="text-sm font-semibold text-slate-700 mb-2">👥 Target Audience</h3>
205+
<p className="text-sm text-slate-600">{summary.target_audience}</p>
206+
</div>
207+
208+
{/* Quick Takeaways */}
209+
<div>
210+
<h3 className="text-sm font-semibold text-slate-700 mb-2">💡 Quick Takeaways</h3>
211+
<div className="space-y-2">
212+
{summary.quick_takeaways?.map((takeaway, idx) => (
213+
<div key={idx} className="bg-purple-50 border border-purple-200 rounded-lg p-3">
214+
<p className="text-sm text-purple-900">{takeaway}</p>
215+
</div>
216+
))}
217+
</div>
218+
</div>
219+
220+
{/* Toggle Full Content */}
221+
{fullContent && (
222+
<div className="pt-4 border-t">
223+
<Button
224+
variant="outline"
225+
onClick={() => setShowFull(!showFull)}
226+
className="w-full"
227+
>
228+
{showFull ? (
229+
<>
230+
<ChevronUp className="h-4 w-4 mr-2" />
231+
Hide Full Documentation
232+
</>
233+
) : (
234+
<>
235+
<ChevronDown className="h-4 w-4 mr-2" />
236+
Show Full Documentation
237+
</>
238+
)}
239+
</Button>
240+
241+
{showFull && (
242+
<div className="mt-4 p-4 bg-slate-50 rounded-lg border border-slate-200 max-h-[600px] overflow-y-auto">
243+
<ReactMarkdown className="prose prose-sm max-w-none">
244+
{fullContent}
245+
</ReactMarkdown>
246+
</div>
247+
)}
248+
</div>
249+
)}
250+
</CardContent>
251+
</Card>
252+
)}
253+
254+
{!summary && !summarizeMutation.isPending && (
255+
<Card className="border-dashed">
256+
<CardContent className="py-12 text-center">
257+
<FileText className="h-12 w-12 text-slate-300 mx-auto mb-3" />
258+
<p className="text-sm text-slate-500">
259+
Select a document and click "Summarize" to generate an AI-powered overview
260+
</p>
261+
</CardContent>
262+
</Card>
263+
)}
264+
</div>
265+
);
266+
}

0 commit comments

Comments
 (0)