feat(win): enable autostart

This commit is contained in:
arkohut 2024-10-11 22:45:20 +08:00
parent a2f488858e
commit d830b136de
15 changed files with 621961 additions and 26 deletions

31
dict/README.md Normal file
View File

@ -0,0 +1,31 @@
# CppJieba字典
文件后缀名代表的是词典的编码方式。
比如filename.utf8 是 utf8编码filename.gbk 是 gbk编码方式。
## 分词
### jieba.dict.utf8/gbk
作为最大概率法(MPSegment: Max Probability)分词所使用的词典。
### hmm_model.utf8/gbk
作为隐式马尔科夫模型(HMMSegment: Hidden Markov Model)分词所使用的词典。
__对于MixSegment(混合MPSegment和HMMSegment两者)则同时使用以上两个词典__
## 关键词抽取
### idf.utf8
IDF(Inverse Document Frequency)
在KeywordExtractor中使用的是经典的TF-IDF算法所以需要这么一个词典提供IDF信息。
### stop_words.utf8
停用词词典

34
dict/hmm_model.utf8 Normal file

File diff suppressed because one or more lines are too long

258826
dict/idf.utf8 Normal file

File diff suppressed because it is too large Load Diff

348982
dict/jieba.dict.utf8 Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,259 @@
#初始状态的概率
#格式
#状态:概率
B,a:-4.7623052146
B,ad:-6.68006603678
B,ag:-3.14e+100
B,an:-8.69708322302
B,b:-5.01837436211
B,bg:-3.14e+100
B,c:-3.42388018495
B,d:-3.97504752976
B,df:-8.88897423083
B,dg:-3.14e+100
B,e:-8.56355183039
B,en:-3.14e+100
B,f:-5.49163041848
B,g:-3.14e+100
B,h:-13.53336513
B,i:-6.11578472756
B,in:-3.14e+100
B,j:-5.05761912847
B,jn:-3.14e+100
B,k:-3.14e+100
B,l:-4.90588358466
B,ln:-3.14e+100
B,m:-3.6524299819
B,mg:-3.14e+100
B,mq:-6.7869530014
B,n:-1.69662577975
B,ng:-3.14e+100
B,nr:-2.23104959138
B,nrfg:-5.87372217541
B,nrt:-4.98564273352
B,ns:-2.8228438315
B,nt:-4.84609166818
B,nz:-3.94698846058
B,o:-8.43349870215
B,p:-4.20098413209
B,q:-6.99812385896
B,qe:-3.14e+100
B,qg:-3.14e+100
B,r:-3.40981877908
B,rg:-3.14e+100
B,rr:-12.4347528413
B,rz:-7.94611647157
B,s:-5.52267359084
B,t:-3.36474790945
B,tg:-3.14e+100
B,u:-9.1639172775
B,ud:-3.14e+100
B,ug:-3.14e+100
B,uj:-3.14e+100
B,ul:-3.14e+100
B,uv:-3.14e+100
B,uz:-3.14e+100
B,v:-2.67405848743
B,vd:-9.04472876024
B,vg:-3.14e+100
B,vi:-12.4347528413
B,vn:-4.33156108902
B,vq:-12.1470707689
B,w:-3.14e+100
B,x:-3.14e+100
B,y:-9.84448567586
B,yg:-3.14e+100
B,z:-7.04568111149
B,zg:-3.14e+100
E,a:-3.14e+100
E,ad:-3.14e+100
E,ag:-3.14e+100
E,an:-3.14e+100
E,b:-3.14e+100
E,bg:-3.14e+100
E,c:-3.14e+100
E,d:-3.14e+100
E,df:-3.14e+100
E,dg:-3.14e+100
E,e:-3.14e+100
E,en:-3.14e+100
E,f:-3.14e+100
E,g:-3.14e+100
E,h:-3.14e+100
E,i:-3.14e+100
E,in:-3.14e+100
E,j:-3.14e+100
E,jn:-3.14e+100
E,k:-3.14e+100
E,l:-3.14e+100
E,ln:-3.14e+100
E,m:-3.14e+100
E,mg:-3.14e+100
E,mq:-3.14e+100
E,n:-3.14e+100
E,ng:-3.14e+100
E,nr:-3.14e+100
E,nrfg:-3.14e+100
E,nrt:-3.14e+100
E,ns:-3.14e+100
E,nt:-3.14e+100
E,nz:-3.14e+100
E,o:-3.14e+100
E,p:-3.14e+100
E,q:-3.14e+100
E,qe:-3.14e+100
E,qg:-3.14e+100
E,r:-3.14e+100
E,rg:-3.14e+100
E,rr:-3.14e+100
E,rz:-3.14e+100
E,s:-3.14e+100
E,t:-3.14e+100
E,tg:-3.14e+100
E,u:-3.14e+100
E,ud:-3.14e+100
E,ug:-3.14e+100
E,uj:-3.14e+100
E,ul:-3.14e+100
E,uv:-3.14e+100
E,uz:-3.14e+100
E,v:-3.14e+100
E,vd:-3.14e+100
E,vg:-3.14e+100
E,vi:-3.14e+100
E,vn:-3.14e+100
E,vq:-3.14e+100
E,w:-3.14e+100
E,x:-3.14e+100
E,y:-3.14e+100
E,yg:-3.14e+100
E,z:-3.14e+100
E,zg:-3.14e+100
M,a:-3.14e+100
M,ad:-3.14e+100
M,ag:-3.14e+100
M,an:-3.14e+100
M,b:-3.14e+100
M,bg:-3.14e+100
M,c:-3.14e+100
M,d:-3.14e+100
M,df:-3.14e+100
M,dg:-3.14e+100
M,e:-3.14e+100
M,en:-3.14e+100
M,f:-3.14e+100
M,g:-3.14e+100
M,h:-3.14e+100
M,i:-3.14e+100
M,in:-3.14e+100
M,j:-3.14e+100
M,jn:-3.14e+100
M,k:-3.14e+100
M,l:-3.14e+100
M,ln:-3.14e+100
M,m:-3.14e+100
M,mg:-3.14e+100
M,mq:-3.14e+100
M,n:-3.14e+100
M,ng:-3.14e+100
M,nr:-3.14e+100
M,nrfg:-3.14e+100
M,nrt:-3.14e+100
M,ns:-3.14e+100
M,nt:-3.14e+100
M,nz:-3.14e+100
M,o:-3.14e+100
M,p:-3.14e+100
M,q:-3.14e+100
M,qe:-3.14e+100
M,qg:-3.14e+100
M,r:-3.14e+100
M,rg:-3.14e+100
M,rr:-3.14e+100
M,rz:-3.14e+100
M,s:-3.14e+100
M,t:-3.14e+100
M,tg:-3.14e+100
M,u:-3.14e+100
M,ud:-3.14e+100
M,ug:-3.14e+100
M,uj:-3.14e+100
M,ul:-3.14e+100
M,uv:-3.14e+100
M,uz:-3.14e+100
M,v:-3.14e+100
M,vd:-3.14e+100
M,vg:-3.14e+100
M,vi:-3.14e+100
M,vn:-3.14e+100
M,vq:-3.14e+100
M,w:-3.14e+100
M,x:-3.14e+100
M,y:-3.14e+100
M,yg:-3.14e+100
M,z:-3.14e+100
M,zg:-3.14e+100
S,a:-3.90253968313
S,ad:-11.0484584802
S,ag:-6.95411391796
S,an:-12.8402179494
S,b:-6.47288876397
S,bg:-3.14e+100
S,c:-4.78696679586
S,d:-3.90391976418
S,df:-3.14e+100
S,dg:-8.9483976513
S,e:-5.94251300628
S,en:-3.14e+100
S,f:-5.19482024998
S,g:-6.50782681533
S,h:-8.65056320738
S,i:-3.14e+100
S,in:-3.14e+100
S,j:-4.91199211964
S,jn:-3.14e+100
S,k:-6.94032059583
S,l:-3.14e+100
S,ln:-3.14e+100
S,m:-3.26920065212
S,mg:-10.8253149289
S,mq:-3.14e+100
S,n:-3.85514838976
S,ng:-4.9134348611
S,nr:-4.48366310396
S,nrfg:-3.14e+100
S,nrt:-3.14e+100
S,ns:-3.14e+100
S,nt:-12.1470707689
S,nz:-3.14e+100
S,o:-8.46446092775
S,p:-2.98684018136
S,q:-4.88865861826
S,qe:-3.14e+100
S,qg:-3.14e+100
S,r:-2.76353367841
S,rg:-10.2752685919
S,rr:-3.14e+100
S,rz:-3.14e+100
S,s:-3.14e+100
S,t:-3.14e+100
S,tg:-6.27284253188
S,u:-6.94032059583
S,ud:-7.72823016105
S,ug:-7.53940370266
S,uj:-6.85251045118
S,ul:-8.41537131755
S,uv:-8.15808672229
S,uz:-9.29925862537
S,v:-3.05329230341
S,vd:-3.14e+100
S,vg:-5.94301818437
S,vi:-3.14e+100
S,vn:-11.4539235883
S,vq:-3.14e+100
S,w:-3.14e+100
S,x:-8.42741965607
S,y:-6.19707946995
S,yg:-13.53336513
S,z:-3.14e+100
S,zg:-3.14e+100

File diff suppressed because it is too large Load Diff

1534
dict/stop_words.utf8 Normal file

File diff suppressed because it is too large Load Diff

4
dict/user.dict.utf8 Normal file
View File

@ -0,0 +1,4 @@
云计算
韩玉鉴赏
蓝翔 nz
区块链 10 nz

View File

@ -1,7 +1,7 @@
import os import os
import logging import logging
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime, timedelta
import httpx import httpx
import typer import typer
@ -19,6 +19,7 @@ import subprocess
import platform import platform
from .cmds.plugin import plugin_app, bind from .cmds.plugin import plugin_app, bind
from .cmds.library import lib_app, scan, index, watch from .cmds.library import lib_app, scan, index, watch
import psutil
app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]}) app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
@ -228,19 +229,28 @@ def get_memos_dir():
def generate_windows_bat(): def generate_windows_bat():
memos_dir = get_memos_dir() memos_dir = get_memos_dir()
python_path = get_python_path() python_path = get_python_path()
pythonw_path = python_path.replace("python.exe", "pythonw.exe")
conda_prefix = os.environ.get("CONDA_PREFIX") conda_prefix = os.environ.get("CONDA_PREFIX")
log_dir = memos_dir / "logs"
log_dir.mkdir(parents=True, exist_ok=True)
if conda_prefix: if conda_prefix:
# If we're in a Conda environment # If we're in a Conda environment
activate_path = os.path.join(conda_prefix, "Scripts", "activate.bat") activate_path = os.path.join(conda_prefix, "Scripts", "activate.bat")
content = f"""@echo off content = f"""@echo off
call "{activate_path}" call "{activate_path}"
start "Memos" cmd /c ""{python_path}" -m memos.commands record & "{python_path}" -m memos.commands serve & timeout /t 5 /nobreak >nul & "{python_path}" -m memos.commands watch" start /B "" "{pythonw_path}" -m memos.commands record > "{log_dir / 'record.log'}" 2>&1
start /B "" "{pythonw_path}" -m memos.commands serve > "{log_dir / 'serve.log'}" 2>&1
timeout /t 5 /nobreak >nul
start /B "" "{pythonw_path}" -m memos.commands watch > "{log_dir / 'watch.log'}" 2>&1
""" """
else: else:
# If we're not in a Conda environment, use the original content # If we're not in a Conda environment
content = f"""@echo off content = f"""@echo off
start "Memos" cmd /c ""{python_path}" -m memos.commands record & "{python_path}" -m memos.commands serve & timeout /t 5 /nobreak >nul & "{python_path}" -m memos.commands watch" start /B "" "{pythonw_path}" -m memos.commands record > "{log_dir / 'record.log'}" 2>&1
start /B "" "{pythonw_path}" -m memos.commands serve > "{log_dir / 'serve.log'}" 2>&1
timeout /t 5 /nobreak >nul
start /B "" "{pythonw_path}" -m memos.commands watch > "{log_dir / 'watch.log'}" 2>&1
""" """
bat_path = memos_dir / "launch.bat" bat_path = memos_dir / "launch.bat"
@ -291,6 +301,7 @@ def setup_windows_autostart(bat_path):
shortcut = shell.CreateShortCut(str(shortcut_path)) shortcut = shell.CreateShortCut(str(shortcut_path))
shortcut.Targetpath = str(bat_path) shortcut.Targetpath = str(bat_path)
shortcut.WorkingDirectory = str(bat_path.parent) shortcut.WorkingDirectory = str(bat_path.parent)
shortcut.WindowStyle = 7 # Minimized
shortcut.save() shortcut.save()
@ -364,6 +375,46 @@ def is_windows():
return platform.system() == "Windows" return platform.system() == "Windows"
def remove_windows_autostart():
startup_folder = Path(os.getenv("APPDATA")) / r"Microsoft\Windows\Start Menu\Programs\Startup"
shortcut_path = startup_folder / "Memos.lnk"
if shortcut_path.exists():
shortcut_path.unlink()
return True
return False
@app.command()
def disable():
"""Disable memos from running at startup"""
if is_windows():
if remove_windows_autostart():
typer.echo("Removed Memos shortcut from startup folder. Memos will no longer run at startup.")
else:
typer.echo("Memos shortcut not found in startup folder. Memos is not set to run at startup.")
elif is_macos():
plist_path = Path.home() / "Library/LaunchAgents/com.user.memos.plist"
if plist_path.exists():
user_domain = f"gui/{os.getuid()}"
service_name = "com.user.memos"
if is_service_loaded(service_name):
subprocess.run(
["launchctl", "bootout", user_domain, str(plist_path)], check=False
)
typer.echo("Unloaded Memos service.")
else:
typer.echo("Memos service was not running.")
plist_path.unlink()
typer.echo("Removed plist file. Memos will no longer run at startup.")
else:
typer.echo("Plist file does not exist. Memos is not set to run at startup.")
else:
typer.echo("Unsupported operating system.")
@app.command() @app.command()
def enable(): def enable():
"""Enable memos to run at startup""" """Enable memos to run at startup"""
@ -391,29 +442,27 @@ def enable():
@app.command() @app.command()
def disable(): def ps():
"""Disable memos from running at startup""" """Show the status of Memos processes"""
if not is_macos(): services = ["serve", "watch", "record"]
typer.echo("Error: This feature is only supported on macOS.")
raise typer.Exit(code=1)
plist_path = Path.home() / "Library/LaunchAgents/com.user.memos.plist" for service in services:
if plist_path.exists(): processes = [p for p in psutil.process_iter(['pid', 'name', 'cmdline', 'create_time'])
user_domain = f"gui/{os.getuid()}" if 'python' in p.info['name'].lower() and
service_name = "com.user.memos" 'memos.commands' in p.info['cmdline'] and
service in p.info['cmdline']]
if is_service_loaded(service_name): if processes:
subprocess.run( for process in processes:
["launchctl", "bootout", user_domain, str(plist_path)], check=False create_time = datetime.fromtimestamp(process.info['create_time']).strftime('%Y-%m-%d %H:%M:%S')
) running_time = str(timedelta(seconds=int(time.time() - process.info['create_time'])))
typer.echo("Unloaded Memos service.") typer.echo(f"{service.capitalize()} is running:")
typer.echo(f" PID: {process.info['pid']}")
typer.echo(f" Started at: {create_time}")
typer.echo(f" Running for: {running_time}")
else: else:
typer.echo("Memos service was not running.") typer.echo(f"{service.capitalize()} is not running")
typer.echo("---")
plist_path.unlink()
typer.echo("Removed plist file. Memos will no longer run at startup.")
else:
typer.echo("Plist file does not exist. Memos is not set to run at startup.")
if __name__ == "__main__": if __name__ == "__main__":

55
memos/process_webp.py Normal file
View File

@ -0,0 +1,55 @@
from pathlib import Path
from PIL import Image
import piexif
import json
from memos.utils import write_image_metadata, get_image_metadata
from tqdm import tqdm
def convert_webp_metadata(directory):
webp_files = list(Path(directory).glob('**/*.webp'))
for webp_file in tqdm(webp_files, desc="Converting WebP metadata", unit="file"):
try:
# Try to get metadata using the new method
new_metadata = get_image_metadata(webp_file)
if new_metadata:
tqdm.write(f"Skipping {webp_file}: Already in new format")
continue
# If new method fails, try to get old metadata
img = Image.open(webp_file)
old_metadata = img.info.get("exif", None)
if old_metadata is None:
tqdm.write(f"Skipping {webp_file}: No metadata found")
continue
if isinstance(old_metadata, bytes):
try:
old_metadata = old_metadata.decode('utf-8')
except UnicodeDecodeError:
tqdm.write(f"Skipping {webp_file}: Unable to decode metadata")
continue
try:
metadata = json.loads(old_metadata)
except json.JSONDecodeError:
tqdm.write(f"Skipping {webp_file}: Invalid metadata format")
continue
# Convert to new format
write_image_metadata(webp_file, metadata)
tqdm.write(f"Converted metadata for {webp_file}")
except Exception as e:
tqdm.write(f"Error processing {webp_file}: {str(e)}")
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print("Usage: python convert_webp_metadata.py <directory>")
sys.exit(1)
directory = sys.argv[1]
convert_webp_metadata(directory)

19
memos/t.py Normal file
View File

@ -0,0 +1,19 @@
import typer
from rich import print
data = {
"name": "Rick",
"age": 42,
"items": [{"name": "Portal Gun"}, {"name": "Plumbus"}],
"active": True,
"affiliation": None,
}
def main():
print("Here's the data")
print(data)
if __name__ == "__main__":
typer.run(main)

101
memos/watchfiles.py Normal file
View File

@ -0,0 +1,101 @@
import os
import time
import sys
import argparse
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
# 定义图片文件扩展名
IMAGE_EXTENSIONS = (".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp")
class ImageHandler(FileSystemEventHandler):
def __init__(self):
self.last_modified = {}
def is_image_file(self, path):
return path.lower().endswith(IMAGE_EXTENSIONS)
def is_temp_file(self, path):
filename = os.path.basename(path)
return (
filename.startswith(".")
or filename.startswith("tmp")
or filename.startswith("temp")
)
def handle_event(self, event):
if (
not event.is_directory
and self.is_image_file(event.src_path)
and not self.is_temp_file(event.src_path)
):
current_time = time.time()
last_modified_time = self.last_modified.get(event.src_path, 0)
if current_time - last_modified_time > 1: # 防止重复触发
self.last_modified[event.src_path] = current_time
return True
return False
def on_modified(self, event):
if self.handle_event(event):
print(f"Image file modified: {event.src_path}")
def on_created(self, event):
if self.handle_event(event):
print(f"Image file created: {event.src_path}")
def on_deleted(self, event):
if self.handle_event(event):
print(f"Image file deleted: {event.src_path}")
def watch_folders(folders, recursive):
event_handler = ImageHandler()
observer = Observer()
# 监听多个文件夹
for folder in folders:
observer.schedule(event_handler, folder, recursive=recursive)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
# main 函数保持不变
def main():
parser = argparse.ArgumentParser(
description="Watch for image file changes in specified folders."
)
parser.add_argument(
"folders",
metavar="FOLDER",
type=str,
nargs="+",
help="One or more folders to watch for image file changes.",
)
parser.add_argument(
"-r",
"--recursive",
action="store_true",
help="Watch folders recursively (may impact performance for large directories).",
)
args = parser.parse_args()
# 确认所有提供的目录都存在
for folder in args.folders:
if not os.path.isdir(folder):
print(f"Error: {folder} is not a valid directory.")
sys.exit(1)
watch_folders(args.folders, args.recursive)
if __name__ == "__main__":
main()

BIN
simple.dll Normal file

Binary file not shown.