引言

你是否想过拥有一个私人订制的AI助手,能够随时为你提供最个性化的信息?本文将带你一步步搭建一个基于本地模型和RAG技术的个人知识库。

搭建本地模型

环境

  • os: archlinux
  • 内存: 32g
  • cpu: 6核12线程
  • python: 3.12.7
  • docker27.3.1 + docker-compose
  • 向量库: milvus2.4.13 + attu2.4(客户端)

ollama

1
2
3
4
5
6
7
pacman -S ollama

systemctl start ollama.service

# 通过下述url判断ollama是否安装成功
http://127.0.0.1:11434/

llama3.2:3b

1
ollama run llama3.2:3b

OpenWebUI(非必须)

1
2
3
4
5
# 启动openwebui, 按照自己需要调整端口
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui ghcr.io/open-webui/open-webui:main

# 浏览器访问, 可以看到之前启动的模型
http://localhost:3000/

程序访问测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage

# 创建ChatOllama实例,指定模型名称
model = ChatOllama(model="llama3.2:3b")

# 定义你的问题
question = HumanMessage("你是如何工作的?")

# 使用模型处理问题
response = model.invoke([question])

# 打印返回的结果
print(response.content)

构建知识库

RAG是什么

大模型的训练数据是有截止日期的,那当我们需要依靠不包含在大模型训练集中的数据时,我们该怎么做呢?一种就是对模型进行微调,另外就是通过检索增强生成RAG(Retrieval Augmented Generation)。在这个过程中,首先检索外部数据,然后在生成步骤中将这些数据传递给LLM。

利用大模型的能力搭建知识库就是一个RAG技术的应用。

RAG的应用抽象为5个过程:

  • 文档加载(Document Loading) :从多种不同来源加载文档。LangChain提供了100多种不同的文档加载器,包括PDF在内的非结构化的数据、SQL在内的结构化的数据,以及Python、Java之类的代码等
  • 文本分割(Splitting) :文本分割器把Documents 切分为指定大小的块,我把它们称为“文档块”或者“文档片”
  • 存储(Storage): 存储涉及到两个环节,分别是:
    1. 将切分好的文档块进行嵌入(Embedding)转换成向量的形式
    2. 将Embedding后的向量数据存储到向量数据库
  • 检索(Retrieval) :一旦数据进入向量数据库,我们仍然需要将数据检索出来,我们会通过某种检索算法找到与输入问题相似的嵌入片
  • 输出(Output) :把问题以及检索出来的嵌入片一起提交给LLM,LLM会通过问题和检索出来的提示一起来生成更加合理的答案

个人笔记

首先起码得有自己的知识库,我这里就是个人多年整理的笔记。或者你有项目相关的文档,也可以作为知识库的基础。

将个人笔记写入到Milvus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from langchain_community.document_loaders import DirectoryLoader
from langchain_community.vectorstores import Milvus
from langchain_ollama import OllamaEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from pymilvus import MilvusClient
import os

# 检查collection是否存在, 如果不指定,默认为LangChainCollection
collection_name = "note"

# 设置 Milvus 客户端
client = MilvusClient(uri="http://localhost:19530")

# 检查collection是否存在
if client.has_collection(collection_name):
# collection存在,执行后续操作
print(f"Collection '{collection_name}' exists.")
else:
# collection不存在,创建collection并进行向量化
print(f"Collection '{collection_name}' does not exist. Creating now...")
# 从url导入知识作为聊天背景上下文, glob代表只查找org文件,可根据实际情况调整为txt等,recursive=True表示会递归查找
loader = DirectoryLoader(os.path.join(os.environ["HOME"], "Documents/notes"), glob="*.org", recursive=True)
# 加载一堆文件
docs = loader.load()

# 文本分词器
# chunk_size=1000
# 表示拆分的文档的大小,也就是上面所说的要设置为多少合适取决于所使用LLM 的窗口大小
# chunk_overlap=100
# 这个参数表示每个拆分好的文档重复多少个字符串。
# 不过这种递归的方式更只能点,不设参数试试默认
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)

# ollama嵌入层
embeddings = OllamaEmbeddings(
model="llama3.2:3b"
)

# 文档向量化,会持久化
vector_store = Milvus.from_documents(documents=documents, embedding=embeddings, collection_name=collection_name, drop_old=True)
print(f"collection'{collection_name}'创建成功!")

注: 上述加载文件的目录需要根据自己实际情况调整,其它的最好用默认,减少出错概率

将llm与Milvus结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_community.vectorstores import Milvus
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaEmbeddings
from langchain_ollama import OllamaLLM
from langchain_text_splitters import RecursiveCharacterTextSplitter
from pymilvus import MilvusClient


def exec(question):
# 检查collection是否存在
collection_name = "note"
# 设置 Milvus 客户端
client = MilvusClient(uri="http://localhost:19530")
vector_store = None
# 检查collection是否存在
if client.has_collection(collection_name):
# collection存在,执行后续操作
print(f"Collection '{collection_name}' exists.")
# 文本分词器
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents([])

# ollama嵌入层
embeddings = OllamaEmbeddings(
model="llama3.2:3b"
)
# 文档向量化
vector_store = Milvus.from_documents(documents=documents, embedding=embeddings, collection_name=collection_name)
else:
# collection不存在,创建collection并进行向量化
print(f"Collection '{collection_name}' does not exist. Please exec LoadFile2Vector.py first")
if vector_store is not None:
# 创建ollama 模型 llama2
llm = OllamaLLM(model="llama3.2:3b")
output_parser = StrOutputParser()

# 创建提示词模版
prompt = ChatPromptTemplate.from_template(
"""Answer the following question based only on the provided context:
<context>
{context}
</context>
Question: {input}"""
)

# 生成chain : prompt | llm
document_chain = create_stuff_documents_chain(llm, prompt)

# 向量数据库检索器
retriever = vector_store.as_retriever()

# 向量数据库检索chain : vector | prompt | llm
retrieval_chain = create_retrieval_chain(retriever, document_chain)

# 调用上面的 (向量数据库检索chain)
response = retrieval_chain.invoke({"input": question})
# 打印结果
print(response["answer"])


if __name__ == '__main__':
exec("我有什么梦想? 如何实现")

大致的流程是:用户的query先转成embedding,去向量数据库查询最接近的top K回答;然后这query + top K的回答 + 其他context一起进入LLM,让LLM整合上述所有的信息后给出最终的回复。

提供接口(非必须)

可通过fastapi等提供restful接口供外部调用,比如一些个人项目公司内部项目之类的,瞬间高大上起来了。

项目源码

https://github.com/zhaozhiwei1992/NoteAI.git

参考

https://blog.csdn.net/AAI666666/article/details/137509781

https://ollama.com/library

文本向量转换: https://github.com/shibing624/text2vec

文本存储: https://juejin.cn/post/7360564568660410377

引言

分享一个前后端分离的后台管理系统,技术栈较新,适合喜欢倒腾的朋友。

地址: https://github.com/zhaozhiwei1992/money-making-machine-plus.git

喜欢的朋友,点点star

项目描述

一个前后端分离的后台管理系统, 基于springboot3.3.3+vue3.3.4+mysql8, 代码结构清晰,注释友好,使用最新的前后端开发技术,适合想要尝鲜的道友。

项目参考了jhipster的优秀代码设计,ruoyi项目的目录接口, 分模块开发, 感谢以上开源项目。

目前处于开发阶段,有问题提issue,后续会继续完善。如果动手能力强的朋友,可以直接参与开发,一起完善这个项目。

为什么叫赚钱工具?字面意思,因为真的很穷。

体验地址

http://43.143.194.245:8091/index.html (无了,暂时没钱搞服务器:D)

用户/密码: admin/admin

项目特点

代码注释友好, 实现简单, 便于阅读, 推荐二次开发

前后端分离,使用 token 认证

支持RBAC权限模型, 支持菜单及按钮权限控制, 动态显示及后端严格权限控制

支持角色+菜单的数据权限控制, 按照规则配置好后,程序自动控制

前端采用 Vue3.x + element-plus-admin, 数据绑定代码简单,提高开发效率

使用 liquibase 进行数据库版本控制, 空库只需创建数据库然后启动服务即可

使用 quartz 定时任务,可动态完成任务的添加、修改、删除、暂停、恢复及日志查看等功能

使用 swagger 查看或测试后端接口

使用 jpa 做数据库操作, 理论上支持大部分关系数据库

同步支持移动端小程序

功能模块

基础数据

  • 部门管理

  • 用户管理

  • 角色管理

  • 基础数据维护

菜单管理

  • 菜单管理

  • 动态表单

  • 采集表

系统管理

  • 功能权限

  • 数据权限

  • 流程管理

  • 缓存管理

  • 定时任务

  • 系统参数

审计查询

系统监控

  • 在线人员监控

  • 日志管理

  • 资源监控

  • 服务状态

  • 缓存状态

首页显示

  • 待办事项

  • 通知公告

国际化

  • 国际化支持

开发者工具

  • 代码生成

  • 大屏显示

  • 报表制作

安装要求

  1. java 21+
  2. springboot 3.3.3.RELEASE
  3. mysql 8+
  4. npm 8+
  5. node 20+

tag1.0.0

  1. java 8+
  2. springboot 2.6.3.RELEASE
  3. mysql 5.7.5+
  4. npm 6.14.4+
  5. node 16.13.1+

安装步骤

  1. git clone 当前项目到你喜欢的目录
  2. 用你喜欢的 ide 引入该项目,并加载好依赖
  3. 创建好数据库 database, 默认 money_making_machine_plus
  4. 启动项目: 后端运行com.z.server.BootStrapServerApplication, 前端进入z-ui-admin-vue3目录, 执行pnpm run dev(先构建)
  5. 访问http://localhost:4000, 登录查看我们的成果, 用户/密码:admin/admin

部署

前后端分离部署

前后端集中部署

1
mvn clean package -Psingle

版本控制

该项目使用 git 进行版本管理。您可以在 tags 参看当前可用版本。

引言

你平时都怎么复制粘贴的?是否每次都是复制一段粘贴一段?是否厌倦了每次只能复制粘贴一次的限制?那这篇文章就是为你量身订做的。

CopyQ简介

CopyQ is clipboard manager – a desktop application which stores content of the system clipboard whenever it changes and allows to search the history and copy it back to the system clipboard or paste it directly to other applications.

CopyQ 是一款开源的、跨平台的剪贴板管理工具,它不仅存储系统剪贴板的内容,还允许用户搜索历史记录,并将所需内容复制回系统剪贴板或直接粘贴到其他应用程序。这就意味着,你可以一次性复制多份内容,然后在需要的时候统一粘贴,极大地提高了工作效率。

官方地址: https://copyq.readthedocs.io/en/latest/

CopyQ支持Windows、macOS、Linux系统,无论你使用的是哪种操作系统,都能享受到它带来的便利。

CopyQ的核心功能

多格式支持:CopyQ不仅限于文本,还支持图片、HTML等多种格式,满足不同场景的需求。

历史记录管理:你可以轻松管理剪贴板的历史记录,进行搜索、筛选和排序,快速找到你需要的内容。

多标签页功能:通过标签页分类管理剪贴板内容,提高组织效率,更清晰。

标记置顶功能: 可以给复制的条目打一个醒目的标签,方便后续查找。也可以将常用的复制内容置顶,后续就不需要每次找到源头复制再去粘贴。

编辑和脚本功能:内置编辑器让你可以对复制的文本内容进行调整,而脚本功能则为高级用户提供了更多自定义的可能。

导出和备份:软件本身支持复制内容的导出备份,同时导出的内容还可以导入到软件中。基于这一点如果动手能力还可以,能做个定时工具,利用github,或者同步网盘做一个多平台同步,爽。

实际应用案例

编程开发:软件开发过程使用复制粘贴很频繁,不然也不会叫CV工程师了。如果有多段分隔开的代码要复制,平时都是复制粘贴一段,返回网站继续复制,循环往复。但是这样做很2,这里就可以使用CopyQ,一次复制完,然后到IDE中多次粘贴即可。

办公:比如经常用的word,excel,我们需要使用其中某些部分填充到新的文件中。此时我们可以直接将要使用的内容全部复制,然后到新的文件中按照需要多次粘贴即可。

笔记:一些经常使用的文字可以保存在CopyQ中,比如todo 、临时笔记等,使用时直接粘贴即可。

结语

这篇文章只是CopyQ的冰山一角,还有更多神奇的功能等待你去发现。三人行必有我师,如果你有其他提高效率的小技巧或工具,欢迎在评论区分享。

用效率工具,享牛马人生!

公众号: 陌上花kai

什么是NAS及为什么要用NAS

NAS,英文全名Network Attached Storage,翻译过来是:网络附接存储。

引用维基百科定义

1
网络附接存储(英语:Network Attached Storage,缩写:NAS)[1]是一种文件级(与块级存储相对)的计算机数据存储服务器,它连接到计算机网络,并提供对异构网络用户的数据访问。它专门用于通过其硬件、软件或配置来提供文件服务。它通常作为专门制造的专用计算机设备制造。 NAS系统是包含一个或多个通常排列成逻辑存储器、冗余存储器或RAID存储驱动器的网络设备。NAS消除了从网络上的其他服务器提供文件服务的负担,它们通常使用网络文件共享协议(如NFS、SMB或AFP)提供对文件的访问。

上边说了一大堆,看着头疼。其实说直白一点,百度网盘大家都用过,可以直接存文件,看电影,放照片很方便对吧, 那么NAS也是干这事儿的。这里大家要问,那我百度2个T的宝贝为啥还要要用NAS呢? 这里就不得不说百度网盘及各种乱七八糟的网盘是很方便,但是有一个很大的缺点,那就是你的资源都掌握在别人手里(你懂得),这时候NAS就体现了它的一个优势,数据都由你自己掌控。

小白特供,NAS可以干什么

个人感觉最主要的几个场景,构建家庭影院,照片分享,文件备份。 同时因为其本身就是一个服务器,心情好你可以做个人博客。

如何选择

新手小白可以直接选择现成品牌即可,市面上用的比较多的有以下几个:

极空间:https://tiyan.zspace.cn/

群晖:https://demo.synology.cn/zh-cn/dsm

威联通:https://www.qnap.com.cn/zh-cn/live-demo

爱速特:https://www.asustor.com/zh-cn/live_demo

可以参考他们的官网按照自己的心里价位购买即可,很easy

如果是老鸟(我是菜鸟),就可以根据以前的使用经验,从硬件到软件统统考虑,然后再结合自己的心里价位去综合考虑。或者动手能力强,自己刷刷刷也不是不行。

为什么要自建及优缺点

现在到了本文的重点,自建NAS。 那么为什么自建,且听我一一道来。

成本效益:

自建NAS通常比购买现成的NAS系统更经济,只要你有台差不多的基本废弃不用的电脑,就可以自建。系统本身及需要的软件也是开源免费使用,四舍五入那就是不花钱。

定制化

可以根据自己的需求定制硬件和软件,如果你觉得自己磁盘不够就可以随时加硬盘,软件不好用那就换软件,系统用腻了那就换系统,爽。

上边都是优点,当然自建也是有缺点的

没有开箱即用,很多东西需要自己学习,对于小白来说有点难。

稳定性可能不如现成的NAS。

UI没有现成的NAS看起来好看统一。

如何自建

一台个人闲置电脑

首先要有一台电脑,最好是台式机,小机箱也行,但是如果需要扩展多块硬盘还是大点好。其次是系统,我个人是使用archlinux习惯了,也可以使用其它发行版本。

DLNA/UPnP家庭流媒体服务 jellyfin + KODI(播放器) 家庭影院软件

https://jellyfin.org/docs/general/installation/linux/

1
2
3
4
# 启动
systemctl start jellyfin.service
# 访问, 按照自己设置的密码搞起即可
http://127.0.0.1:8096

BT下载aria2

Linux服务器web管理神器–Cockpit (作为服务资源监控管理工具使用)

1
2
3
4
#启动
systemctl start cockpit.service
# 访问
http://localhost:9091

照片查看 photoprism

https://docs.photoprism.app/user-guide/

1
2
3
4
5
6
7
cd ~/.photoprism
docker-compose up -d

#访问
http://127.0.0.1:2342

PhotoPrism 的默认用户名为 admin,密码为 insecure

优势: 可以使用现有的存储路径,重建索引

缺点: 只有网页版

网盘聚合alist + rclone(非必须)

可以通过该工具,直接在线访问网盘中视频,或者配合其它工具(rclone)通过webdav将网盘目录挂载到本地

windows下用RaiDrive替代rclone

samba: Samba(SMB)文件共享服务(非必须)

主要是用来跟win进行数据共享,如果有需要可以安装起来

移动端

视频播放 mxplayer(安卓) nplayer(ios)

浏览器直接访问

交流

欢迎关注公众号, 更方便查看文章

公众号: 陌上花kai

引言

系统没有高低贵贱,主要还是使用的人,哪个跟你更契合。对我而言, archlinux就是最契合的那个。本文主要是对archlinux使用做一个粗浅的介绍,如果能勾起你一丝兴趣,那就更好了。

第一部分:初识Arch Linux

从Ubuntu和Fedora到Arch的转变

大学期间了解到有linux这么一类系统,看起来很酷,那命令行操作神秘又高级,瞬间引起了我的兴趣。经过各种对比,选择了最容易上手的ubuntu发行版。使用中发现跟windown体验大不相同,很多东西都要从头学起,对于喜欢折腾的人来说真的是瞌睡给了个枕头。同时这个系统简直是游戏荒漠,使用这个系统又能帮助我远离游戏,一举多得。

大概使用一年多ubuntu后中间也接触了fedora但是也没什么吸引力,个人感觉也就是界面不同,包管理机制不同,没什么特殊的。直到我遇到了archlinux,搜索各种资料学习安装,说实话刚开始纯命令行安装真的很头大,就怕一步搞不对,但是折腾起来后,很有j成就感。瞬间感觉自己的水平上了一个档次。

搜索与学习:如何克服初期困难

其实所有发行版都是基于同一个linux内核,大差不差,但是不同的发行版有各自的特色,archlinux就是让你可以更加自由的定制。如果是纯新手我建议不用想别的就是一直逼着自己用, 不会就去搜索,这个是必须要经历的,等过了这段时间就是海阔天空。

第二部分:桌面环境的探索

UNITY

最初ubuntu模式使用unity桌面,那时候导航栏靠左显示,那叫一个帅气。

GNOME

fedora系统默认使用gnome桌面,这个桌面给我的第一感觉就是很绚,而且这套桌面环境自带了很多实用的功能,开箱即用,对新手很友好。

XFCE

如果你的电脑比较老旧,可以选用xfce,这个桌面环境麻雀虽小五脏俱全,占用资源很小而且足够用,不用太折腾。

Openbox

严格来说openbox并不算桌面环境,只能算是个桌面管理器,要构成一个完整的桌面需要自己去定制,如: panel栏:tint2,背景透明: xcompmgr,程序运行:albert,喇叭图标volumeicon,登录管理器:slim等。一段时间这是我的主力桌面,真的很快。

i3wm

一个偶然的机会听说有一种叫平铺的桌面环境,然后就结识了i3,跟openbox一样仅仅是个桌面管理器,一切都要自己去定制,包括桌面背景,导航栏,登录管理器等。感兴趣的道友可以去看看,新手不建议使用,容易劝退。

第三部分:Arch Linux的日常生活

从不熟悉到离不开

最开始因为对系统的不熟悉有很多问题,天天不是在搜索就是在搜索的路上,工作的事情一点没干都是在学怎么用系统了。随着时间的推移,很多坑也慢慢填平了,系统使用越来越熟练,很多工作在命令下操作会比界面操作效率高很多,现在让我换回windows真的很不习惯。

日常工作与生活的便利

在日常工作和生活中,Arch Linux的高效操作让我能够更快地完成任务。有一件印象深刻的事儿,刚毕业工作那会儿,有一次领导让整理几百个脚本文件,需要在每个脚本前边加上begin。作为一个”懒惰”的程序员,必须善用工具,使用sed命令分分钟搞定,当时那叫一个骄傲。

第四部分:工作中的Arch Linux

提高工作效率的秘诀

工作这么多年,大家一致觉得我的工作效率比较高,主要原因就在于这个系统,因为基本上是我自己定制出来的,对它更熟悉,使用起来当然得心应手。对于文本操作,软件开发,linux是有天然的优势,因为一切皆文件,很多时候文本操作会比图形界面快很多,比如开发环境搭建,文本有天然优势,可以做成工具一步到位。

定制化系统以适应工作需求

不论任何行业工作久了都会有自己的工具箱,我自己会把一些日常使用的东西配置都整理到一起,然后通过git版本控制,如果换新的机器,直接安装好后统一初始化,搞定。这个真的很舒服,要用起来。

服务器管理的简便性

如果你是技术人员,日常中使用linux让你在面对生产服务器时也会更从容。 就相当与给你换了太电脑,仅此而已,so easy。

第五部分:Arch Linux的学习之道

逼迫自己:持续使用的重要性

学会使用Arch Linux的最好方式就是逼迫自己一直使用它。

实践出真知:通过实际操作学习

系统就是要经常用,不要怕,用不坏的。

社区资源:如何利用Arch Linux社区

大部分的问题在arch wiki都可以找到,系统安装了之类的不要看乱七八糟的地方,wiki足以。

https://archlinux.org/

结语

Arch Linux的旅程充满了挑战,但也充满了乐趣。它不仅提高了我的技术能力,也锻炼了我的自制力。如果你也在寻找一个能够挑战自我、提高效率的Linux发行版,那么Arch Linux绝对是一个不错的选择。

一个测试112

测试评论

封面

::: {.center}
xx公司

2020-01-01
:::

文档管理

合理地管理主文档,确保文档版本的及时更新,同时保持备份文档和源文档的一致性。

版本管理


本版本修订日期 2019-08-12 生效日期 2019-08-12


版本 生效日期 变更内容 编制人


V1.0 2020-01-01 初稿编写完成 xx

引言

编写目的

说明编写这份概要设计说明书的目的,指出预期的读者。(对于由多个子系统构成的系统,可以根据需要针对子系统编写单独的软件概要设计说明)

背景

说明:

待开发软件系统的名称;

列出此项目的任务提出者、开发者、用户以及将运行该软件的位置;

术语和缩略语

列出本文件中用到的专门术语的定义和外文首字母组词的原词组。

参考资料

列出有关的参考文件,如:

本项目的经核准的计划任务书或合同,上级机关的批文;

属于本项目的其他已编制文件;

本文件中各处引用的文件、资料,包括所要用到的软件开发标准、专业技术标准。列出这些文件的标题、文件编号、发表日期、出版单位和来源。

总体设计

需求规定

说明对本系统的主要的输入输出项目、处理的功能性能要求。可以引用软件规格说明文档以避免重复。

运行环境

简要地说明对本系统的运行环境(包括硬件环境和支持环境)的规定。

设计思想

系统构思

说明本系统设计的系统构思。

关键技术与算法

说明本系统设计采用的关键技术和主要算法。

关键数据结构

简要说明本系统实现中的最主要的数据结构。

系统总体结构

以图表的形式说明本系统的系统元素(各层模块、子模块、公用模块等)的划分,扼要说明各系统元素的标识和功能,分层次说明各系统元素之间的关系。

基本处理流程

系统流程图

用流程图的方式说明本系统的主要控制流程和处理流程。

数据流程图

根据需要,用数据流程图说明本系统的主要数据及其流转过程,并说明流转过程中的处理动作。

功能需求与模块的关系

说明各项功能需求的实现同各模块的分配关系。要与软件规格说明中的功能编号相一致。

尚未解决的问题

说明在概要设计过程中尚未解决而设计者认为在系统完成之前必须解决的各个问题。

接口设计

外部接口

说明本系统同外界的所有接口设计。包括本系统与硬件之间的接口设计、本系统与各支持软件之间的接口设计、对外提供的接口服务的设计。

内部接口

说明本系统之内的各个系统元素之间的接口的安排。

性能设计及质量属性考虑

通过设计落实在软件规格说明中的各种性能及质量属性规定。

数据库设计

说明本系统内所使用的数据结构设计要点及与程序模块间的关系。对数据库表的设计一般以另文方式(数据库设计说明)给出。

内容审核要点:

是否全面考虑了软件需求规格说明文档的功能需求;

所述功能名称及编号与软件需求规格说明文档是否一致;

总体结构是否清晰合理;

是否包括对外提供的接口服务的形式化表述和设计内容;

数据结构设计内容的全面性及合理性;

参考

https://www.jianshu.com/p/a7984927cfb9

Vim插件管理器Vundle使用指南

Vundle简介

Vundle是一个Vim插件管理器,它允许您:

  • .vimrc中跟踪和配置插件
  • 安装配置的插件
  • 更新插件
  • 搜索所有可用的Vim脚本
  • 清理未使用的插件
  • 通过交互模式一键运行上述操作

快速开始

1. 安装Vundle

1
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim

2. 配置vimrc.bundle

.vimrc中添加以下内容,以使用Vundle:

1
2
3
4
5
6
... 一堆配置
if filereadable(expand("~/.vimrc.bundles"))
source ~/.vimrc.bundles
endif
filetype plugin indent on

3. 安装插件

在Vim中执行:PluginInstall来安装插件。

或者从命令行执行vim +PluginInstall +qall

4. (可选)对于使用fish shell的用户

.vimrc中添加set shell=/bin/bash

好用的Vim插件

surround

surround插件可以方便地添加、修改和删除包围符:

1
2
3
4
5
6
7
8
9
10
11
12
13
" 替换: cs"'
"Hello world!" -> 'Hello world!'

" 替换-标签: cst"
<a>abc</a> -> "abc"

" 添加: ysiw"
Hello -> "Hello"

" 添加-整行: yss"
Hello world -> "Hello world"

" 添加-当前到行尾: ys$"

vim-repeat

vim-repeat插件允许你重复一个插件的操作,例如surround.vim:

通过.号重复上一次操作。

模糊搜索神器fzf

fzf是一个强大的模糊搜索工具,结合fzf.vim插件使用:

1
2
Bundle 'junegunn/fzf'
Bundle 'junegunn/fzf.vim'

在Vim中执行:PlugInstall安装插件。

需要安装ripgrep

1
pacman -S ripgrep

使用Vundle

Vundle提供了多种命令来管理插件:

  • :PluginList - 列出配置的插件
  • :PluginInstall - 安装插件
  • :PluginUpdate - 更新插件
  • :PluginSearch - 搜索插件
  • :PluginClean - 清理未使用的插件
1
2
" 把自定义的.vimrc.bundle文件引入到.vimrc中
source ~/.vimrc.bundle
1
2
# 复制molokai主题到你的vim目录
cd ~/.vim & cp -r bundle/molokai/colors .
1
2
" 更新所有插件
:BundleUpdate

一份个人插件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
if &compatible
set nocompatible
end

filetype off
set rtp+=~/.vim/bundle/Vundle.vim/
call vundle#rc()

" Let Vundle manage Vundle
Bundle 'gmarik/vundle'

" Define bundles via Github repos
Bundle "tomasr/molokai"
Bundle 'vim-airline'
Bundle 'jlanzarotta/bufexplorer'
"Bundle 'skammer/vim-css-color'
"Bundle 'mattn/emmet-vim'
"Bundle 'mbbill/fencview'
"Bundle 'tpope/vim-fugitive'
Bundle 'tpope/vim-surround'
Bundle 'tpope/vim-repeat'
"Bundle 'airblade/vim-gitgutter'
"Bundle 'nathanaelkane/vim-indent-guides'
"Bundle 'vim-scripts/JavaScript-Libraries-Syntax'
"Bundle 'scrooloose/nerdcommenter'
Bundle 'scrooloose/nerdtree'
"Bundle 'edkolev/promptline.vim'
"Bundle 'MarcWeber/vim-addon-mw-utils'
"Bundle 'tomtom/tlib_vim'
"Bundle 'garbas/vim-snipmate'
Bundle 'scrooloose/syntastic'
"Bundle 'godlygeek/tabular'
Bundle 'majutsushi/tagbar'
"Bundle 'tomtom/tlib_vim'
"Bundle 'vim-scripts/TxtBrowser'
"Bundle 'xsbeats/vim-blade'
"Bundle 'guns/vim-clojure-static'
"Bundle 'kchmck/vim-coffee-script'
"Bundle 'webfd/vim-cppstl'
"Bundle 'rhysd/vim-crystal'
"Bundle 'hail2u/vim-css3-syntax'
"Bundle 'OrangeT/vim-csharp'
"Bundle 'chrisbra/csv.vim'
"Bundle 'JesseKPhillips/d.vim'
"Bundle 'dart-lang/dart-vim-plugin'
"Bundle 'ekalinin/Dockerfile.vim'
"Bundle 'elixir-lang/vim-elixir'
"Bundle 'jimenezrick/vimerl'
"Bundle 'kongo2002/fsharp-vim'
"Bundle 'fatih/vim-go'
"Bundle 'tfnico/vim-gradle'
"Bundle 'webfd/vim-haskell'
"Bundle 'jdonaldson/vaxe'
"Bundle 'othree/html5.vim'
"Bundle 'digitaltoad/vim-jade'
"Bundle 'pangloss/vim-javascript'
"Bundle 'mitsuhiko/vim-jinja'
"Bundle 'jason0x43/vim-js-indent'
"Bundle 'leshill/vim-json'
"Bundle 'elzr/vim-json'
"Bundle 'mxw/vim-jsx'
"Bundle 'briancollins/vim-jst'
"Bundle 'JuliaLang/julia-vim'
"Bundle 'udalov/kotlin-vim'
"Bundle 'groenewege/vim-less'
"Bundle 'godlygeek/tabular'
"Bundle 'plasticboy/vim-markdown'
"Bundle 'mustache/vim-mustache-handlebars'
"Bundle 'evanmiller/nginx-vim-syntax'
"Bundle 'rgrinberg/vim-ocaml'
"Bundle 'vim-perl/vim-perl'
"Bundle 'exu/pgsql.vim'
"Bundle 'shawncplus/phpcomplete.vim'
"Bundle 'stephpy/vim-php-cs-fixer'
"Bundle '2072/PHP-Indenting-for-VIm'
"Bundle 'me-vlad/python-syntax.vim'
"Bundle 'wlangstroth/vim-racket'
"Bundle 'vim-ruby/vim-ruby'
"Bundle 'rust-lang/rust.vim'
"Bundle 'derekwyatt/vim-scala'
"Bundle 'cakebaker/scss-syntax.vim'
"Bundle 'slim-template/vim-slim.git'
"Bundle 'iakio/smarty3.vim'
"Bundle 'keith/swift.vim'
"Bundle 'evidens/vim-twig'
"Bundle 'leafgarland/typescript-vim'
"Bundle 'tkztmk/vim-vala'
"Bundle 'vimwiki/vimwiki'
"Bundle 'xwsoul/vim-zephir'
Bundle 'junegunn/fzf'
Bundle 'junegunn/fzf.vim'

syntax enable
filetype plugin indent on

if filereadable(expand("~/.vimrc.bundles.local"))
source ~/.vimrc.bundles.local
endif

filetype on

Vim实用技巧:文本编辑与处理

基数行与偶数行分组

使用Vim的替换命令,可以轻松地将基数行和偶数行分组:

1
%s/\(^.*$\)\n\(^.*$\)/\1 \2/g

然后,删除所有的基数行:

1
%s/^.*$\n\(^.*$\)/\1/g

删除重复行

在Vim中删除重复行是一个常见的操作,以下是几种方法:

删除相邻重复行

1
:g/\(.\+\)$\n\1/d

删除不相邻重复行

使用排序命令删除不相邻的重复行:

1
:sort u

删除重复行,结果按照原顺序排列

为了保存原有顺序,首先给每行加上行号和1个{

1
:let i=1|g/^/s//\=i.'{'/|let i+=1

按照行号后面的内容排序:

1
:sort /^\d\{-}/

删除行号后面的内容相同的行保留后面的行:

1
:g/^\d\{-}\{.∗$\n\d\{-}\{1$/d

按照行号恢复顺序:

1
:sort n

删除空白行

删除文件中的空白行:

1
%g/^\s*$/d

添加序号

有多种方法可以为文本添加序号:

通过let变量

1
let i=1 | g/^/s//\=i.' '/ | let i=i+1

直接使用行号

1
:g/^/ s//\=line('.').' '

使用range()函数

1
2
3
:for i in range(1, 31)
: call setline(i, i .' '. getline(i))
:endfor

利用Vim的编程支持

1
2
3
4
5
:python <<EOF
from vim import current
for i in range(len(current.buffer)):
current.buffer[i] = str(i+1) + ' ' + current.buffer[i]
EOF

外部命令

使用外部命令如findstr, sed, diff, perl, python等为文本添加序号:

1
2
3
4
5
:%!findstr /N "^"
:%!sed =|sed "N;s/\n/ /"
:%!diff --line-format=%dn%L % -
:%!perl -pe "print ++$a . ' '"
:%!python -c "import sys,fileinput as f;[sys.stdout.write(str(f.lineno())+a) for a in f.input()]"

查看文件行数、列数、字符数及所占字节大小

查看文件的行数、列数、字符数及所占字节大小:

1
g + <Ctrl-g>
0%