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

## Tutorial-Codebase-Knowledge介绍
这是一个 Pocket Flow 的教程项目,一个仅100行代码的LLM框架。它爬取 GitHub 仓库,并从代码中构建知识库。它分析整个代码库以识别核心抽象及其交互方式,并将复杂的代码转化为带有清晰可视化内容的初学者友好教程。
## 实践
创建一个python虚拟环境,安装包:
```csharp
pip install -r requirements.txt
```
需要修改一下call\_llm.py:
使用谷歌的模型可以这样写:
```csharp
def call_llm(prompt, use_cache: bool = True):
client = genai.Client(
api_key=os.getenv("GEMINI_API_KEY", "你的api key"),
)
model = os.getenv("GEMINI_MODEL", "gemini-2.5-pro-exp-03-25")
response = client.models.generate_content(
model=model,
contents=[prompt]
)
response_text = response.text
return response_text
```
使用兼容OpenAI格式的模型可以这样写:
```csharp
# Use OpenAI o1
def call_llm(prompt, use_cache: bool = True):
from openai import OpenAI
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "你的api key"),
base_url="https://api.siliconflow.cn/v1")
r = client.chat.completions.create(
model="Qwen/QwQ-32B",
messages=[{"role": "user", "content": prompt}],
response_format={
"type": "text"
},
reasoning_effort="medium",
store=False
)
return r.choices[0].message.content
```
使用这个命令用于测试:
```csharp
python utils/call_llm.py
```
参考README的使用方法:
```csharp
# Analyze a GitHub repository
python main.py --repo https://github.com/username/repo --include "*.py" "*.js" --exclude "tests/*" --max-size 50000
# Or, analyze a local directory
python main.py --dir /path/to/your/codebase --include "*.py" --exclude "*test*"
# Or, generate a tutorial in Chinese
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")
正常运行如下图所示:

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

在我使用的模型中,我觉得效果最好的是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 -- "继承基类" --> A5
# Chapter 1: 主应用程序配置
## 欢迎初学者!
欢迎来到我们的第一个章节!在这个章节中,我们将学习如何配置和启动Avalonia应用程序。如果你是第一次接触Avalonia或者依赖注入(Dependency Injection, DI),请不要担心,我们将通过具体的例子来一步步引导你。
## 为什么要配置主应用程序?
在开发任何应用程序时,首先需要做的一件事情就是配置和启动它。在Avalonia中,主应用程序配置类似于一家公司的前台,负责接待访客并引导他们进入正确的房间。在这个例子中,我们的“前台”会做一些必要的初始化工作,比如设置主窗口和初始化依赖注入。这样的配置能确保应用程序能够顺利启动,用户可以使用所有的功能。
## 具体实现
### 1. 创建应用程序类
我们从创建应用程序类开始。在Avalonia中,应用程序类继承自`Application`,并重写一些方法来配置应用程序。我们来看一下`App.axaml.cs`文件中的代码:
```csharp
using System.Linq;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using AvaloniaWithDependencyInjection.ViewModels;
using AvaloniaWithDependencyInjection.Views;
using Microsoft.Extensions.DependencyInjection;
namespace AvaloniaWithDependencyInjection
{
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
DisableAvaloniaDataAnnotationValidation();
var mainWindow = Program.ServiceProvider?.GetRequiredService();
var mainViewModel = Program.ServiceProvider?.GetRequiredService();
if (mainWindow != null && mainViewModel != null)
{
mainWindow.DataContext = mainViewModel;
desktop.MainWindow = mainWindow;
}
}
base.OnFrameworkInitializationCompleted();
}
private void DisableAvaloniaDataAnnotationValidation()
{
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType().ToArray();
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
}
}
```
### 代码解释
1. **Initialize 方法**:
- `AvaloniaXamlLoader.Load(this);`:加载XAML资源,初始化用户界面。
2. **OnFrameworkInitializationCompleted 方法**:
- `ApplicationLifetime`:检查应用程序是否在传统的桌面环境中运行。
- `DisableAvaloniaDataAnnotationValidation()`:禁用Avalonia的数据注释验证,避免与CommunityToolkit重复验证。
- `Program.ServiceProvider.GetRequiredService()` 和 `Program.ServiceProvider.GetRequiredService()`:从依赖注入服务中获取主窗口和主窗口视图模型。
- `mainWindow.DataContext = mainViewModel;`:将主窗口的 DataContext 设置为主窗口视图模型。
- `desktop.MainWindow = mainWindow;`:设置应用程序的主窗口。
3. **DisableAvaloniaDataAnnotationValidation 方法**:
- 从数据验证插件中移除Avalonia的数据注释验证插件,避免重复验证。
### 2. 配置依赖注入
接下来,我们来看看如何配置依赖注入。在`Program.cs`文件中,我们会创建一个服务集合,并注册所需的依赖项:
```csharp
using System;
using Avalonia;
using Microsoft.Extensions.DependencyInjection;
namespace AvaloniaWithDependencyInjection
{
internal sealed class Program
{
public static IServiceProvider? ServiceProvider { get; private set; }
[STAThread]
public static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddViews()
.AddViewModels()
.AddServices();
ServiceProvider = services.BuildServiceProvider();
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}
}
```
### 代码解释
1. **Main 方法**:
- `var services = new ServiceCollection();`:创建一个服务集合。
- `services.AddViews().AddViewModels().AddServices();`:注册视图、视图模型和其他服务。
- `ServiceProvider = services.BuildServiceProvider();`:构建服务提供者。
- `BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);`:配置并启动Avalonia应用程序。
2. **BuildAvaloniaApp 方法**:
- `AppBuilder.Configure()`:配置应用程序。
- `UsePlatformDetect()`:自动检测平台。
- `WithInterFont()`:使用Inter字体。
- `LogToTrace()`:将日志记录到跟踪。
### 内部实现
#### 步骤详解
1. **创建应用程序类**:
- 继承自`Application`。
- 重写`Initialize`方法,加载XAML资源。
- 重写`OnFrameworkInitializationCompleted`方法,配置主窗口和依赖注入。
2. **配置依赖注入**:
- 创建服务集合。
- 注册所需的视图、视图模型和其他服务。
- 构建服务提供者。
- 启动Avalonia应用程序。
#### 序列图
sequenceDiagram
participant 程序入口
participant 服务集合
participant 服务提供者
participant 应用程序
participant 主窗口
程序入口->>服务集合: 创建服务集合
程序入口->>服务集合: 注册视图、视图模型和其他服务
服务集合->>服务提供者: 构建服务提供者
程序入口->>应用程序: 配置并启动应用程序
应用程序->>主窗口: 设置主窗口和视图模型
## 结论
通过本章,我们学习了如何配置和启动Avalonia应用程序。我们介绍了应用程序类的创建和依赖注入的配置。希望你现在已经能够理解这些基本概念,并能够自己动手配置一个简单Avalonia应用程序。
接下来,我们将深入学习依赖注入的更多内容。请继续阅读:[依赖注入](https://www.cnblogs.com/mingupupu/p/02_%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5_.md)。
# Chapter 2: 依赖注入
## 从上一章过渡
在上一章 [主应用程序配置](https://www.cnblogs.com/mingupupu/p/01_%E4%B8%BB%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E9%85%8D%E7%BD%AE_.md) 中,我们学习了如何配置和启动一个Avalonia应用程序。我们介绍了应用程序类的创建和依赖注入的基本概念。在这一章中,我们将深入探讨依赖注入(Dependency Injection, 简称DI)这一重要的设计模式。通过理解依赖注入,你将能够更灵活地管理和使用应用程序中的各个组件。
## 依赖注入的基本概念
### 为什么使用依赖注入?
假设你正在开发一个应用程序,其中包含多个组件,例如视图(View)、视图模型(ViewModel)和服务(Service)。每个组件都可能需要依赖其他组件来完成特定的功能。例如,一个视图模型可能会依赖一个服务来获取数据。如果没有依赖注入,每个组件都需要自己创建或查找依赖,这样会导致代码耦合度高,难以测试和维护。
依赖注入通过将依赖关系从组件内部移到外部来解决这个问题。就像在一个团队中,领导分配任务,而不是每个成员自己找任务。这种方式使得组件更加独立和模块化,更容易测试和维护。
### 依赖注入的关键概念
1. **依赖(Dependency)**:
- 一个组件需要使用的其他组件。例如,视图模型可能需要一个服务来获取数据。
2. **注入(Injection)**:
- 通过构造函数、属性或方法将依赖传递给组件的过程。这种方式使得组件不需要自己创建或查找依赖。
3. **依赖注入容器(Dependency Injection Container)**:
- 管理和提供依赖的工具。在Avalonia中,我们使用 `Microsoft.Extensions.DependencyInjection` 来创建和管理依赖注入容器。
## 如何使用依赖注入
### 一个简单的例子
假设我们有一个视图模型 `MainWindowViewModel`,它需要使用一个服务 `DataService` 来获取数据。我们可以通过依赖注入来实现这一点。
#### 定义服务
首先,我们定义一个服务 `DataService`:
```csharp
namespace AvaloniaWithDependencyInjection.Services
{
public interface IDataService
{
string GetData();
}
public class DataService : IDataService
{
public string GetData()
{
return "Hello, World!";
}
}
}
```
#### 注册服务
接下来,我们需要在依赖注入容器中注册这个服务。我们已经在 `Program.cs` 文件中完成了这一部分:
```csharp
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
[STAThread]
public static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddViews()
.AddViewModels()
.AddServices();
ServiceProvider = services.BuildServiceProvider();
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
```
在 `ServiceCollectionExtensions.cs` 文件中,我们注册了所有的视图、视图模型和服务:
```csharp
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddViews(this IServiceCollection services)
{
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
return services;
}
public static IServiceCollection AddViewModels(this IServiceCollection services)
{
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
return services;
}
public static IServiceCollection AddServices(this IServiceCollection services)
{
services.AddSingleton();
return services;
}
}
```
#### 注入依赖
现在,我们可以在 `MainWindowViewModel` 中注入 `DataService`:
```csharp
namespace AvaloniaWithDependencyInjection.ViewModels
{
public class MainWindowViewModel
{
private readonly IDataService _dataService;
public string Data { get; private set; }
public MainWindowViewModel(IDataService dataService)
{
_dataService = dataService;
Data = _dataService.GetData();
}
}
}
```
### 代码解释
1. **定义服务**:
- `DataService` 实现了 `IDataService` 接口,并提供了 `GetData` 方法。
2. **注册服务**:
- 在 `ServiceCollectionExtensions` 中,我们通过 `AddServices` 方法注册了 `DataService`。
3. **注入依赖**:
- 在 `MainWindowViewModel` 中,我们通过构造函数注入了 `IDataService`,并在构造函数中调用了 `GetData` 方法。
### 运行结果
当应用程序启动时,依赖注入容器会自动创建 `DataService` 实例,并将其传递给 `MainWindowViewModel` 的构造函数。`MainWindowViewModel` 会调用 `GetData` 方法,并将返回的数据赋值给 `Data` 属性。最终,`Data` 属性的值会显示在主窗口中。
## 内部实现
### 依赖注入容器的工作原理
1. **创建服务集合**:
- 在 `Program.cs` 中,我们创建了一个 `ServiceCollection` 实例。
2. **注册依赖**:
- 通过 `AddViews`、`AddViewModels` 和 `AddServices` 方法,我们注册了所有的视图、视图模型和服务。
3. **构建服务提供者**:
- 使用 `services.BuildServiceProvider()` 方法,我们构建了一个 `IServiceProvider` 实例。
4. **获取服务**:
- 在 `App.axaml.cs` 文件中,我们通过 `Program.ServiceProvider.GetRequiredService()` 和 `Program.ServiceProvider.GetRequiredService()` 方法从服务提供者中获取主窗口和主窗口视图模型。
### 序列图

## 结论
通过本章,我们深入探讨了依赖注入的基本概念和使用方法。我们学习了如何通过依赖注入来管理和使用应用程序中的各个组件,使得代码更加模块化和易于测试。希望你现在能够理解依赖注入的重要性和使用方法。
接下来,我们将学习 [应用程序生命周期](https://www.cnblogs.com/mingupupu/p/03_%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F_.md) 的相关内容。请继续阅读,了解应用程序的各个生命周期阶段。
## 最后
多的就不放了,感兴趣的朋友可以去GitHub上看完整的,让我惊讶的地方是感觉gemini-2.5-pro-exp-03-25的图画的很不错,在教程中多放点这种图,会让读者更加清晰易懂。
本文来自投稿,不代表本站立场,如若转载,请注明出处:http//www.knowhub.vip/share/2/2513
- 热门的技术博文分享
- 1 . ESP实现Web服务器
- 2 . 从零到一:打造高效的金仓社区 API 集成到 MCP 服务方案
- 3 . 使用C#构建一个同时问多个LLM并总结的小工具
- 4 . .NET 原生驾驭 AI 新基建实战系列Milvus ── 大规模 AI 应用的向量数据库首选
- 5 . 在Avalonia/C#中使用依赖注入过程记录
- 6 . [设计模式/Java] 设计模式之工厂方法模式
- 7 . 5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
- 8 . SQL 中的各种连接 JOIN 的区别总结!
- 9 . JavaScript 中防抖和节流的多种实现方式及应用场景
- 10 . SaltStack 远程命令执行中文乱码问题
- 11 . 推荐10个 DeepSeek 神级提示词,建议搜藏起来使用
- 12 . C#基础:枚举、数组、类型、函数等解析
- 13 . VMware平台的Ubuntu部署完全分布式Hadoop环境
- 14 . C# 多项目打包时如何将项目引用转为包依赖
- 15 . Chrome 135 版本开发者工具(DevTools)更新内容
- 16 . 从零创建npm依赖,只需执行一条命令
- 17 . 关于 Newtonsoft.Json 和 System.Text.Json 混用导致的的序列化不识别的问题
- 18 . 大模型微调实战之训练数据集准备的艺术与科学
- 19 . Windows快速安装MongoDB之Mongo实战
- 20 . 探索 C# 14 新功能:实用特性为编程带来便利
- 相关联分享