Skip to content

Commit d6d6f2e

Browse files
committed
Fix three bugs: file paths, missing Canvas URL scheme, terminal refresh
Bug 1 — FileNotFoundError (wrong output directory): - All pipeline scripts used PROJECT_DIR (/tmp AppImage mount) for data paths - Added DATA_DIR = ~/.auto_note/ when frozen, else PROJECT_DIR, to each script - downloader.py, extract_caption.py, semantic_alignment.py, note_generation.py: API key files, config.json, MANIFEST_FILE, course_dirs all use DATA_DIR - downloader.py base_dir default now uses DATA_DIR instead of PROJECT_DIR - MANIFEST_FILE in both downloader.py and extract_caption.py now in DATA_DIR Bug 2 — MissingSchema (no https:// prefix): - downloader.py loaded CANVAS_URL from PROJECT_DIR/config.json (empty in AppImage) causing Canvas("", token) → invalid URL with no scheme - Fixed: load config from DATA_DIR; auto-prefix https:// if missing Bug 3 — Terminal only refreshes on page switch: - Added self._lines.update() + time.sleep(0.02) after page.update() in OutputConsole._flush_thread so Flet event loop has time to repaint
1 parent df7472e commit d6d6f2e

5 files changed

Lines changed: 41 additions & 14 deletions

File tree

downloader.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,27 @@
3636
# ── Configuration ──────────────────────────────────────────────────────────────
3737

3838
PROJECT_DIR = Path(__file__).parent
39-
MANIFEST_FILE = PROJECT_DIR / "manifest.json"
39+
MANIFEST_FILE = None # set after DATA_DIR is resolved below
40+
41+
# When bundled as an AppImage, __file__ resolves to a temp dir deleted on exit.
42+
# Credentials and config must be read from the persistent ~/.auto_note/ directory.
43+
if getattr(sys, "frozen", False):
44+
DATA_DIR = Path.home() / ".auto_note"
45+
else:
46+
DATA_DIR = PROJECT_DIR
47+
48+
MANIFEST_FILE = DATA_DIR / "manifest.json"
4049

4150
# ── User-configurable connection settings (set via GUI Settings page) ──────────
42-
_config_file = PROJECT_DIR / "config.json"
51+
_config_file = DATA_DIR / "config.json"
4352
_config: dict = json.load(open(_config_file)) if _config_file.exists() else {}
4453

45-
CANVAS_URL = _config.get("CANVAS_URL", "")
54+
CANVAS_URL = _config.get("CANVAS_URL", "").strip().rstrip("/")
55+
if CANVAS_URL and not CANVAS_URL.startswith(("http://", "https://")):
56+
CANVAS_URL = "https://" + CANVAS_URL
4657
PANOPTO_HOST = _config.get("PANOPTO_HOST", "")
4758

48-
_canvas_token_file = PROJECT_DIR / "canvas_token.txt"
59+
_canvas_token_file = DATA_DIR / "canvas_token.txt"
4960
CANVAS_TOKEN = (
5061
_canvas_token_file.read_text().strip()
5162
if _canvas_token_file.exists() else
@@ -649,7 +660,7 @@ def _classify_with_ai(files: list[dict], course_name: str) -> list[dict]:
649660
import anthropic
650661
key = os.environ.get("ANTHROPIC_API_KEY", "")
651662
if not key:
652-
kf = PROJECT_DIR / "anthropic_key.txt"
663+
kf = DATA_DIR / "anthropic_key.txt"
653664
if kf.exists():
654665
key = kf.read_text().strip()
655666
client = anthropic.Anthropic(api_key=key)
@@ -975,7 +986,7 @@ def main() -> None:
975986
parser.print_help()
976987
sys.exit(0)
977988

978-
base_dir = Path(args.path) if args.path else PROJECT_DIR
989+
base_dir = Path(args.path) if args.path else DATA_DIR
979990
canvas = Canvas(CANVAS_URL, CANVAS_TOKEN)
980991

981992
# ── --course-list ──────────────────────────────────────────────────────────

extract_caption.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
from pathlib import Path
2424

2525
PROJECT_DIR = Path(__file__).parent
26-
MANIFEST_FILE = PROJECT_DIR / "manifest.json"
26+
if getattr(sys, "frozen", False):
27+
DATA_DIR = Path.home() / ".auto_note"
28+
else:
29+
DATA_DIR = PROJECT_DIR
30+
MANIFEST_FILE = DATA_DIR / "manifest.json"
2731

2832
# ── Tunable constants ─────────────────────────────────────────────────────────
2933

@@ -36,7 +40,7 @@
3640
_API_CHUNK_MINUTES = 60
3741

3842
# OpenAI API key: read from openai_api.txt or OPENAI_API_KEY env var
39-
_openai_key_file = PROJECT_DIR / "openai_api.txt"
43+
_openai_key_file = DATA_DIR / "openai_api.txt"
4044
_OPENAI_API_KEY = (
4145
_openai_key_file.read_text().strip()
4246
if _openai_key_file.exists() else

gui.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,9 @@ def _flush_thread() -> None:
448448
no_wrap=False, selectable=True,
449449
)
450450
)
451+
self._lines.update() # push the ListView itself
451452
self.page.update()
453+
time.sleep(0.02) # yield to Flet event loop so repaint fires
452454

453455
def _worker() -> None:
454456
try:

note_generation.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
import alignment_parser
3131

3232
PROJECT_DIR = Path(__file__).parent
33+
import sys as _sys
34+
if getattr(_sys, "frozen", False):
35+
DATA_DIR = Path.home() / ".auto_note"
36+
else:
37+
DATA_DIR = PROJECT_DIR
3338

3439
# ── Constants ─────────────────────────────────────────────────────────────────
3540

@@ -481,7 +486,7 @@ def _make_client(provider: str):
481486
from openai import OpenAI
482487
key = os.environ.get("GEMINI_API_KEY", "")
483488
if not key:
484-
kf = PROJECT_DIR / "gemini_api.txt"
489+
kf = DATA_DIR / "gemini_api.txt"
485490
if kf.exists():
486491
key = kf.read_text().strip()
487492
if not key:
@@ -494,7 +499,7 @@ def _make_client(provider: str):
494499
from anthropic import Anthropic
495500
key = os.environ.get("ANTHROPIC_API_KEY", "")
496501
if not key:
497-
kf = PROJECT_DIR / "anthropic_key.txt"
502+
kf = DATA_DIR / "anthropic_key.txt"
498503
if kf.exists():
499504
key = kf.read_text().strip()
500505
if not key:
@@ -504,7 +509,7 @@ def _make_client(provider: str):
504509
from openai import OpenAI
505510
key = os.environ.get("OPENAI_API_KEY", "")
506511
if not key:
507-
kf = PROJECT_DIR / "openai_api.txt"
512+
kf = DATA_DIR / "openai_api.txt"
508513
if kf.exists():
509514
key = kf.read_text().strip()
510515
if not key:
@@ -1295,7 +1300,7 @@ def main() -> None:
12951300
args = parser.parse_args()
12961301

12971302
if args.course:
1298-
course_dir = PROJECT_DIR / args.course
1303+
course_dir = DATA_DIR / args.course
12991304
course_name = args.course_name or f"CS{args.course}"
13001305
lectures = _discover_lectures(course_dir)
13011306
if args.lectures:

semantic_alignment.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
import numpy as np
4040

4141
PROJECT_DIR = Path(__file__).parent
42+
import sys as _sys
43+
if getattr(_sys, "frozen", False):
44+
DATA_DIR = Path.home() / ".auto_note"
45+
else:
46+
DATA_DIR = PROJECT_DIR
4247

4348
# ── Tunable knobs ─────────────────────────────────────────────────────────────
4449

@@ -84,7 +89,7 @@ def _get_openai_key() -> str:
8489
import os
8590
key = os.environ.get("OPENAI_API_KEY", "")
8691
if not key:
87-
key_file = PROJECT_DIR / "openai_api.txt"
92+
key_file = DATA_DIR / "openai_api.txt"
8893
if key_file.exists():
8994
key = key_file.read_text().strip()
9095
return key
@@ -1082,7 +1087,7 @@ def _content_match_slide_group(
10821087

10831088

10841089
def process_course(course_id: int | str) -> None:
1085-
course_dir = PROJECT_DIR / str(course_id)
1090+
course_dir = DATA_DIR / str(course_id)
10861091
captions = sorted((course_dir / "captions").glob("*.json"))
10871092
all_slides = _candidate_slides(course_dir)
10881093
out_dir = course_dir / "alignment"

0 commit comments

Comments
 (0)