Rel timestamps, center caption
This commit is contained in:
parent
72ace3dc09
commit
d09378811d
59
tools.py
59
tools.py
@ -16,6 +16,8 @@ def format_relative_time(timestamp: float) -> str:
|
|||||||
now = time.time()
|
now = time.time()
|
||||||
diff = now - timestamp
|
diff = now - timestamp
|
||||||
seconds = int(diff)
|
seconds = int(diff)
|
||||||
|
if seconds < 0:
|
||||||
|
return "In the future"
|
||||||
if seconds < 60:
|
if seconds < 60:
|
||||||
return "Just now"
|
return "Just now"
|
||||||
minutes = seconds // 60
|
minutes = seconds // 60
|
||||||
@ -27,11 +29,11 @@ def format_relative_time(timestamp: float) -> str:
|
|||||||
days = hours // 24
|
days = hours // 24
|
||||||
if days == 1:
|
if days == 1:
|
||||||
return "Yesterday"
|
return "Yesterday"
|
||||||
if days < 7:
|
if days < 30:
|
||||||
return f"{days}d ago"
|
return f"{days}d ago"
|
||||||
weeks = days // 7
|
months = days // 30
|
||||||
if weeks < 4:
|
if months < 12:
|
||||||
return f"{weeks}w ago"
|
return f"{months}mo ago"
|
||||||
dt = datetime.datetime.fromtimestamp(timestamp)
|
dt = datetime.datetime.fromtimestamp(timestamp)
|
||||||
return dt.strftime('%Y-%m-%d')
|
return dt.strftime('%Y-%m-%d')
|
||||||
|
|
||||||
@ -166,7 +168,6 @@ async def list_thumbnails_handler(args: Dict[str, Any]):
|
|||||||
x = padding + col * (thumb_size + padding)
|
x = padding + col * (thumb_size + padding)
|
||||||
y = padding + row * (thumb_size + label_height + padding)
|
y = padding + row * (thumb_size + label_height + padding)
|
||||||
|
|
||||||
# Continuous numbering across pages
|
|
||||||
global_index = start_idx + i + 1
|
global_index = start_idx + i + 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -178,11 +179,17 @@ async def list_thumbnails_handler(args: Dict[str, Any]):
|
|||||||
canvas.paste(img, (x + off_x, y + off_y))
|
canvas.paste(img, (x + off_x, y + off_y))
|
||||||
|
|
||||||
mod_time_rel = format_relative_time(info["mtime"])
|
mod_time_rel = format_relative_time(info["mtime"])
|
||||||
size_kb = info["size"] / 1024
|
file_details.append(f"{global_index}. {filename} | {width}x{height} | {mod_time_rel}")
|
||||||
file_details.append(f"{global_index}. {filename} | {width}x{height} | {size_kb:.1f}KB | {mod_time_rel}")
|
|
||||||
|
|
||||||
text = str(global_index)
|
text = str(global_index)
|
||||||
draw.text((x + 2, y + thumb_size + 2), text, fill=(255, 255, 255), font=font)
|
if font:
|
||||||
|
bbox = draw.textbbox((0, 0), text, font=font)
|
||||||
|
text_w = bbox[2] - bbox[0]
|
||||||
|
else:
|
||||||
|
text_w = len(text) * 7
|
||||||
|
|
||||||
|
text_x = x + (thumb_size - text_w) // 2
|
||||||
|
draw.text((text_x, y + thumb_size + 2), text, fill=(255, 255, 255), font=font)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to process {filename}: {e}")
|
logger.error(f"Failed to process {filename}: {e}")
|
||||||
@ -207,6 +214,7 @@ async def list_directory_details_handler(args: Dict[str, Any]):
|
|||||||
path = args.get("path")
|
path = args.get("path")
|
||||||
page = int(args.get("page", 1))
|
page = int(args.get("page", 1))
|
||||||
page_size = int(args.get("page_size", 64))
|
page_size = int(args.get("page_size", 64))
|
||||||
|
sort_by = args.get("sort_by", "mtime")
|
||||||
|
|
||||||
if not path:
|
if not path:
|
||||||
return {"text": "Error: Missing path argument"}
|
return {"text": "Error: Missing path argument"}
|
||||||
@ -234,7 +242,9 @@ async def list_directory_details_handler(args: Dict[str, Any]):
|
|||||||
"type": "dir",
|
"type": "dir",
|
||||||
"name": entry,
|
"name": entry,
|
||||||
"info": f"{count} items",
|
"info": f"{count} items",
|
||||||
"mtime": mtime_rel
|
"mtime": mtime_rel,
|
||||||
|
"mtime_raw": stats.st_mtime,
|
||||||
|
"size": stats.st_size
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
size_kb = stats.st_size / 1024
|
size_kb = stats.st_size / 1024
|
||||||
@ -242,16 +252,33 @@ async def list_directory_details_handler(args: Dict[str, Any]):
|
|||||||
"type": "file",
|
"type": "file",
|
||||||
"name": entry,
|
"name": entry,
|
||||||
"info": f"{size_kb:.1f}KB",
|
"info": f"{size_kb:.1f}KB",
|
||||||
"mtime": mtime_rel
|
"mtime": mtime_rel,
|
||||||
|
"mtime_raw": stats.st_mtime,
|
||||||
|
"size": stats.st_size
|
||||||
})
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Could not stat {entry}: {e}")
|
logger.error(f"Could not stat {entry}: {e}")
|
||||||
|
|
||||||
all_items.sort(key=lambda x: (x["type"] == "file", x["name"].lower()))
|
if sort_by == "mtime":
|
||||||
|
all_items.sort(key=lambda x: (x["type"] == "file", -x["mtime_raw"]))
|
||||||
|
elif sort_by == "size":
|
||||||
|
all_items.sort(key=lambda x: (x["type"] == "file", -x["size"]))
|
||||||
|
else:
|
||||||
|
all_items.sort(key=lambda x: (x["type"] == "file", x["name"].lower()))
|
||||||
|
|
||||||
total_items = len(all_items)
|
total_items = len(all_items)
|
||||||
start_idx = (page - 1) * page_size
|
|
||||||
end_idx = start_idx + page_size
|
if total_items <= 100:
|
||||||
|
start_idx = 0
|
||||||
|
end_idx = total_items
|
||||||
|
effective_page = 1
|
||||||
|
total_pages = 1
|
||||||
|
else:
|
||||||
|
start_idx = (page - 1) * page_size
|
||||||
|
end_idx = start_idx + page_size
|
||||||
|
total_pages = (total_items + page_size - 1) // page_size
|
||||||
|
effective_page = page
|
||||||
|
|
||||||
paged_items = all_items[start_idx:end_idx]
|
paged_items = all_items[start_idx:end_idx]
|
||||||
|
|
||||||
if not paged_items:
|
if not paged_items:
|
||||||
@ -264,8 +291,7 @@ async def list_directory_details_handler(args: Dict[str, Any]):
|
|||||||
else:
|
else:
|
||||||
output.append(f" {item['name']} | {item['info']} | {item['mtime']}")
|
output.append(f" {item['name']} | {item['info']} | {item['mtime']}")
|
||||||
|
|
||||||
total_pages = (total_items + page_size - 1) // page_size
|
header = f"Listing of {path}\nPage {effective_page} of {total_pages} ({total_items} total items). Showing {start_idx+1}-{min(end_idx, total_items)}."
|
||||||
header = f"Listing of {path}\nPage {page} of {total_pages} ({total_items} total items). Showing {start_idx+1}-{min(end_idx, total_items)}."
|
|
||||||
|
|
||||||
return {"text": f"{header}\n\n" + "\n".join(output)}
|
return {"text": f"{header}\n\n" + "\n".join(output)}
|
||||||
|
|
||||||
@ -307,13 +333,14 @@ TOOL_REGISTRY = [
|
|||||||
),
|
),
|
||||||
Tool(
|
Tool(
|
||||||
name="list_directory",
|
name="list_directory",
|
||||||
description="Lists the contents of a directory in a file browser format. Directories first, then files. Supports pagination.",
|
description="Lists the contents of a directory in a file browser format. Directories first, then files. Supports pagination and sorting.",
|
||||||
schema={
|
schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"path": {"type": "string", "description": "Path to the directory to list"},
|
"path": {"type": "string", "description": "Path to the directory to list"},
|
||||||
"page": {"type": "integer", "description": "The page number to retrieve (1-indexed)", "default": 1},
|
"page": {"type": "integer", "description": "The page number to retrieve (1-indexed)", "default": 1},
|
||||||
"page_size": {"type": "integer", "description": "Number of items per page", "default": 64},
|
"page_size": {"type": "integer", "description": "Number of items per page", "default": 64},
|
||||||
|
"sort_by": {"type": "string", "description": "Sort order: 'mtime' (newest first, default), 'name' (alphabetical), or 'size' (largest first)", "default": "mtime"},
|
||||||
},
|
},
|
||||||
"required": ["path"],
|
"required": ["path"],
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user