作者: Jet L

  • 【小贴士】WordPress主题更新的问题

    我的网站一般通过functions.php文件来加载特定的JS代码或CSS,这样虽然有一定的灵活性,但是WordPress主题文件更新时,其会将用户上传到主题文件夹的代码删除,也会重置functions.php文件,不过不用太担心,这个操作在你点击更新之前会进行提示而非全自动就给你覆盖掉了。

    因此必须定期备份修改过的文件,此外也可以考虑采用子主题——Child Theme,这个操作可以参考WordPress的子主题介绍来进行。

    其中对于如何上传自主题、如何修改functions.php,都有较为详细的解释。

  • 【Ai】在Windows系统本地部署DeepSeek-R1的极简步骤

    惊闻B站有人出售百元本地部署教程,NND给我看笑了,什么都能卖钱是吧,当然不排除人家手把手教,提供足够的情绪价值。

    但是如果你不想花钱,同时想提升一下英文水平和计算机熟练度,请跟着官方文档一步步进行,目前的文档已经相当详细且可行。

    我们如果在Windows上进行部署和调试,推荐使用Open WebUi+Ollama的方式进行部署。

    PS:其实更建议在Linux上进行部署,一键部署更加便利~

    1、选择后端Ollama

    在Ollama官网选择Win版本下载,会自动部署相关环境,在CMD或者中powershell可以按照对应的模型拉取到本地。

    请根据自己的硬件量力而行。我的显卡为RTX3070 8G,按照ollama默认设置,运行7B已经亚历山大。

    2、选择前端Open-WebUi

    请根据您的系统,在Open-WebUi的官方文档,按照步骤,一步步来进行部署。

    Win版本下按照官方建议,可以使用uv,在powershell中进行拉取和部署,其中对网络环境有一定要求。

    3、启动Open-WebUi后的注意事项

    Open-WebUi原版毕竟是国外软件,在国内这个环境启动还是有一点网络困扰的,尤其是有些文件是通过Github的地址获取的,请对自己的网络环境做出一些针对性的优化调整。

    另外完成本地部署后,如果是启动在127.0.0.1上,那么检查ollama的端口是否running,一般按照官方部署都可以进行顺畅进行(只有国内这个网不太顺畅)

    此外Open-WebUi默认检查OpenAi的API,这个选项可以在首次登陆后去管理员面板关闭,这样不会每次启动都遇到拉取模型缓慢、超时的情况。

    4、其他分享

    我的电脑采用13700K 32G DDR5 RTX3070 8G,但大模型运行需要大显存,8G显存只能算起步,参数量只能流畅运行7B左右的模型,因此一般的家用和办公电脑跑大模型都存在很大的限制。

    RTX3070 8G跑DeepSeek-R1:7B的速度——显存爆满,ollama默认设置,显示CPU处理占用10%,GPU处理占用90%,常规问答的response token/s在39左右 ,prompt_token/s在2500左右。但是大模型性能存在一定的短板,长上下文效果不尽如人意。

    RTX3070 8G跑DeepSeek-R1:14B,ollama默认设置命令行中速度可以接受,在WebUi中短回答response token/s约为14,较长的上下文降低到7不到,一半跑在GPU一半跑在CPU,长文本效果很差。

    RTX3070 8G跑DeepSeek-R1:32B,ollama默认设置在命令行中速度还行,缓慢但可以简单对话,处理长文本速度基本不可用。若用13700K跑在CPU则32G内容跑满,速度也是非常慢。

    在跑完Ai测试后,请关闭Ollama的进程,否则你将面临满占用的显存或内存~

    5、体验

    搭配Open-WebUi可以实现本地部署,多端使用,但是对体验影响更大的限制——模型本身——我们个人、及小公司的计算性能均没法有效支撑,本来大模型就是为了提升效率,本地部署一个跑的死慢的模型,对效率的提升实在是存疑。

    当然我鼓励大家都去本地部署体验一下,从中也可以获得一些乐趣,但是如果到实际应用层面,大一些的模型硬件需求激增,小公司玩这个自建后端的硬件成本还是太高了。

    因此,对小公司而言,可能选择一个大树,使用API,保护好自己的数据(真的是有价值的数据吗?)进行针对性的训练,拓展自己的RAG系统,做好本地化的情况下拥抱云计算,才是提升小公司效率的一条路吧。

    但话说回来,小公司真的愿意为这个人工和软件成本付费吗?

  • 【Python】提取视频画面并生成PPT

    比较笨的方法,用来提取PPT课程视频画面,并生成对应的PPT,代码检测黑屏但没有检测白屏,没有检测重复画面(因为有些人讲课会来回翻PPT),因此还有优化空间。内存占用会逐渐增多,不过测试没有出现崩溃的情况。

    PS:做完发现可以直接问讲课人要PPT原件,我,,,

    import cv2
    import os
    import numpy as np
    from pptx import Presentation
    from pptx.util import Inches
    from skimage.metrics import structural_similarity as ssim
    import tkinter as tk
    from tkinter import filedialog, messagebox
    
    # 选择视频和输出目录
    def select_video_and_output():
        video_path = filedialog.askopenfilename(title="选择视频文件", filetypes=[("MP4 files", "*.mp4")])
        if not video_path:
            messagebox.showwarning("选择视频", "未选择视频文件")
            return None, None
        
        output_dir = filedialog.askdirectory(title="选择输出目录")
        if not output_dir:
            messagebox.showwarning("选择输出目录", "未选择输出目录")
            return None, None
    
        pptx_path = os.path.join(output_dir, "output_presentation.pptx")
        return video_path, pptx_path
    
    # 处理视频并生成 PPT
    def process_video_to_ppt(video_path, pptx_path):
        os.makedirs("ppt_images", exist_ok=True)
        
        cap = cv2.VideoCapture(video_path)
        _, prev_frame = cap.read()
        prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
    
        frame_count = 0
        slide_count = 0
        images = []
        similarity_threshold = 0.95  # 提高 SSIM 阈值,减少相似图片
        brightness_threshold = 10  # 黑屏检测(平均亮度 < 10 认为是黑屏)
    
        def process_frame(frame):
            """ 计算 SSIM 相似度,判断是否保存该帧 """
            nonlocal prev_gray, slide_count
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            score = ssim(prev_gray, gray)
    
            # 计算平均亮度,过滤黑屏
            avg_brightness = np.mean(gray)
            if avg_brightness < brightness_threshold:
                return  # 跳过黑屏帧
    
            if score < similarity_threshold:  
                img_path = os.path.join("ppt_images", f"slide_{slide_count}.jpg")
    
                # 确保不同的幻灯片才保存
                if len(images) == 0 or images[-1] != img_path:  
                    cv2.imwrite(img_path, frame)
                    images.append(img_path)
                    slide_count += 1
                    prev_gray = gray  # 只在确认变化时更新参考帧
    
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
    
            # 仅每隔 15 帧处理一次
            if frame_count % 15 == 0:
                process_frame(frame)
    
            frame_count += 1
    
        cap.release()
        # cv2.destroyAllWindows()
    
        # 创建 PPT
        prs = Presentation()
        for img in images:
            slide = prs.slides.add_slide(prs.slide_layouts[5])  # 空白幻灯片
            left, top, width, height = Inches(0), Inches(0), Inches(10), Inches(7.5)
            slide.shapes.add_picture(img, left, top, width, height)
    
        prs.save(pptx_path)
        messagebox.showinfo("完成", f"PPTX 生成完成: {pptx_path}")
    
    # 主函数
    def main():
        root = tk.Tk()
        root.withdraw()  # 隐藏主窗口
        video_path, pptx_path = select_video_and_output()
        if video_path and pptx_path:
            process_video_to_ppt(video_path, pptx_path)
    
    if __name__ == "__main__":
        main()