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

  1. Download the AISummary plugin from Github
  2. Upload the plugin folder to Typecho's /usr/plugins/ directory
  3. 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:

image.png

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)

    image.png

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:

image.png

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->text is the original Markdown text from Vditor, unprocessed by any plugins.
$obj->content is the HTML content processed by the Typecho plugin system, including the summary added by the AISummary plugin's customContent method.
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.

END

本文标题:Typecho添加文章AI摘要功能(Handsome等全主题适配)

本文链接:https://www.imsuk.cn/archives/98/

除非另有说明,本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

声明:转载请注明文章来源。

Last modification:January 31, 2026
请用钱砸我