mirror of
https://github.com/open-webui/open-webui
synced 2025-06-26 18:26:48 +00:00
enh: contributions stats script
This commit is contained in:
parent
176a7fc986
commit
b1fb298bee
@ -1,64 +0,0 @@
|
|||||||
# Run with
|
|
||||||
# caddy run --envfile ./example.env --config ./Caddyfile.localhost
|
|
||||||
#
|
|
||||||
# This is configured for
|
|
||||||
# - Automatic HTTPS (even for localhost)
|
|
||||||
# - Reverse Proxying to Ollama API Base URL (http://localhost:11434/api)
|
|
||||||
# - CORS
|
|
||||||
# - HTTP Basic Auth API Tokens (uncomment basicauth section)
|
|
||||||
|
|
||||||
|
|
||||||
# CORS Preflight (OPTIONS) + Request (GET, POST, PATCH, PUT, DELETE)
|
|
||||||
(cors-api) {
|
|
||||||
@match-cors-api-preflight method OPTIONS
|
|
||||||
handle @match-cors-api-preflight {
|
|
||||||
header {
|
|
||||||
Access-Control-Allow-Origin "{http.request.header.origin}"
|
|
||||||
Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
|
|
||||||
Access-Control-Allow-Headers "Origin, Accept, Authorization, Content-Type, X-Requested-With"
|
|
||||||
Access-Control-Allow-Credentials "true"
|
|
||||||
Access-Control-Max-Age "3600"
|
|
||||||
defer
|
|
||||||
}
|
|
||||||
respond "" 204
|
|
||||||
}
|
|
||||||
|
|
||||||
@match-cors-api-request {
|
|
||||||
not {
|
|
||||||
header Origin "{http.request.scheme}://{http.request.host}"
|
|
||||||
}
|
|
||||||
header Origin "{http.request.header.origin}"
|
|
||||||
}
|
|
||||||
handle @match-cors-api-request {
|
|
||||||
header {
|
|
||||||
Access-Control-Allow-Origin "{http.request.header.origin}"
|
|
||||||
Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
|
|
||||||
Access-Control-Allow-Headers "Origin, Accept, Authorization, Content-Type, X-Requested-With"
|
|
||||||
Access-Control-Allow-Credentials "true"
|
|
||||||
Access-Control-Max-Age "3600"
|
|
||||||
defer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# replace localhost with example.com or whatever
|
|
||||||
localhost {
|
|
||||||
## HTTP Basic Auth
|
|
||||||
## (uncomment to enable)
|
|
||||||
# basicauth {
|
|
||||||
# # see .example.env for how to generate tokens
|
|
||||||
# {env.OLLAMA_API_ID} {env.OLLAMA_API_TOKEN_DIGEST}
|
|
||||||
# }
|
|
||||||
|
|
||||||
handle /api/* {
|
|
||||||
# Comment to disable CORS
|
|
||||||
import cors-api
|
|
||||||
|
|
||||||
reverse_proxy localhost:11434
|
|
||||||
}
|
|
||||||
|
|
||||||
# Same-Origin Static Web Server
|
|
||||||
file_server {
|
|
||||||
root ./build/
|
|
||||||
}
|
|
||||||
}
|
|
74
contribution_stats.py
Normal file
74
contribution_stats.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
|
CONFIG_FILE_EXTENSIONS = (".json", ".yml", ".yaml", ".ini", ".conf", ".toml")
|
||||||
|
|
||||||
|
|
||||||
|
def is_text_file(filepath):
|
||||||
|
# Check for binary file by scanning for null bytes.
|
||||||
|
try:
|
||||||
|
with open(filepath, "rb") as f:
|
||||||
|
chunk = f.read(4096)
|
||||||
|
if b"\0" in chunk:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def should_skip_file(path):
|
||||||
|
base = os.path.basename(path)
|
||||||
|
# Skip dotfiles and dotdirs
|
||||||
|
if base.startswith("."):
|
||||||
|
return True
|
||||||
|
# Skip config files by extension
|
||||||
|
if base.lower().endswith(CONFIG_FILE_EXTENSIONS):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_tracked_files():
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(["git", "ls-files"], text=True)
|
||||||
|
files = output.strip().split("\n")
|
||||||
|
files = [f for f in files if f and os.path.isfile(f)]
|
||||||
|
return files
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print("Error: Are you in a git repository?")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
files = get_tracked_files()
|
||||||
|
email_counter = Counter()
|
||||||
|
total_lines = 0
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
if should_skip_file(file):
|
||||||
|
continue
|
||||||
|
if not is_text_file(file):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
blame = subprocess.check_output(
|
||||||
|
["git", "blame", "-e", file], text=True, errors="replace"
|
||||||
|
)
|
||||||
|
for line in blame.splitlines():
|
||||||
|
# The email always inside <>
|
||||||
|
if "<" in line and ">" in line:
|
||||||
|
try:
|
||||||
|
email = line.split("<")[1].split(">")[0].strip()
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
email_counter[email] += 1
|
||||||
|
total_lines += 1
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for email, lines in email_counter.most_common():
|
||||||
|
percent = (lines / total_lines * 100) if total_lines else 0
|
||||||
|
print(f"{email}: {lines} {percent:.2f}%")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user