本地化部署笔记服务: AFFiNE,并启用AI支持(不需要购买AFFiNE付费服务)

最近几个月用Obsidian让我有点头痛,因为以下的问题让我开始找适合自己使用习惯的新软件和服务:

  1. 每次需要快速更改内容的时候总是会反复去调整Markdown,在调整的过程中并不美观,有时候我只想写一些简易的文字内容;而且需要用鼠标点击切换才会显示为预览/阅读模式,太累了! :tieba_008:

  2. 保存方案是使用WebDAV通过内网穿透存到家里的All in boom里面,我选择的是基于Wireguard的易有云,两年期不算很贵(买的时候似乎是¥199两年)但是我在切换代理的时候就需要通过浏览器访问认证页面,认证保留时间只有24h,也即每天都需要登录一次,才能打开笔记并同步回我的存储,太麻烦了! :tieba_016:

  3. 我需要使用AI进行内容优化,万一也需要写代码什么的呢?于是买了一个月Notion。Notion对于纯文字内容的优化能力是很强的,但是价格放在那里,能少花钱就少花钱不是?Obsidian插件的话又不够快捷好用, 我除了Ctrl+C/Ctrl+V和截图之外的快捷键一向是不想去记的 :tieba_003:如果能支持我用鼠标选中唤醒那不是更快更好吗?


部署AFFiNE

访问项目的页面AFFiNE往下即可看到Self Hosted相关内容,你只需要安装docker和docker compose即可。

在首次部署时,会自动生成AFFiNE的环境配置文件,默认路径在

/root/.affine/self-host/config/affine.js

这个文件中往下找,修改这段,记得末尾的括号要前后匹配,不要漏了

AFFiNE.use('copilot', {
  openai: {
    baseURL: 'https://API代理网址/v1',
    apiKey: '你的Key',
  },
# 后面的fal api可以不管,如果你只需要对话功能
# 末尾的括号解注释
})

然后重启整个应用,你就可以在浏览器中访问你搭建的AFFiNE服务,使用AI帮忙编辑你的笔记了。(这里选择让AI帮忙翻译一下)

翻译的消耗量,在这里也简单统计下(用的是去年玩的一个代理站,额度还剩好多没消耗完,放着也是浪费 :tieba_003:

同样,你也可以选择调用本地的AI服务,最好用one-api转换为通用统一的,因为我尝试把供应换成claude就报错了。没有多尝试,有兴趣的可以多试试其它模型。

我在Issue里看了一下,后面开发团队说是会慢慢测试支持各种模型,拭目以待吧。

虽然自建是通过浏览器访问编辑,但是AFFiNE支持批量导入MarkDown、导入HTML和Notion。 :tieba_002:


如果你自建完成,登录准备编辑后发现一直有个让你开启云同步的红色提示,那么就开启它,没关系的,你并不会自动创建一个云账号担心你的内容被同步上去。实在不放心的话,你就在你的服务器上做一个限制吧。 :tieba_024:

一定要创建并开启云空间同步,你的笔记才能保存在自建服务器上哦~


在我优化+测试的过程中,我发现了如果按照默认情况来配置AFFiNE,用户会遇到AI请求限制的问题,以及工作区创建限制。 :tieba_016:有点鸡贼,我一边改数据库一边恼火。

考察了一下Issue,AFFiNE使用的数据库是 PostgreSQL 解决各类使用限制的方案如下:

进入你的PostgreSQL容器

docker exec -it affine_postgres psql -U affine

执行select命令,你就可以看到权限对应的ID和说明。别忘记了末尾有分号。

affine=# select id, feature, configs from features;
---
 id |       feature        |                                                                             configs                                                                             
----+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------
  1 | copilot              | {}
  2 | early_access         | {"whitelist":["@toeverything.info"]}
  3 | early_access         | {"whitelist":[]}
  4 | unlimited_workspace  | {}
  5 | unlimited_copilot    | {}
  6 | ai_early_access      | {}
  7 | administrator        | {}
  8 | free_plan_v1         | {"name":"Free","blobLimit":10485760,"storageQuota":10737418240,"historyPeriod":604800000,"memberLimit":3}
  9 | pro_plan_v1          | {"name":"Pro","blobLimit":104857600,"storageQuota":107374182400,"historyPeriod":2592000000,"memberLimit":10}
 10 | restricted_plan_v1   | {"name":"Restricted","blobLimit":1048576,"storageQuota":10485760,"historyPeriod":2592000000,"memberLimit":10}
 11 | free_plan_v1         | {"name":"Free","blobLimit":104857600,"storageQuota":10737418240,"historyPeriod":604800000,"memberLimit":3}
 12 | free_plan_v1         | {"name":"Free","blobLimit":10485760,"businessBlobLimit":104857600,"storageQuota":10737418240,"historyPeriod":604800000,"memberLimit":3}
 13 | free_plan_v1         | {"name":"Free","blobLimit":10485760,"businessBlobLimit":104857600,"storageQuota":10737418240,"historyPeriod":604800000,"memberLimit":3,"copilotActionLimit":10}
 14 | pro_plan_v1          | {"name":"Pro","blobLimit":104857600,"storageQuota":107374182400,"historyPeriod":2592000000,"memberLimit":10,"copilotActionLimit":10}
 15 | restricted_plan_v1   | {"name":"Restricted","blobLimit":1048576,"storageQuota":10485760,"historyPeriod":2592000000,"memberLimit":10,"copilotActionLimit":10}
 16 | lifetime_pro_plan_v1 | {"name":"Lifetime Pro","blobLimit":104857600,"storageQuota":1099511627776,"historyPeriod":2592000000,"memberLimit":10,"copilotActionLimit":10}
(16 rows)

那么为了解除AI请求限制、创建工作区限制和协作人员数量限制,你可以选择在权限表里添加序号为"4、5、16"来提权。

insert into user_features (id,user_id,feature_id,reason,activated) values (3,'3eae2420-77a6-45b1-b2ec-d2be829752a8',4,'AI request unlimited','t');
---
# 执行这个命令,你就能看到所有用户对应的权限了
select * from user_features;
---
# reason这个项可以随便写,因为是记录权限描述的项,所以我很随意的复制粘贴了
 id |               user_id                | feature_id |   reason   |         created_at         | expired_at | activated 
----+--------------------------------------+------------+------------+----------------------------+------------+-----------
  2 | 3eae2420-77a6-45b1-b2ec-d2be829752a8 |          7 | Admin user | 2024-09-11 09:19:02.565+00 |            | t
  1 | 3eae2420-77a6-45b1-b2ec-d2be829752a8 |         16 | sign up    | 2024-09-11 09:19:02.556+00 |            | t
  3 | 3eae2420-77a6-45b1-b2ec-d2be829752a8 |          4 | sign up    | 2024-09-11 09:28:04.837+00 |            | t
  4 | 3eae2420-77a6-45b1-b2ec-d2be829752a8 |          5 | sign up    | 2024-09-11 09:28:22.998+00 |            | t
(4 rows)

依照刚才的操作,现在你已经可以无限次请求AI了

那么成员数如何修改呢?

# 更新权限表里的描述
# 修改memberLimit
affine=# update features set configs = '{"name":"Lifetime Pro","blobLimit":104857600,"storageQuota":1099511627776,"historyPeriod":2592000000,"memberLimit":1000,"copilotActionLimit":10}' where id = 16;

所有的操作完成后,重启PostgreSQL即可

docker restart affine_postgres

成功咯! :tieba_003:


接下来就是如何处理网页版无法复制粘贴内容的问题

你在实现了基础的部署后,会发现操作内容时,只能从电脑粘贴内容到AFFiNE里,却无法从AFFiNE拷贝内容到剪贴板上。

这是因为AFFiNE前端代码里面指定了必须要通过HTTPS来实现完整的复制粘贴功能【我也不知道他们怎么想的】那么这里就有两种方案了

  1. 使用Docker-reverse-proxy这个项目来实现反向代理【依照文档里的步骤来即可,很简单】,避开申请证书的步骤,但是仍需要使用域名来访问,你可能需要加静态解析
  2. DDNS/Nginx或其他服务,将AFFiNE的端口代理出来。这就可能需要你有一个自己的域名,或者稍微折腾下DDNS了。

如果已经实现了内网穿透,而你不想使用域名访问,只想使用HTTPS+IP,那么可以用nginx如下步骤实现正常的同步、复制粘贴。

生成证书和key【这里选择APT安装nginx了,懒得用Docker把配置文件挂在主机上】

openssl genrsa -out /etc/nginx/ssl.key 2048
openssl req -new -key /etc/nginx/ssl.key -out /etc/nginx/ssl.csr
openssl x509 -req -days 1460 -in /etc/nginx/ssl.csr -signkey /etc/nginx/ssl.key -out /etc/nginx/ssl.crt

# Nginx配置
ssl_certificate /etc/nginx/ssl.crt;
ssl_certificate_key /etc/nginx/ssl.key;
ssl_session_timeout 30m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

允许WebSocket通信【不然你会发现访问的时候一直无法载入】

location / {    
    proxy_pass http://127.0.0.1:3010;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
}
235 个赞

让我想到了一个meme

22 个赞

哈哈,如果我是苹果系用户,感觉就不会那么折腾,库克全给包干了
因为最近发现用AI比较多,所以想找个快捷一点的

2 个赞

可惜沒有多用戶功能

3 个赞

有的
部署好之后你访问你配置的端口,会进入默认的管理员注册界面
在那里开放用户注册即可

1 个赞

我上年部署的時候,是沒有多用戶的,我今晚部署看看先 :tieba_066:

2 个赞

嗯,我觉得也可以等等官方支持其他模型,直接用客户端,更方便些

嘿嘿 我就是苹果系用户
不过我现在还是在用notion 感觉也挺方便的 比如说写学习笔记的时候可以分章节
apple intelligence还没用过 :tieba_019:

2 个赞

感谢大佬教程

6 个赞

notion的AI很强,我有时候写东西,写个一两句就让它续写去了
就是太贵啦

2 个赞

大帅哥从早八水到下班,太猛了

1 个赞

app支持自建登录吗

2 个赞

不行呢,APP登录只能使用注册到官方服务器的账号
自建只能使用浏览器【PC/手机均可】
或者用Nativefier打包个exe用

1 个赞

这比 Trilium Notes就差一点了, Trilium 支持离线编辑,不过也没有安卓端,不然将是绝杀

感谢分享,又多了一个选择tieba_003

2 个赞

我把优化操作添加上去了,佬友可以再看一下哈

7 个赞

赞一个,最近在整理之前obs的笔记,又乱又杂,刚好有这个需求!

2 个赞

感谢佬友
不过要注意AFFiNE自建,内容是暂时存在浏览器缓存的
我晚上或者明天看看如何实现存储至本地

5 个赞

我也是苹果用户,快把佬所知道的AI分享一下 :cowboy_hat_face:

感谢分享,先插个眼,等更新再看

1 个赞