2026-01-08 00:44:25 +08:00
|
|
|
"""
|
|
|
|
|
Sync OpenWebUI Post IDs to local plugin files
|
|
|
|
|
同步远程插件 ID 到本地文件
|
|
|
|
|
"""
|
|
|
|
|
|
2026-01-08 00:10:47 +08:00
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
import re
|
|
|
|
|
import difflib
|
|
|
|
|
|
|
|
|
|
# Add current directory to path
|
|
|
|
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
|
|
2026-01-08 00:44:25 +08:00
|
|
|
from openwebui_community_client import get_client
|
|
|
|
|
|
2026-01-08 00:10:47 +08:00
|
|
|
try:
|
|
|
|
|
from extract_plugin_versions import scan_plugins_directory
|
|
|
|
|
except ImportError:
|
2026-01-08 00:44:25 +08:00
|
|
|
print("Error: extract_plugin_versions.py not found.")
|
2026-01-08 00:10:47 +08:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def normalize(s):
|
|
|
|
|
if not s:
|
|
|
|
|
return ""
|
|
|
|
|
return re.sub(r"\s+", " ", s.lower().strip())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def insert_id_into_file(file_path, post_id):
|
|
|
|
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
|
|
|
lines = f.readlines()
|
|
|
|
|
|
|
|
|
|
new_lines = []
|
|
|
|
|
inserted = False
|
|
|
|
|
in_frontmatter = False
|
|
|
|
|
|
|
|
|
|
for line in lines:
|
|
|
|
|
# Check for start/end of frontmatter
|
|
|
|
|
if line.strip() == '"""':
|
|
|
|
|
if not in_frontmatter:
|
|
|
|
|
in_frontmatter = True
|
|
|
|
|
else:
|
|
|
|
|
# End of frontmatter
|
|
|
|
|
in_frontmatter = False
|
|
|
|
|
|
|
|
|
|
# Check if ID already exists
|
|
|
|
|
if in_frontmatter and (
|
|
|
|
|
line.strip().startswith("openwebui_id:")
|
|
|
|
|
or line.strip().startswith("post_id:")
|
|
|
|
|
):
|
|
|
|
|
print(f" ID already exists in {os.path.basename(file_path)}")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
new_lines.append(line)
|
|
|
|
|
|
|
|
|
|
# Insert after version
|
|
|
|
|
if in_frontmatter and not inserted and line.strip().startswith("version:"):
|
|
|
|
|
new_lines.append(f"openwebui_id: {post_id}\n")
|
|
|
|
|
inserted = True
|
|
|
|
|
|
|
|
|
|
if inserted:
|
|
|
|
|
with open(file_path, "w", encoding="utf-8") as f:
|
|
|
|
|
f.writelines(new_lines)
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
2026-01-08 00:44:25 +08:00
|
|
|
try:
|
|
|
|
|
client = get_client()
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
print(f"Error: {e}")
|
2026-01-08 00:10:47 +08:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
2026-01-08 00:44:25 +08:00
|
|
|
print("Fetching remote posts from OpenWebUI Community...")
|
2026-01-08 00:10:47 +08:00
|
|
|
remote_posts = client.get_all_posts()
|
|
|
|
|
print(f"Fetched {len(remote_posts)} remote posts.")
|
|
|
|
|
|
|
|
|
|
plugins_dir = os.path.join(
|
|
|
|
|
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "plugins"
|
|
|
|
|
)
|
|
|
|
|
local_plugins = scan_plugins_directory(plugins_dir)
|
|
|
|
|
print(f"Found {len(local_plugins)} local plugins.")
|
|
|
|
|
|
|
|
|
|
matched_count = 0
|
|
|
|
|
|
|
|
|
|
for plugin in local_plugins:
|
|
|
|
|
local_title = plugin.get("title", "")
|
|
|
|
|
if not local_title:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
file_path = plugin.get("file_path")
|
|
|
|
|
best_match = None
|
|
|
|
|
highest_ratio = 0.0
|
|
|
|
|
|
|
|
|
|
# 1. Try Exact Match on Manifest Title (High Confidence)
|
|
|
|
|
for post in remote_posts:
|
|
|
|
|
manifest_title = (
|
|
|
|
|
post.get("data", {})
|
|
|
|
|
.get("function", {})
|
|
|
|
|
.get("meta", {})
|
|
|
|
|
.get("manifest", {})
|
|
|
|
|
.get("title")
|
|
|
|
|
)
|
|
|
|
|
if manifest_title and normalize(manifest_title) == normalize(local_title):
|
|
|
|
|
best_match = post
|
|
|
|
|
highest_ratio = 1.0
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
# 2. Try Fuzzy Match on Post Title if no exact match
|
|
|
|
|
if not best_match:
|
|
|
|
|
for post in remote_posts:
|
|
|
|
|
post_title = post.get("title", "")
|
|
|
|
|
ratio = difflib.SequenceMatcher(
|
|
|
|
|
None, normalize(local_title), normalize(post_title)
|
|
|
|
|
).ratio()
|
|
|
|
|
if ratio > 0.8 and ratio > highest_ratio:
|
|
|
|
|
highest_ratio = ratio
|
|
|
|
|
best_match = post
|
|
|
|
|
|
|
|
|
|
if best_match:
|
|
|
|
|
post_id = best_match.get("id")
|
|
|
|
|
post_title = best_match.get("title")
|
|
|
|
|
print(
|
|
|
|
|
f"Match found: '{local_title}' <--> '{post_title}' (ID: {post_id}) [Score: {highest_ratio:.2f}]"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if insert_id_into_file(file_path, post_id):
|
|
|
|
|
print(f" -> Updated {os.path.basename(file_path)}")
|
|
|
|
|
matched_count += 1
|
|
|
|
|
else:
|
|
|
|
|
print(f"No match found for: '{local_title}'")
|
|
|
|
|
|
|
|
|
|
print(f"\nTotal updated: {matched_count}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|