Implementation Plan
Plugin Selection
The AISummary plugin is an ideal choice for implementing AI summaries in Typecho blogs, offering the following advantages:
- Supports integration with multiple AI platforms (including free platforms like Alibaba Qwen, Gemini, etc.)
- Can generate summaries for all articles with one click, or update them individually
- Provides custom styles and display methods, with strong adaptability
Implementation Steps
1. Install the AISummary Plugin
- Download the AISummary plugin from Github
- Upload the plugin folder to Typecho's
/usr/plugins/directory - Navigate to Typecho backend → Plugins → Enable AISummary plugin
2. Configure the Plugin and API Interface
Open the AISummary plugin settings page and fill in the following configurations:

Basic Settings
- Model Name:
gemini-2.5-flash(Google free model) - API KEY: Your Gemini API key
- API Address: Refer to the next article for details on setting up a Gemini proxy in China (Domestic proxy for Gemini access)
Prompt:
Your task is to generate a summary of the article. Please generate a summary within 150 characters based on the following article content. Do not output any other irrelevant content besides the generated summary.Maximum summary length:
150(It is recommended to set this slightly larger than the number of characters requested in the prompt)
Display Settings
- Replace Default Summary: Select as needed ( "Replace" is recommended)
- Update Summary on Article Modification: Select as needed (choose "Enable" for automatic updates)
- Content Summary Display Style: Select "Use Custom Style"
- Storage Field Name: Keep the default
summary
3. Custom Style Settings
The plugin provides style customization features, perfectly adapting to most themes. Fill in the following code in the "Custom Style" text box:
[hide]
```html ``` /* Responsive adjustments */ @media (max-width: 768px) { .aisummary { padding: 10px; margin: 20px 0 25px; } .ai-header { font-size: 16px !important; } .ai-header svg { width: 22px; height: 22px; margin-right: 6px; } .ai-text-container { font-size: 14px; padding: 10px 12px; line-height: 1.65; } .ai-footer { font-size: 12px !important; margin-top: 8px !important; } } /* Dark mode adaptation */ [data-night="night"] .aisummary, .dark-mode .aisummary, body.dark .aisummary, body.night .aisummary, .night .aisummary, .night-mode .aisummary, html.night .aisummary, .theme-dark .aisummary { background: #2c2c2e; border-color: #38383a; color: #d1d1d1; box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.15); } [data-night="night"] .ai-text-container, .dark-mode .ai-text-container, body.dark .ai-text-container, body.night .ai-text-container, .night .ai-text-container, .night-mode .ai-text-container, html.night .ai-text-container, .theme-dark .ai-text-container { background: #333333; border-color: #4a4a4a; color: #c8c8c8; } [data-night="night"] .ai-header, .dark-mode .ai-header, body.dark .ai-header, body.night .ai-header, .night .ai-header, .night-mode .ai-header, html.night .ai-header, .theme-dark .ai-header { color: #7c89f1 !important; } [data-night="night"] .ai-cursor, .dark-mode .ai-cursor, body.dark .ai-cursor, body.night .ai-cursor, .night .ai-cursor, .night-mode .ai-cursor, html.night .ai-cursor, .theme-dark .ai-cursor { background-color: #7c89f1; } [data-night="night"] .ai-footer, .dark-mode .ai-footer, body.dark .ai-footer, body.night .ai-footer, .night .ai-footer, .night-mode .ai-footer, html.night .ai-footer, .theme-dark .ai-footer { color: rgba(200, 200, 200, 0.6) !important; } /* Manually added dark mode class */ .aisummary.ai-dark-theme { background: #2c2c2e; border-color: #38383a; color: #d1d1d1; box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.15); } ```css .ai-dark-theme .ai-text-container { background: #333333; border-color: #4a4a4a; color: #c8c8c8; } .ai-dark-theme .ai-header { color: #7c89f1 !important; } .ai-dark-theme .ai-cursor { background-color: #7c89f1; } .ai-dark-theme .ai-footer { color: rgba(200, 200, 200, 0.6) !important; } ``` ```html // Core logic for typewriter effect function executeAiSummaryTyping() { const typewriterElement = document.querySelector('.ai-typewriter-text'); const sourceTextElement = document.querySelector('.ai-hidden-text'); const typingSpeed = 50; // Typing speed, smaller value means faster if (!typewriterElement || !sourceTextElement) return; if (aiSummaryTypingTimeoutId) { clearTimeout(aiSummaryTypingTimeoutId); } let textToType = sourceTextElement.textContent.trim(); if (textToType.length > 0) { textToType = ' ' + textToType; // First line indentation } typewriterElement.textContent = ''; let charIndex = 0; function typeNextCharacter() { if (charIndex < textToType.length) { typewriterElement.textContent += textToType.charAt(charIndex); charIndex++; aiSummaryTypingTimeoutId = setTimeout(typeNextCharacter, typingSpeed); } else { aiSummaryTypingTimeoutId = null; } } typeNextCharacter(); } // Execute after page loads document.addEventListener('DOMContentLoaded', function() { setTimeout(() => { executeAiSummaryTyping(); detectAndSyncTheme(); }, 300); }); ``` ```html // PJAX/SPA compatibility handling setInterval(function() { if (window.location.href !== aiSummaryLastProcessedUrl) { aiSummaryLastProcessedUrl = window.location.href; setTimeout(() => { executeAiSummaryTyping(); detectAndSyncTheme(); }, 1000); } }, 100); // Listen for theme switching const observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.attributeName === 'class' || mutation.attributeName === 'data-night') { detectAndSyncTheme(); } }); }); // Start observing class changes on document and body elements document.addEventListener('DOMContentLoaded', function() { observer.observe(document.documentElement, { attributes: true }); observer.observe(document.body, { attributes: true }); }); // Compatibility for Handsome theme's night mode switching event document.addEventListener('DOMContentLoaded', function() { // Attempt to find night mode toggle buttons and listen for click events const nightModeButtons = document.querySelectorAll('[data-toggle-theme], .theme-toggle, #nightmode, .night-mode-btn'); if (nightModeButtons.length > 0) { nightModeButtons.forEach(button => { button.addEventListener('click', function() { // Delay detection to ensure theme switching is complete setTimeout(detectAndSyncTheme, 100); }); }); } }); // If a global theme switching function exists, intercept it to sync the state if (typeof window.switchNightMode === 'function') { const originalSwitchNightMode = window.switchNightMode; window.switchNightMode = function() { originalSwitchNightMode.apply(this, arguments); setTimeout(detectAndSyncTheme, 100); }; } ```[/hide]
4. Set up HTML Template
Enter the following HTML code in the "Fixed text before and after the main text summary" text box:
[hide]
<p class="ai-header">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M3 10a4 4 0 0 1 4 -4h10a4 4 0 0 1 4 4v6a4 4 0 0 1 -4 4h-10a4 4 0 0 1 -4 -4v-6z" ></path>
<path d="M8 3l2 3" ></path>
<path d="M16 3l-2 3" ></path>
<path d="M9 13v-2" ></path>
<path d="M15 11v2" ></path>
</svg>AI Summary
</p>
<div class="ai-text-container">
<div class="ai-hidden-text">{{text}}</div>
<div class="ai-typewriter-text"></div>
<span class="ai-cursor"></span>
</div>
<p class="ai-footer">
This content is generated based on the article and is for explanation and summary purposes only.
</p>[/hide]
5. Generate Summary
After configuration, you can manually generate summaries in bulk in the management section:

You can also add the character summary to the publishing page, and it will be automatically generated upon publishing.
[collapse status="false" title="handsome loading solution"]
Use style
<!-- AI Summary Styles - Handsome Theme Optimized Version -->
<style>
/* Summary Container Styles */
.aisummary {
background: #f7f7f9;
border-radius: 12px;
padding: 12px;
box-shadow: 0 8px 16px -4px rgba(44, 45, 48, 0.047);
border: 1px solid #e3e8f7;
margin: 25px 0 30px;
color: #333;
position: relative;
overflow: hidden;
}
/* Title Styles */
.ai-header {
margin-bottom: 10px !important;
color: #465CEB !important;
text-align: left !important;
display: flex !important;
align-items: center !important;
text-indent: 0 !important;
font-weight: bold !important;
font-size: 17px !important;
}
.ai-header svg {
margin-right: 8px;
width: 24px;
height: 24px;
stroke: currentColor;
}
/* Text Container Styles */
.ai-text-container {
background: #fff;
border-radius: 8px;
padding: 12px 15px;
border: 1px solid #e3e8f7;
margin-bottom: 10px;
font-size: 15px;
line-height: 1.7;
color: #333;
}
.ai-hidden-text {
display: none;
}
.ai-typewriter-text {
display: inline;
text-indent: 2em;
word-wrap: break-word;
white-space: pre-wrap;
}
/* Cursor Styles and Animation */
.ai-cursor {
display: inline-block;
width: 2px;
height: 1em;
background-color: #465CEB;
margin-left: 3px;
animation: ai-blink 0.7s infinite;
vertical-align: middle;
}
@keyframes ai-blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
/* Footer Styles */
.ai-footer {
font-size: 13px !important;
color: rgba(60, 60, 67, 0.65) !important;
font-style: italic !important;
margin-bottom: 0 !important;
padding: 0 5px !important;
text-align: left !important;
text-indent: 0 !important;
margin-top: 10px !important;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.aisummary {
padding: 10px;
margin: 20px 0 25px;
}
.ai-header {
font-size: 16px !important;
}
.ai-header svg {
width: 22px;
height: 22px;
margin-right: 6px;
}
.ai-text-container {
font-size: 14px;
padding: 10px 12px;
line-height: 1.65;
}
.ai-footer {
font-size: 12px !important;
margin-top: 8px !important;
}
}
/* Dark mode adaptation */
[data-night="night"] .aisummary,
.dark-mode .aisummary,
body.dark .aisummary,
body.night .aisummary,
.night .aisummary,
.night-mode .aisummary,
html.night .aisummary,
.theme-dark .aisummary {
background: #2c2c2e;
border-color: #38383a;
color: #d1d1d1;
box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.15);
}
[data-night="night"] .ai-text-container,
.dark-mode .ai-text-container,
body.dark .ai-text-container,
body.night .ai-text-container,
.night .ai-text-container,
.night-mode .ai-text-container,
html.night .ai-text-container,
.theme-dark .ai-text-container {
background: #333333;
border-color: #4a4a4a;
color: #c8c8c8;
}
[data-night="night"] .ai-header,
.dark-mode .ai-header,
body.dark .ai-header,
body.night .ai-header,
.night .ai-header,
.night-mode .ai-header,
html.night .ai-header,
.theme-dark .ai-header {
color: #7c89f1 !important;
}
[data-night="night"] .ai-cursor,
.dark-mode .ai-cursor,
body.dark .ai-cursor,
body.night .ai-cursor,
.night .ai-cursor,
.night-mode .ai-cursor,
html.night .ai-cursor,
.theme-dark .ai-cursor {
background-color: #7c89f1;
}
[data-night="night"] .ai-footer,
.dark-mode .ai-footer,
body.dark .ai-footer,
body.night .ai-footer,
.night .ai-footer,
.night-mode .ai-footer,
html.night .ai-footer,
.theme-dark .ai-footer {
color: rgba(200, 200, 200, 0.6) !important;
}
/* Manually added dark mode class */
.aisummary.ai-dark-theme {
background: #2c2c2e;
border-color: #38383a;
color: #d1d1d1;
box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.15);
}
.ai-dark-theme .ai-text-container {
background: #333333;
border-color: #4a4a4a;
color: #c8c8c8;
}
.ai-dark-theme .ai-header {
color: #7c89f1 !important;
}
.ai-dark-theme .ai-cursor {
background-color: #7c89f1;
}
.ai-dark-theme .ai-footer {
color: rgba(200, 200, 200, 0.6) !important;
}
</style>
<!-- AI Summary Typing Effect Script -->
<script>
// Global variables
let aiSummaryTypingTimeoutId = null;
let aiSummaryLastProcessedUrl = window.location.href;
// AI Summary Theme Setting Function
window.aiSummaryUser = {
setAiSummaryTheme: function(theme) {
const summaryElements = document.querySelectorAll('.aisummary');
if (summaryElements.length > 0) {
summaryElements.forEach(element => {
if (theme === 'dark') {
element.classList.add('ai-dark-theme');
} else {
element.classList.remove('ai-dark-theme');
}
});
}
},
detectAndSyncTheme: function() {
// Check for common dark mode indicators
const isDarkMode =
document.body.classList.contains('night') ||
document.body.classList.contains('dark') ||
document.documentElement.classList.contains('night') ||
document.documentElement.getAttribute('data-night') === 'night' ||
document.querySelector('html').classList.contains('dark-mode') ||
document.querySelector('[data-theme="dark"]') !== null;
// Apply the corresponding theme
if (isDarkMode) {
this.setAiSummaryTheme('dark');
} else {
this.setAiSummaryTheme('light');
}
},
executeAiSummaryTyping: function() {
const typewriterElement = document.querySelector('.ai-typewriter-text');
const sourceTextElement = document.querySelector('.ai-hidden-text');
const typingSpeed = 50; // Typing speed, smaller value means faster
if (!typewriterElement || !sourceTextElement) return;
if (aiSummaryTypingTimeoutId) {
clearTimeout(aiSummaryTypingTimeoutId);
}
```javascript
let textToType = sourceTextElement.textContent.trim();
if (textToType.length > 0) {
textToType = ' ' + textToType; // First line indent
}
typewriterElement.textContent = '';
let charIndex = 0;
function typeNextCharacter() {
if (charIndex < textToType.length) {
typewriterElement.textContent += textToType.charAt(charIndex);
charIndex++;
aiSummaryTypingTimeoutId = setTimeout(typeNextCharacter, typingSpeed);
} else {
aiSummaryTypingTimeoutId = null;
}
}
typeNextCharacter();
}
};
```
```html
// Execute after the page loads
document.addEventListener('DOMContentLoaded', function() {
setTimeout(() => {
window.aiSummaryUser.executeAiSummaryTyping();
window.aiSummaryUser.detectAndSyncTheme();
}, 300);
});
// Listen for theme switching
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === 'class' || mutation.attributeName === 'data-night') {
window.aiSummaryUser.detectAndSyncTheme();
}
});
});
// Start observing class changes on document and body elements
document.addEventListener('DOMContentLoaded', function() {
observer.observe(document.documentElement, { attributes: true });
observer.observe(document.body, { attributes: true });
});
// Compatibility for Handsome theme's night mode switching event
document.addEventListener('DOMContentLoaded', function() {
// Try to find night mode switching buttons and listen for click events
const nightModeButtons = document.querySelectorAll('[data-toggle-theme], .theme-toggle, #nightmode, .night-mode-btn');
if (nightModeButtons.length > 0) {
nightModeButtons.forEach(button => {
button.addEventListener('click', function() {
// Delay detection to ensure theme switching is complete
setTimeout(window.aiSummaryUser.detectAndSyncTheme, 100);
});
});
}
});
// If a global theme switching function exists, intercept it to sync the state
if (typeof window.switchNightMode === 'function') {
const originalSwitchNightMode = window.switchNightMode;
window.switchNightMode = function() {
originalSwitchNightMode.apply(this, arguments);
setTimeout(window.aiSummaryUser.detectAndSyncTheme, 100);
};
}
```
[/collapse]
Frontend Vditor Parsing Article Page Does Not Display AI Summary
[collapse status="false" title="Solution"]
1. Open the file: usr/themes/handsome/libs/content/PostContent.php
2. Find line 382 (approximately between lines 380-385)
3. Change $content = $obj->text; to $content = $obj->content;
4. Save the file
$obj->textis the original Markdown text from Vditor, unprocessed by any plugins.$obj->contentis the HTML content processed by the Typecho plugin system, including the summary added by the AISummary plugin'scustomContentmethod.
By using$obj->content, you ensure that all plugin hooks work correctly.
[/collapse]
Summary
With the AISummary plugin, you can easily add intelligently generated summaries to your Typecho blog posts.
If you have any questions or suggestions, feel free to leave a comment below.