找回密码
 立即注册
首页 业界区 业界 使用这个工具,基于代码仓库直接生成教程文档,感觉比我 ...

使用这个工具,基于代码仓库直接生成教程文档,感觉比我自己写的还好

施婉秀 2025-6-5 10:07:38
前言

我比较喜欢写教程,但是纯手写的话,一方面太麻烦了,另一方面就是觉得自己写的不太好,很多时候都喜欢直接贴代码算了。但直接贴代码对有编程基础的人而言可能很有帮助,但是对想入门的小白而言,一上来就是一大堆代码就很容易劝退。
怎么把教程写好,是我一直都在探索的事情。
昨天在GitHub上偶然刷到了一个项目,说是基于代码仓库直接就能生成教程文档,我抱着试一试的心态去尝试了一下,结果确实被惊艳到了,今天就来分享给大家,我也会带大家实践一下。
这个项目叫Tutorial-Codebase-Knowledge。
GitHub地址:https://github.com/The-Pocket/Tutorial-Codebase-Knowledge
1.png

Tutorial-Codebase-Knowledge介绍

这是一个 Pocket Flow 的教程项目,一个仅100行代码的LLM框架。它爬取 GitHub 仓库,并从代码中构建知识库。它分析整个代码库以识别核心抽象及其交互方式,并将复杂的代码转化为带有清晰可视化内容的初学者友好教程。
实践

创建一个python虚拟环境,安装包:
  1. pip install -r requirements.txt
复制代码
需要修改一下call_llm.py:
使用谷歌的模型可以这样写:
  1. def call_llm(prompt, use_cache: bool = True):   
  2.     client = genai.Client(
  3.         api_key=os.getenv("GEMINI_API_KEY", "你的api key"),
  4.     )
  5.     model = os.getenv("GEMINI_MODEL", "gemini-2.5-pro-exp-03-25")
  6.     response = client.models.generate_content(
  7.         model=model,
  8.         contents=[prompt]
  9.     )
  10.     response_text = response.text
  11.     return response_text
复制代码
使用兼容OpenAI格式的模型可以这样写:
  1. # Use OpenAI o1
  2. def call_llm(prompt, use_cache: bool = True):   
  3.     from openai import OpenAI
  4.     client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "你的api key"),
  5.                      base_url="https://api.siliconflow.cn/v1")
  6.      r = client.chat.completions.create(
  7.          model="Qwen/QwQ-32B",
  8.          messages=[{"role": "user", "content": prompt}],
  9.         response_format={
  10.              "type": "text"
  11.          },
  12.         reasoning_effort="medium",
  13.          store=False
  14.      )
  15.      return r.choices[0].message.content
复制代码
使用这个命令用于测试:
  1. python utils/call_llm.py
复制代码
参考README的使用方法:
  1. # Analyze a GitHub repository
  2. python main.py --repo https://github.com/username/repo --include "*.py" "*.js" --exclude "tests/*" --max-size 50000
  3. # Or, analyze a local directory
  4. python main.py --dir /path/to/your/codebase --include "*.py" --exclude "*test*"
  5. # Or, generate a tutorial in Chinese
  6. python main.py --repo https://github.com/username/repo --language "Chinese"
复制代码
--repo 或 --dir - 指定 GitHub 仓库 URL 或本地目录路径(必需,互斥)
-n, --name - 项目名称(可选,如果省略则从 URL/目录派生)
-t, --token - GitHub 令牌(或设置 GITHUB_TOKEN 环境变量)
-o, --output - 输出目录(默认:./output)
-i, --include - 要包含的文件(例如,".py" ".js")
-e, --exclude - 要排除的文件(例如,"tests/" "docs/")
-s, --max-size - 文件最大大小(以字节为单位,默认:100KB)
--language - 生成教程的语言(默认:"english")
正常运行如下图所示:
2.png

会开始分析章节然后开始写章节的内容。
以自己的一个教程仓库为例,我使用了不同的模型创建教程,把生成的教程我上传到GitHub了。
地址:https://github.com/Ming-jiayou/Avalonia_With_Dependency_Injection_Example/tree/main/Tutorials
3.png

在我使用的模型中,我觉得效果最好的是gemini-2.5-pro-exp-03-25。
感兴趣的朋友可以自己看看对比一下。
我现在把gemini-2.5-pro-exp-03-25生成的贴出来看看。
Tutorial: Avalonia_With_Dependency_Injection_Example

本项目 Avalonia_With_Dependency_Injection_Example 是一个使用 Avalonia UI依赖注入 技术构建的示例应用。它展示了如何通过依赖注入管理应用的 组件和服务,并通过 导航服务 实现不同视图之间的切换。通过视图模型与视图的分离设计,项目实现了模块化开发,提高了代码的复用性和可维护性。
Source Repository: https://github.com/Ming-jiayou/Avalonia_With_Dependency_Injection_Example
flowchart TD    A0["主应用程序配置"]    A1["依赖注入"]    A2["导航服务"]    A3["视图模型基类"]    A4["视图定位器"]    A5["主窗口视图模型"]    A6["页面视图模型"]    A7["主窗口视图"]    A8["页面视图"]    A9["应用程序生命周期"]    A0 -- "初始化依赖注入" --> A1    A0 -- "管理生命周期" --> A9    A1 -- "注册视图模型" --> A3    A1 -- "注册视图定位器" --> A4    A1 -- "注册导航服务" --> A2    A2 -- "管理导航" --> A5    A5 -- "使用导航服务" --> A2    A5 -- "切换页面视图模型" --> A6    A4 -- "定位主窗口视图" --> A7    A4 -- "定位页面视图" --> A8    A7 -- "绑定视图模型" --> A5    A8 -- "绑定视图模型" --> A6    A6 -- "管理页面视图" --> A8    A3 -- "继承基类" --> A6    A3 -- "继承基类" --> A5Chapter 1: 主应用程序配置

欢迎初学者!

欢迎来到我们的第一个章节!在这个章节中,我们将学习如何配置和启动Avalonia应用程序。如果你是第一次接触Avalonia或者依赖注入(Dependency Injection, DI),请不要担心,我们将通过具体的例子来一步步引导你。
为什么要配置主应用程序?

在开发任何应用程序时,首先需要做的一件事情就是配置和启动它。在Avalonia中,主应用程序配置类似于一家公司的前台,负责接待访客并引导他们进入正确的房间。在这个例子中,我们的“前台”会做一些必要的初始化工作,比如设置主窗口和初始化依赖注入。这样的配置能确保应用程序能够顺利启动,用户可以使用所有的功能。
具体实现

1. 创建应用程序类

我们从创建应用程序类开始。在Avalonia中,应用程序类继承自Application,并重写一些方法来配置应用程序。我们来看一下App.axaml.cs文件中的代码:
  1. using System.Linq;
  2. using Avalonia;
  3. using Avalonia.Controls.ApplicationLifetimes;
  4. using Avalonia.Data.Core;
  5. using Avalonia.Data.Core.Plugins;
  6. using Avalonia.Markup.Xaml;
  7. using AvaloniaWithDependencyInjection.ViewModels;
  8. using AvaloniaWithDependencyInjection.Views;
  9. using Microsoft.Extensions.DependencyInjection;
  10. namespace AvaloniaWithDependencyInjection
  11. {
  12.     public partial class App : Application
  13.     {
  14.         public override void Initialize()
  15.         {
  16.             AvaloniaXamlLoader.Load(this);
  17.         }
  18.         public override void OnFrameworkInitializationCompleted()
  19.         {
  20.             if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
  21.             {
  22.                 DisableAvaloniaDataAnnotationValidation();
  23.                 var mainWindow = Program.ServiceProvider?.GetRequiredService<MainWindow>();
  24.                 var mainViewModel = Program.ServiceProvider?.GetRequiredService<MainWindowViewModel>();
  25.                 if (mainWindow != null && mainViewModel != null)
  26.                 {
  27.                     mainWindow.DataContext = mainViewModel;
  28.                     desktop.MainWindow = mainWindow;
  29.                 }
  30.             }
  31.             base.OnFrameworkInitializationCompleted();
  32.         }
  33.         private void DisableAvaloniaDataAnnotationValidation()
  34.         {
  35.             var dataValidationPluginsToRemove =
  36.                 BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
  37.             foreach (var plugin in dataValidationPluginsToRemove)
  38.             {
  39.                 BindingPlugins.DataValidators.Remove(plugin);
  40.             }
  41.         }
  42.     }
  43. }
复制代码
代码解释


  • Initialize 方法:

    • AvaloniaXamlLoader.Load(this);:加载XAML资源,初始化用户界面。

  • OnFrameworkInitializationCompleted 方法:

    • ApplicationLifetime:检查应用程序是否在传统的桌面环境中运行。
    • DisableAvaloniaDataAnnotationValidation():禁用Avalonia的数据注释验证,避免与CommunityToolkit重复验证。
    • Program.ServiceProvider.GetRequiredService() 和 Program.ServiceProvider.GetRequiredService():从依赖注入服务中获取主窗口和主窗口视图模型。
    • mainWindow.DataContext = mainViewModel;:将主窗口的 DataContext 设置为主窗口视图模型。
    • desktop.MainWindow = mainWindow;:设置应用程序的主窗口。

  • DisableAvaloniaDataAnnotationValidation 方法:

    • 从数据验证插件中移除Avalonia的数据注释验证插件,避免重复验证。

2. 配置依赖注入

接下来,我们来看看如何配置依赖注入。在Program.cs文件中,我们会创建一个服务集合,并注册所需的依赖项:
  1. using System;
  2. using Avalonia;
  3. using Microsoft.Extensions.DependencyInjection;
  4. namespace AvaloniaWithDependencyInjection
  5. {
  6.     internal sealed class Program
  7.     {
  8.         public static IServiceProvider? ServiceProvider { get; private set; }
  9.         [STAThread]
  10.         public static void Main(string[] args)
  11.         {
  12.             var services = new ServiceCollection();
  13.             
  14.             services.AddViews()
  15.                     .AddViewModels()
  16.                     .AddServices();
  17.             
  18.             ServiceProvider = services.BuildServiceProvider();
  19.             
  20.             BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
  21.         }
  22.         public static AppBuilder BuildAvaloniaApp()
  23.             => AppBuilder.Configure()
  24.                 .UsePlatformDetect()
  25.                 .WithInterFont()
  26.                 .LogToTrace();
  27.     }
  28. }
复制代码
代码解释


  • Main 方法:

    • var services = new ServiceCollection();:创建一个服务集合。
    • services.AddViews().AddViewModels().AddServices();:注册视图、视图模型和其他服务。
    • ServiceProvider = services.BuildServiceProvider();:构建服务提供者。
    • BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);:配置并启动Avalonia应用程序。

  • BuildAvaloniaApp 方法:

    • AppBuilder.Configure():配置应用程序。
    • UsePlatformDetect():自动检测平台。
    • WithInterFont():使用Inter字体。
    • LogToTrace():将日志记录到跟踪。

内部实现

步骤详解


  • 创建应用程序类:

    • 继承自Application。
    • 重写Initialize方法,加载XAML资源。
    • 重写OnFrameworkInitializationCompleted方法,配置主窗口和依赖注入。

  • 配置依赖注入:

    • 创建服务集合。
    • 注册所需的视图、视图模型和其他服务。
    • 构建服务提供者。
    • 启动Avalonia应用程序。

序列图

sequenceDiagram    participant 程序入口    participant 服务集合    participant 服务提供者    participant 应用程序    participant 主窗口    程序入口->>服务集合: 创建服务集合    程序入口->>服务集合: 注册视图、视图模型和其他服务    服务集合->>服务提供者: 构建服务提供者    程序入口->>应用程序: 配置并启动应用程序    应用程序->>主窗口: 设置主窗口和视图模型结论

通过本章,我们学习了如何配置和启动Avalonia应用程序。我们介绍了应用程序类的创建和依赖注入的配置。希望你现在已经能够理解这些基本概念,并能够自己动手配置一个简单Avalonia应用程序。
接下来,我们将深入学习依赖注入的更多内容。请继续阅读:依赖注入。
Chapter 2: 依赖注入

从上一章过渡

在上一章 主应用程序配置 中,我们学习了如何配置和启动一个Avalonia应用程序。我们介绍了应用程序类的创建和依赖注入的基本概念。在这一章中,我们将深入探讨依赖注入(Dependency Injection, 简称DI)这一重要的设计模式。通过理解依赖注入,你将能够更灵活地管理和使用应用程序中的各个组件。
依赖注入的基本概念

为什么使用依赖注入?

假设你正在开发一个应用程序,其中包含多个组件,例如视图(View)、视图模型(ViewModel)和服务(Service)。每个组件都可能需要依赖其他组件来完成特定的功能。例如,一个视图模型可能会依赖一个服务来获取数据。如果没有依赖注入,每个组件都需要自己创建或查找依赖,这样会导致代码耦合度高,难以测试和维护。
依赖注入通过将依赖关系从组件内部移到外部来解决这个问题。就像在一个团队中,领导分配任务,而不是每个成员自己找任务。这种方式使得组件更加独立和模块化,更容易测试和维护。
依赖注入的关键概念


  • 依赖(Dependency)

    • 一个组件需要使用的其他组件。例如,视图模型可能需要一个服务来获取数据。

  • 注入(Injection)

    • 通过构造函数、属性或方法将依赖传递给组件的过程。这种方式使得组件不需要自己创建或查找依赖。

  • 依赖注入容器(Dependency Injection Container)

    • 管理和提供依赖的工具。在Avalonia中,我们使用 Microsoft.Extensions.DependencyInjection 来创建和管理依赖注入容器。

如何使用依赖注入

一个简单的例子

假设我们有一个视图模型 MainWindowViewModel,它需要使用一个服务 DataService 来获取数据。我们可以通过依赖注入来实现这一点。
定义服务

首先,我们定义一个服务 DataService:
  1. namespace AvaloniaWithDependencyInjection.Services
  2. {
  3.     public interface IDataService
  4.     {
  5.         string GetData();
  6.     }
  7.     public class DataService : IDataService
  8.     {
  9.         public string GetData()
  10.         {
  11.             return "Hello, World!";
  12.         }
  13.     }
  14. }
复制代码
注册服务

接下来,我们需要在依赖注入容器中注册这个服务。我们已经在 Program.cs 文件中完成了这一部分:
  1. public static AppBuilder BuildAvaloniaApp()
  2.     => AppBuilder.Configure()
  3.         .UsePlatformDetect()
  4.         .WithInterFont()
  5.         .LogToTrace();
  6. [STAThread]
  7. public static void Main(string[] args)
  8. {
  9.     var services = new ServiceCollection();
  10.     services.AddViews()
  11.             .AddViewModels()
  12.             .AddServices();
  13.     ServiceProvider = services.BuildServiceProvider();
  14.     BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
  15. }
复制代码
在 ServiceCollectionExtensions.cs 文件中,我们注册了所有的视图、视图模型和服务:
  1. public static class ServiceCollectionExtensions
  2. {
  3.     public static IServiceCollection AddViews(this IServiceCollection services)
  4.     {
  5.         services.AddSingleton<MainWindow>();
  6.         services.AddSingleton<Page1View>();
  7.         services.AddSingleton<Page2View>();
  8.         return services;
  9.     }
  10.     public static IServiceCollection AddViewModels(this IServiceCollection services)
  11.     {
  12.         services.AddSingleton<MainWindowViewModel>();
  13.         services.AddSingleton<Page1ViewModel>();
  14.         services.AddSingleton<Page2ViewModel>();
  15.         return services;
  16.     }
  17.     public static IServiceCollection AddServices(this IServiceCollection services)
  18.     {
  19.         services.AddSingleton<IDataService, DataService>();
  20.         return services;
  21.     }
  22. }
复制代码
注入依赖

现在,我们可以在 MainWindowViewModel 中注入 DataService:
  1. namespace AvaloniaWithDependencyInjection.ViewModels
  2. {
  3.     public class MainWindowViewModel
  4.     {
  5.         private readonly IDataService _dataService;
  6.         public string Data { get; private set; }
  7.         public MainWindowViewModel(IDataService dataService)
  8.         {
  9.             _dataService = dataService;
  10.             Data = _dataService.GetData();
  11.         }
  12.     }
  13. }
复制代码
代码解释


  • 定义服务

    • DataService 实现了 IDataService 接口,并提供了 GetData 方法。

  • 注册服务

    • 在 ServiceCollectionExtensions 中,我们通过 AddServices 方法注册了 DataService。

  • 注入依赖

    • 在 MainWindowViewModel 中,我们通过构造函数注入了 IDataService,并在构造函数中调用了 GetData 方法。

运行结果

当应用程序启动时,依赖注入容器会自动创建 DataService 实例,并将其传递给 MainWindowViewModel 的构造函数。MainWindowViewModel 会调用 GetData 方法,并将返回的数据赋值给 Data 属性。最终,Data 属性的值会显示在主窗口中。
内部实现

依赖注入容器的工作原理


  • 创建服务集合

    • 在 Program.cs 中,我们创建了一个 ServiceCollection 实例。

  • 注册依赖

    • 通过 AddViews、AddViewModels 和 AddServices 方法,我们注册了所有的视图、视图模型和服务。

  • 构建服务提供者

    • 使用 services.BuildServiceProvider() 方法,我们构建了一个 IServiceProvider 实例。

  • 获取服务

    • 在 App.axaml.cs 文件中,我们通过 Program.ServiceProvider.GetRequiredService() 和 Program.ServiceProvider.GetRequiredService() 方法从服务提供者中获取主窗口和主窗口视图模型。

序列图

4.png

结论

通过本章,我们深入探讨了依赖注入的基本概念和使用方法。我们学习了如何通过依赖注入来管理和使用应用程序中的各个组件,使得代码更加模块化和易于测试。希望你现在能够理解依赖注入的重要性和使用方法。
接下来,我们将学习 应用程序生命周期 的相关内容。请继续阅读,了解应用程序的各个生命周期阶段。
最后

多的就不放了,感兴趣的朋友可以去GitHub上看完整的,让我惊讶的地方是感觉gemini-2.5-pro-exp-03-25的图画的很不错,在教程中多放点这种图,会让读者更加清晰易懂。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册