Spaces:
Sleeping
Sleeping
[feat] first commit
Browse files- .gitignore +2 -0
- About.md +1 -0
- app.py +179 -0
- requirements.txt +4 -0
- src/schema.py +13 -0
- src/skill_db.py +98 -0
- src/tools.py +31 -0
.gitignore
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
venv/
|
2 |
+
__pycache__/
|
About.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
# Skill Library Hub
|
app.py
ADDED
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import List
|
2 |
+
import streamlit as st
|
3 |
+
import extra_streamlit_components as stx
|
4 |
+
from streamlit_searchbox import st_searchbox
|
5 |
+
from pathlib import Path
|
6 |
+
from streamlit_tags import st_tags
|
7 |
+
from src.tools import hf_pull_skill, time_ago
|
8 |
+
from src.skill_db import SkillsDB
|
9 |
+
from src.schema import Skill
|
10 |
+
st.title("Skill Library Hub")
|
11 |
+
|
12 |
+
skill_db = SkillsDB('skills.db')
|
13 |
+
all_skills = skill_db.get_skills()
|
14 |
+
|
15 |
+
all_tags = skill_db.get_tags()
|
16 |
+
|
17 |
+
if all_skills is None:
|
18 |
+
all_skills = []
|
19 |
+
|
20 |
+
def search(searchterm: str) -> List[any]:
|
21 |
+
global all_skills
|
22 |
+
global skill_db
|
23 |
+
if all_skills is None:
|
24 |
+
if skill_db is None:
|
25 |
+
skill_db = SkillsDB('skills.db')
|
26 |
+
all_skills = skill_db.get_skills()
|
27 |
+
result = []
|
28 |
+
if all_skills is not None and len(all_skills) > 0:
|
29 |
+
for skill in all_skills:
|
30 |
+
if searchterm.lower() in skill.skill_name.lower():
|
31 |
+
result.append(skill.skill_name.lower())
|
32 |
+
if searchterm.lower() in skill.author.lower():
|
33 |
+
result.append(skill.author.lower())
|
34 |
+
if len(result)>10:
|
35 |
+
return result
|
36 |
+
if len(result)<3:
|
37 |
+
for skill in all_skills:
|
38 |
+
if searchterm.lower() in skill.skill_description.lower():
|
39 |
+
result.append(skill.skill_description.lower())
|
40 |
+
if len(result)>10:
|
41 |
+
return result
|
42 |
+
return result
|
43 |
+
return result
|
44 |
+
|
45 |
+
program_languages = ["python", "r", "julia", "javascript", "html", "shell", "applescript"]
|
46 |
+
|
47 |
+
def main_page():
|
48 |
+
global all_skills
|
49 |
+
global skill_db
|
50 |
+
if all_skills is None:
|
51 |
+
if skill_db is None:
|
52 |
+
skill_db = SkillsDB('skills.db')
|
53 |
+
all_skills = skill_db.get_skills()
|
54 |
+
|
55 |
+
selected_languages = []
|
56 |
+
selected_tags = []
|
57 |
+
with st.sidebar:
|
58 |
+
st.title("🎈 Search Skills")
|
59 |
+
with st.expander("✨ PROGRAM", True):
|
60 |
+
if st.checkbox("Python"):
|
61 |
+
selected_languages.append("python")
|
62 |
+
if st.checkbox("Julia"):
|
63 |
+
selected_languages.append("julia")
|
64 |
+
if st.checkbox("R"):
|
65 |
+
selected_languages.append("r")
|
66 |
+
if st.checkbox("Javascript"):
|
67 |
+
selected_languages.append("javascript")
|
68 |
+
if st.checkbox("Html"):
|
69 |
+
selected_languages.append("html")
|
70 |
+
if st.checkbox("Shell"):
|
71 |
+
selected_languages.append("shell")
|
72 |
+
if st.checkbox("AppleScript"):
|
73 |
+
selected_languages.append("applescript")
|
74 |
+
|
75 |
+
with st.expander("🔖 TAGS", True):
|
76 |
+
if all_tags is not None:
|
77 |
+
for tag in all_tags:
|
78 |
+
if st.checkbox(tag):
|
79 |
+
selected_tags.append(tag)
|
80 |
+
|
81 |
+
if not selected_languages:
|
82 |
+
selected_languages = program_languages
|
83 |
+
|
84 |
+
all_skills = [item for item in all_skills if item.skill_program_language in selected_languages]
|
85 |
+
|
86 |
+
if not selected_tags and all_tags:
|
87 |
+
selected_tags = all_tags
|
88 |
+
all_skills = [item for item in all_skills if set(item.skill_tags) & set(selected_tags)]
|
89 |
+
|
90 |
+
selected_value = st_searchbox(
|
91 |
+
search,
|
92 |
+
key="",
|
93 |
+
)
|
94 |
+
|
95 |
+
print(f"selected_value: {selected_value}")
|
96 |
+
selected_skills = all_skills
|
97 |
+
if selected_value is None and len(selected_skills)!= len(all_skills):
|
98 |
+
selected_skills = all_skills
|
99 |
+
|
100 |
+
if selected_value is not None:
|
101 |
+
all_skills = [item for item in all_skills if selected_value.lower() in item.skill_name.lower() or
|
102 |
+
selected_value.lower() in item.author.lower() or
|
103 |
+
selected_value.lower() in item.skill_description.lower()]
|
104 |
+
|
105 |
+
if all_skills is not None and len(all_skills) > 0:
|
106 |
+
for skill in all_skills:
|
107 |
+
with st.expander(f"{skill.author}/{skill.skill_name}", expanded=True):
|
108 |
+
tags = "`{}`".format("`\t\t`".join(skill.skill_tags))
|
109 |
+
st.markdown(f"{tags}")
|
110 |
+
st.markdown(f"**<a href='https://huggingface.co/spaces/{skill.repo_id}?page=detail_page&skill_name={skill.skill_name}' style='font-size: 22px;' target='_self'>{skill.author}/{skill.skill_name}</a>**", unsafe_allow_html=True)
|
111 |
+
st.markdown(f">**{skill.skill_description}**")
|
112 |
+
st.markdown("Install:")
|
113 |
+
install = f"import creator\ncreator.create(huggingface_repo_id=\"{skill.repo_id}\", huggingface_skill_path=\"{skill.skill_name}\")"
|
114 |
+
st.code(install, language=skill.skill_program_language)
|
115 |
+
st.markdown("Usage:")
|
116 |
+
usage = f"{skill.skill_usage_example}"
|
117 |
+
if skill.skill_program_language.lower() == "python":
|
118 |
+
usage = f"from {skill.repo_id.replace('/', '.')}.skill_code import {skill.skill_name}\n"+usage
|
119 |
+
st.code(usage, language=skill.skill_program_language)
|
120 |
+
st.markdown(f"`Created {time_ago(skill.created_at)}` `{skill.skill_program_language}`")
|
121 |
+
else:
|
122 |
+
st.markdown(f"### 🎉 Search results for `{selected_value}`")
|
123 |
+
st.markdown(f"**No results found**")
|
124 |
+
|
125 |
+
def about_page():
|
126 |
+
file_path = "About.md"
|
127 |
+
with open(file_path, 'r', encoding='utf-8') as file:
|
128 |
+
content = file.read()
|
129 |
+
st.write(content, unsafe_allow_html=True)
|
130 |
+
|
131 |
+
def submit_page():
|
132 |
+
global all_skills
|
133 |
+
global skill_db
|
134 |
+
if all_skills is None:
|
135 |
+
if skill_db is None:
|
136 |
+
skill_db = SkillsDB('skills.db')
|
137 |
+
all_skills = skill_db.get_skills()
|
138 |
+
st.markdown(f"### ✉️✨ Submit your skill here!")
|
139 |
+
with st.form(key='my_form'):
|
140 |
+
skill_repository = st.text_input('Skill Repo Id:')
|
141 |
+
skill_names = st_tags(
|
142 |
+
label="Skills' name:",
|
143 |
+
text='Press enter to add every skill folder',
|
144 |
+
value=[],
|
145 |
+
suggestions=[],
|
146 |
+
maxtags = 10,
|
147 |
+
key='1')
|
148 |
+
|
149 |
+
if st.form_submit_button('Submit'):
|
150 |
+
skills = []
|
151 |
+
if skill_names is not None and len(skill_names) > 0:
|
152 |
+
for skill_name in skill_names:
|
153 |
+
skill = hf_pull_skill(skill_repository, skill_name)
|
154 |
+
skill["repo_id"] = skill_repository
|
155 |
+
skills.append(skill)
|
156 |
+
|
157 |
+
if skills is not None and len(skills) > 0:
|
158 |
+
for skill in skills:
|
159 |
+
if skill is not None:
|
160 |
+
if skill not in all_skills:
|
161 |
+
skill_obj = Skill(skill["repo_id"], skill["skill_name"], skill["skill_description"], skill["skill_metadata"]["author"], skill["skill_metadata"]["created_at"], skill["skill_usage_example"], skill["skill_program_language"], skill["skill_tags"])
|
162 |
+
result = skill_db.add_skill(skill_obj)
|
163 |
+
if result != "ok":
|
164 |
+
st.error(result)
|
165 |
+
continue
|
166 |
+
all_skills.append(skill_obj)
|
167 |
+
|
168 |
+
chosen_id = stx.tab_bar(data=[
|
169 |
+
stx.TabBarItemData(id=1, title="🏅 Skill Library", description=""),
|
170 |
+
stx.TabBarItemData(id=2, title="📝 About", description=""),
|
171 |
+
stx.TabBarItemData(id=3, title="🚀 Submit here!", description=""),
|
172 |
+
], default=1)
|
173 |
+
|
174 |
+
if chosen_id == '1':
|
175 |
+
main_page()
|
176 |
+
elif chosen_id == '2':
|
177 |
+
about_page()
|
178 |
+
elif chosen_id == '3':
|
179 |
+
submit_page()
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit-searchbox
|
2 |
+
extra_streamlit_components
|
3 |
+
streamlit-tags
|
4 |
+
huggingface_hub
|
src/schema.py
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class Skill:
|
2 |
+
def __init__(self, repo_id, skill_name, skill_description, author, created_at, skill_usage_example, skill_program_language, skill_tags):
|
3 |
+
self.repo_id = repo_id
|
4 |
+
self.skill_name = skill_name
|
5 |
+
self.skill_description = skill_description
|
6 |
+
self.author = author
|
7 |
+
self.created_at = created_at
|
8 |
+
self.skill_usage_example = skill_usage_example
|
9 |
+
self.skill_program_language = skill_program_language
|
10 |
+
self.skill_tags = skill_tags
|
11 |
+
|
12 |
+
def __str__(self) -> str:
|
13 |
+
return f"Skill: repo_id: {self.repo_id}, name: {self.skill_name}, description: {self.skill_description}, author: {self.author}, created_at: {self.created_at}, skill_usage_example: {self.skill_usage_example}, skill_program_language: {self.skill_program_language}, skill_tags: {self.skill_tags}"
|
src/skill_db.py
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sqlite3
|
2 |
+
import os
|
3 |
+
from src.schema import Skill
|
4 |
+
|
5 |
+
class SkillsDB:
|
6 |
+
def __init__(self, db_name="skills.db"):
|
7 |
+
# Check if the database file exists
|
8 |
+
db_exists = os.path.exists(db_name)
|
9 |
+
|
10 |
+
# Connect to the database
|
11 |
+
self.conn = sqlite3.connect(db_name)
|
12 |
+
self.cursor = self.conn.cursor()
|
13 |
+
|
14 |
+
# If the database file didn't exist before, create and initialize the database
|
15 |
+
if not db_exists:
|
16 |
+
self.create_db()
|
17 |
+
|
18 |
+
def create_db(self):
|
19 |
+
# Create skill table
|
20 |
+
self.cursor.execute('''
|
21 |
+
CREATE TABLE IF NOT EXISTS skills (
|
22 |
+
id INTEGER PRIMARY KEY,
|
23 |
+
repo_id TEXT NOT NULL,
|
24 |
+
skill_name TEXT NOT NULL,
|
25 |
+
skill_description TEXT,
|
26 |
+
author TEXT,
|
27 |
+
created_at TEXT,
|
28 |
+
skill_usage_example TEXT,
|
29 |
+
skill_program_language TEXT,
|
30 |
+
skill_tags TEXT
|
31 |
+
);
|
32 |
+
''')
|
33 |
+
|
34 |
+
# Create tags table
|
35 |
+
self.cursor.execute('''
|
36 |
+
CREATE TABLE IF NOT EXISTS tags (
|
37 |
+
id INTEGER PRIMARY KEY,
|
38 |
+
tag TEXT NOT NULL UNIQUE
|
39 |
+
);
|
40 |
+
''')
|
41 |
+
|
42 |
+
self.conn.commit()
|
43 |
+
|
44 |
+
def add_skill(self, skill):
|
45 |
+
self.cursor.execute('SELECT id FROM skills WHERE skill_name = ? AND author = ?;', (skill.skill_name, skill.author))
|
46 |
+
if self.cursor.fetchone() is not None:
|
47 |
+
return f"Skill with name '{skill.skill_name}' by author '{skill.author}' already exists!"
|
48 |
+
# Handle tags: check if they exist; if not, insert them
|
49 |
+
tag_ids = []
|
50 |
+
for tag in skill.skill_tags:
|
51 |
+
self.cursor.execute('SELECT id FROM tags WHERE tag = ?;', (tag,))
|
52 |
+
tag_id = self.cursor.fetchone()
|
53 |
+
if tag_id is None:
|
54 |
+
self.cursor.execute('INSERT INTO tags (tag) VALUES (?);', (tag,))
|
55 |
+
tag_id = self.cursor.lastrowid
|
56 |
+
else:
|
57 |
+
tag_id = tag_id[0]
|
58 |
+
tag_ids.append(str(tag_id))
|
59 |
+
tags_str = ",".join(tag_ids)
|
60 |
+
|
61 |
+
# Insert skill into skills table
|
62 |
+
self.cursor.execute('''
|
63 |
+
INSERT INTO skills (repo_id, skill_name, skill_description, author, created_at, skill_usage_example, skill_program_language, skill_tags)
|
64 |
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
65 |
+
''', (skill.repo_id, skill.skill_name, skill.skill_description, skill.author, skill.created_at, skill.skill_usage_example, skill.skill_program_language, tags_str))
|
66 |
+
|
67 |
+
self.conn.commit()
|
68 |
+
return "ok"
|
69 |
+
|
70 |
+
def get_skills(self):
|
71 |
+
# Fetch all skills from the skills table along with column names
|
72 |
+
self.cursor.execute('SELECT * FROM skills;')
|
73 |
+
col_names = [col[0] for col in self.cursor.description]
|
74 |
+
skills_data = self.cursor.fetchall()
|
75 |
+
|
76 |
+
# Extract data using column names and create Skill objects
|
77 |
+
skills = []
|
78 |
+
for skill_data in skills_data:
|
79 |
+
skill_dict = dict(zip(col_names, skill_data))
|
80 |
+
tag_ids = skill_dict['skill_tags'].split(',')
|
81 |
+
self.cursor.execute('SELECT tag FROM tags WHERE id IN (%s);' % ','.join(['?'] * len(tag_ids)), tag_ids)
|
82 |
+
tags = [tag[0] for tag in self.cursor.fetchall()]
|
83 |
+
skill_obj = Skill(skill_dict['repo_id'], skill_dict['skill_name'], skill_dict['skill_description'], skill_dict['author'],
|
84 |
+
skill_dict['created_at'], skill_dict['skill_usage_example'], skill_dict['skill_program_language'], tags)
|
85 |
+
skills.append(skill_obj)
|
86 |
+
|
87 |
+
return skills
|
88 |
+
|
89 |
+
def get_tags(self):
|
90 |
+
# Fetch all tags from the tags table
|
91 |
+
self.cursor.execute('SELECT tag FROM tags;')
|
92 |
+
tags = self.cursor.fetchall()
|
93 |
+
if tags is not None:
|
94 |
+
return [tag[0] for tag in tags]
|
95 |
+
return []
|
96 |
+
|
97 |
+
def close(self):
|
98 |
+
self.conn.close()
|
src/tools.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
from huggingface_hub import hf_hub_download
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
def hf_pull_skill(repo_id, huggingface_skill_path):
|
6 |
+
return_path = hf_hub_download(repo_id=repo_id, subfolder=huggingface_skill_path, repo_type="space", filename="skill.json")
|
7 |
+
with open(return_path) as f:
|
8 |
+
skill_json = json.load(f)
|
9 |
+
return skill_json
|
10 |
+
|
11 |
+
def time_ago(updated_at_str):
|
12 |
+
now = datetime.now()
|
13 |
+
updated_at = datetime.strptime(updated_at_str, '%Y-%m-%d %H:%M:%S')
|
14 |
+
delta = now - updated_at
|
15 |
+
|
16 |
+
minutes = delta.total_seconds() / 60
|
17 |
+
hours = minutes / 60
|
18 |
+
days = hours / 24
|
19 |
+
months = days / 30.44 # An average month length
|
20 |
+
years = days / 365.25 # Account for leap years
|
21 |
+
|
22 |
+
if minutes < 60:
|
23 |
+
return f"{int(minutes)} minutes ago"
|
24 |
+
elif hours < 24:
|
25 |
+
return f"{int(hours)} hours ago"
|
26 |
+
elif days < 30.44:
|
27 |
+
return f"{int(days)} days ago"
|
28 |
+
elif months < 12:
|
29 |
+
return f"{int(months)} months ago"
|
30 |
+
else:
|
31 |
+
return f"{int(years)} years ago"
|