Generating LinkedIn Posts
Relevant source files
The following files were used as context for generating this wiki page:
The "Generating LinkedIn Posts" feature is a core component of the Smart Board Analysis functionality. It automatically transforms the transcript of a YouTube video into a detailed, professional summary optimized for engagement on LinkedIn. This process leverages the Google Gemini API to interpret the transcript and structure the output into a specific JSON format, which is then rendered in the application's UI.
This feature is designed to help users quickly repurpose long-form video content into actionable intelligence and social media assets, turning a video into a polished LinkedIn post with a single workflow.
Sources: README.md, services/geminiService.ts
Architecture and Data Flow
The generation of a LinkedIn post is initiated automatically after a video's transcript has been successfully fetched. The process involves several components, from the main application view to the AI service and finally to the UI board where the content is displayed.
The overall flow can be visualized as follows:
This diagram shows the end-to-end process, starting from the App component loading a transcript, triggering the useContentGenerator hook, which in turn calls the geminiService to interact with the Gemini API. The resulting LinkedInPost object is then passed back to the SmartBoard component for rendering.
Sources: App.tsx:41-47, hooks/useContentGenerator.ts:98-101, 126-131, services/geminiService.ts:221-229
Key Functions
The process relies on a chain of functions across different modules:
| Function | File | Description |
|---|---|---|
generateAll | hooks/useContentGenerator.ts | Orchestrates the parallel generation of all content types, including the LinkedIn post. |
generateLinkedInPost | services/geminiService.ts | Prepares and initiates the AI generation specifically for a LinkedIn post, providing the correct prompt. |
generateAIContent | services/geminiService.ts | A generic function that handles the API call to Google Gemini, including error handling and JSON parsing. |
Sources: hooks/useContentGenerator.ts:98, services/geminiService.ts:153, 221
AI Generation and Prompting
The core of the feature lies in the geminiService.ts module, which communicates with the Google Gemini API.
AI Prompt
A specific system instruction, LINKEDIN_INSTRUCTION, is sent to the Gemini model. This prompt guides the AI to act as a "professional LinkedIn thought leader" and to return the output in a strict JSON format.
const LINKEDIN_INSTRUCTION = `
You are a professional LinkedIn thought leader. Convert this video transcript into a compelling LinkedIn post.
Output EXACTLY in this JSON format (no markdown, no code blocks):
{"hook":"[Attention-grabbing first line]","body":"[3-4 paragraphs of value]","cta":"[Call to action]","hashtags":["tag1","tag2","tag3"]}
Rules:
- Hook: Bold statement or question (under 100 chars)
- Body: Professional tone, insights, lessons learned
- CTA: Encourage engagement
- Hashtags: 3-5 relevant tags
`;
Sources: services/geminiService.ts:198-210
API Interaction
The generateLinkedInPost function calls the generic generateAIContent helper, which constructs and sends the request to the gemini-2.0-flash model. The interaction is designed to be robust, with a fallback value provided in case the API call fails or returns an invalid response.
The sequence of operations is as follows:
This diagram illustrates how the useContentGenerator hook triggers a chain of function calls, culminating in an API request to Google Gemini and the subsequent parsing of the JSON response into a structured LinkedInPost object.
Sources: services/geminiService.ts:153-196, 221-229, hooks/useContentGenerator.ts:126-131
Data Structure
The generated content for a LinkedIn post is strictly typed using the LinkedInPost interface. This ensures consistency between the AI output and the data consumed by the frontend components.
// From types.ts
export interface LinkedInPost {
hook: string;
body: string;
cta: string;
hashtags: string[];
}
Sources: types.ts:28-33
The fields of this interface are defined as follows:
| Field | Type | Description |
|---|---|---|
hook | string | An attention-grabbing first line or question (under 100 characters). |
body | string | The main content of the post, written in a professional tone. |
cta | string | A call to action to encourage engagement from readers. |
hashtags | string[] | An array of 3-5 relevant hashtags. |
Sources: types.ts:28-33, services/geminiService.ts:204-208
UI Rendering in SmartBoard
The SmartBoard.tsx component is responsible for displaying the generated LinkedIn post. It features a dedicated "LinkedIn" tab that becomes active once the content is available.
Component Breakdown
- TabButton: A button in the header of the
SmartBoardto switch to the LinkedIn view. It shows a loading spinner or a checkmark based on the generation progress. - Content Area: When the LinkedIn tab is active, this area renders the
hook,body,cta, andhashtagsfrom thecontent.linkedInPostobject. - CopyButton: A utility component to copy individual parts of the post (e.g., the hook) to the clipboard.
- Copy Full Post: A main action button that formats the entire post into a single string and copies it to the clipboard.
The rendering logic for the LinkedIn post is contained within the SmartBoard component:
// from components/SmartBoard.tsx
{activeTab === 'linkedin' && (
<div className="space-y-4">
{progress.linkedin === 'loading' && (
/* ... loading spinner ... */
)}
{content?.linkedInPost && (
<>
<div className="p-4 bg-white/5 border border-white/10 rounded-xl space-y-3">
<div className="flex items-start justify-between">
<p className="text-lg font-bold text-white">{content.linkedInPost.hook}</p>
<CopyButton text={content.linkedInPost.hook} field="linkedin-hook" />
</div>
<p className="text-gray-300 text-sm whitespace-pre-wrap leading-relaxed">{content.linkedInPost.body}</p>
<p className="text-blue-400 font-medium text-sm">{content.linkedInPost.cta}</p>
<div className="flex flex-wrap gap-2 pt-2">
{content.linkedInPost.hashtags.map((tag, i) => (
<span key={i} className="text-xs text-blue-400 bg-blue-500/10 px-2 py-1 rounded-full">#{tag}</span>
))}
</div>
</div>
<button
onClick={() => handleCopy(
`${content.linkedInPost!.hook}\n\n${content.linkedInPost!.body}\n\n${content.linkedInPost!.cta}\n\n${content.linkedInPost!.hashtags.map(t => `#${t}`).join(' ')}`,
'linkedin-full'
)}
/* ... button styles and content ... */
>
<Linkedin className="w-4 h-4" />
Copy Full Post
</button>
</>
)}
</div>
)}
Sources: components/SmartBoard.tsx:114, 192-228
Summary
The LinkedIn post generation feature is a powerful tool within the Nota application that exemplifies the project's goal of turning long-form video into "actionable intelligence." By combining a well-defined AI prompt, a robust service layer, and a clear UI, it provides users with a seamless way to create professional social media content directly from a YouTube video transcript. The entire process is automated, asynchronous, and integrated directly into the user's workflow.
Sources: README.md, hooks/useContentGenerator.ts, services/geminiService.ts