wangzhibo
2025-07-30 25087cbe79c8c4992551477d55d9db8bbea2202e
auto_media_publisher/modifiers/rewriter/docx_rewriter_gemini.py
@@ -1,7 +1,8 @@
from docx import Document
from docx.shared import Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Pt, Inches
from docx.oxml.ns import qn
from io import BytesIO
from docx.enum.text import WD_ALIGN_PARAGRAPH
import random
import threading
import re
@@ -11,20 +12,23 @@
from io import BytesIO
from PIL import Image
import google.generativeai as genai
from auto_media_publisher.config.conf_base import GOOGLE_API_KEY,GOOGLE_MODEL,GOOGLE_CHAT_MIN_INTERVAL
from auto_media_publisher.config.conf_base import GOOGLE_GEMINI_TEMPERATURE_MIN,GOOGLE_GEMINI_TEMPERATURE_MAX,GOOGLE_REWRITE_STYLE_MAP,GEMINI_PROMPT_INIT_DEFAULT
from auto_media_publisher.config.conf_base import GOOGLE_API_KEY,GOOGLE_MODEL,GOOGLE_CHAT_MIN_INTERVAL,DEFAULT_PREFIX_MAP,DEFAULT_SURFIX_MAP
from auto_media_publisher.config.conf_base import GOOGLE_GEMINI_TEMPERATURE_MIN,GOOGLE_GEMINI_TEMPERATURE_MAX,GOOGLE_GEMINI_TOPN_MIN,GOOGLE_GEMINI_TOPN_MAX,GOOGLE_REWRITE_STYLE_MAP,GEMINI_PROMPT_INIT_DEFAULT
from auto_media_publisher.config.conf_base import GEMINI_PROMPT_TITLE,GEMINI_PROMPT_DESCRIPTION,GEMINI_PROMPT_TAG
from auto_media_publisher.utils.logger import get_logger
from auto_media_publisher.utils.utils_text2image_pollinations import Text2ImageGenerator
class GeminiDocxRewriter:
    def __init__(self,rewrite_style="default" ):
class DocxRewriterGemini:
    def __init__(self,rewrite_style="default" ,docx_author="我"):
        genai.configure(api_key=GOOGLE_API_KEY)
        self.temperature = round(random.uniform(GOOGLE_GEMINI_TEMPERATURE_MIN, GOOGLE_GEMINI_TEMPERATURE_MAX), 2)
        self.top_n = round(random.uniform(GOOGLE_GEMINI_TOPN_MIN, GOOGLE_GEMINI_TOPN_MAX), 2)
        self.model = genai.GenerativeModel(GOOGLE_MODEL,
            generation_config=genai.types.GenerationConfig(
                temperature=self.temperature,
                top_p=1.0
                top_p=self.top_n,
                top_k=random.choice([40, 50, 80, 100])
            )
        )
        if rewrite_style =="random":
@@ -32,11 +36,16 @@
        else:
            self.rewrite_style = rewrite_style
        
        self.prefix_text = f"我是{docx_author},{random.choice(DEFAULT_PREFIX_MAP)}"
        self.surfix_text = random.choice(DEFAULT_SURFIX_MAP)
        self.last_call_time = 0
        self.min_interval = GOOGLE_CHAT_MIN_INTERVAL  # 限制最短请求间隔(秒)
        self.lock = threading.Lock()  # 多线程并发时也安全
        self.logger = get_logger(self.__class__.__name__,"admin")
        self.text2imager = Text2ImageGenerator()
        self.text2imager = Text2ImageGenerator(width=900,height=383)
        self.summary_info = {}
    
    #@retry(stop=stop_after_attempt(3), wait=wait_fixed(2))  # 自动重试机制
    def safe_send_message(self, content: str):
@@ -59,16 +68,11 @@
            rewritten = self._rewrite_blocks(blocks)
            self._save_to_new_docx(rewritten, output_path)
            
        summary_info = self.summarize_title_intro_keywords()
        print(summary_info)
        self.text2imager.generate_image(summary_info["summary"],output_path.replace(".docx",".jpg"))
        summary_info["cover_image"] = output_path.replace(".docx",".jpg")
        self.summary_info = self._summarize_title_intro_keywords()
        print(self.summary_info)
        self.text2imager.generate_image(self.summary_info["description"],output_path.replace(".docx",".png"))
        self.summary_info["path_cover"] = output_path.replace(".docx",".png")
        # 3. 写入磁盘
        with open(output_path.replace(".docx",".json"), "w", encoding="utf-8") as f:
            json.dump(summary_info, f, ensure_ascii=False, indent=4)
        return summary_info
    
    def extract_docx_blocks_by_order(self,docx_path):
        doc = Document(docx_path)
@@ -146,28 +150,53 @@
    def _save_to_new_docx(self, blocks, output_path):
        doc = Document()
        # 设置默认样式
        style = doc.styles['Normal']
        font = style.font
        font.name = '楷体'  # 西文字体设置为楷体
        font.size = Pt(10.5)  # 小四字体
        style._element.rPr.rFonts.set(qn('w:eastAsia'), '楷体')  # 中文字体设定
        # 前言
        para = doc.add_paragraph(self.prefix_text)
        para.paragraph_format.line_spacing = 1.5
        para.paragraph_format.space_before = Pt(0)
        para.paragraph_format.space_after = Pt(0)
        for block in blocks:
            if block["type"]=="text":
            if block["type"] == "text":
                for line in block["content"].split("\n"):
                    doc.add_paragraph(line.strip())
                    para = doc.add_paragraph(line.strip())
                    para.paragraph_format.line_spacing = 1.5  # 行距1.5倍
                    para.paragraph_format.space_before = Pt(0)  # 段前0磅
                    para.paragraph_format.space_after = Pt(0)   # 段后0磅
            elif block["type"] == "image":
                image_data = block["content"]
                image_stream = BytesIO(image_data)
                paragraph = doc.add_paragraph()
                run = paragraph.add_run()
                run.add_picture(image_stream, width=Inches(5.5))  # 适当调整宽度
                run.add_picture(image_stream, width=Inches(5.5))
                paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
        doc.save(output_path)
        # 结语
        para2 = doc.add_paragraph(self.surfix_text)
        para2.paragraph_format.line_spacing = 1.5
        para2.paragraph_format.space_before = Pt(12)
        para2.paragraph_format.space_after = Pt(0)
    def summarize_title_intro_keywords(self) -> dict:
        doc.save(output_path)
    def _summarize_title_intro_keywords(self) -> dict:
        title = self.safe_send_message(GEMINI_PROMPT_TITLE).text.strip()
        summary = self.safe_send_message(GEMINI_PROMPT_DESCRIPTION).text.strip()
        description = self.safe_send_message(GEMINI_PROMPT_DESCRIPTION).text.strip()
        keywords = self.safe_send_message(GEMINI_PROMPT_TAG).text.strip()
        return {
            "title": title,
            "summary": summary,
            "keywords": re.split(r'[、,\s]+', keywords.strip("。"))
            "title": title.splitlines()[0].strip()[:64],
            "description": description[:120],
            "tags": re.split(r'[、,\s]+', keywords.strip("。"))
        }