Add accent color, email subjects, MD+DOCX outputs, update README
This commit is contained in:
@@ -29,11 +29,16 @@ For more information: https://apstrom.ca
|
||||
- Jobs are queued and processed in the background (Celery + Redis).
|
||||
- Emails:
|
||||
- Immediate confirmation with queue position.
|
||||
- Final transcript (TXT + JSON) when ready.
|
||||
- Final transcript (MD + JSON) when ready.
|
||||
- Summary as MD file (if requested).
|
||||
- Error notification if processing fails.
|
||||
- File formats:
|
||||
- Transcript: .md and .docx
|
||||
- Summary (if requested): .md and .docx
|
||||
- Full structured output: .json
|
||||
- Customizable branding:
|
||||
- Web GUI title, logo, and email logo via environment variables.
|
||||
- Web GUI title, logo, and accent color via environment variables.
|
||||
- Email logo, accent color, and subject lines via environment variables.
|
||||
- CLI and Python API:
|
||||
- Simple command-line interface.
|
||||
- Drop-in Scraibe class for integration into other tools.
|
||||
@@ -74,6 +79,7 @@ Run the container with your LocalAI and summarizer endpoints:
|
||||
-e WEBUI_TITLE="Your Transcription Service" \
|
||||
-e WEBUI_LOGO_URL="https://your-domain.com/logo.png" \
|
||||
-e EMAIL_LOGO_URL="https://your-domain.com/logo.png" \
|
||||
-e EMAIL_ACCENT_COLOR="#7C6DA0" \
|
||||
scraibe:latest
|
||||
|
||||
Then open: http://<host>:7860
|
||||
@@ -195,6 +201,14 @@ Web GUI and branding:
|
||||
- URL of the logo displayed in the web GUI header.
|
||||
- Example: https://your-domain.com/logo.png
|
||||
|
||||
Accent color (UI and emails):
|
||||
|
||||
- EMAIL_ACCENT_COLOR:
|
||||
- Accent color used in:
|
||||
- Web GUI buttons and accents
|
||||
- Email headings, links, and email addresses
|
||||
- Default: #7C6DA0
|
||||
|
||||
Async processing (Celery + Redis):
|
||||
|
||||
- CELERY_BROKER_URL:
|
||||
@@ -227,6 +241,30 @@ Email configuration:
|
||||
- EMAIL_CSS_PATH:
|
||||
- Path to the CSS used in emails (default: /app/src/misc/mail_style.css).
|
||||
|
||||
Email subject lines (customizable):
|
||||
|
||||
- EMAIL_SUBJECT_UPLOAD:
|
||||
- Subject for upload confirmation email.
|
||||
- Default: "ScrAIbe: Your transcription request has been received"
|
||||
- EMAIL_SUBJECT_SUCCESS:
|
||||
- Subject for transcript-ready email.
|
||||
- Default: "ScrAIbe: Your transcript is ready"
|
||||
- EMAIL_SUBJECT_ERROR:
|
||||
- Subject for error notification email.
|
||||
- Default: "ScrAIbe: Error with your transcription request"
|
||||
|
||||
Output files (async web GUI):
|
||||
|
||||
When a job completes, the user receives:
|
||||
- Transcript:
|
||||
- .md file
|
||||
- .docx file
|
||||
- Summary (if requested):
|
||||
- .md file
|
||||
- .docx file
|
||||
- JSON:
|
||||
- Structured transcript with diarization and metadata
|
||||
|
||||
All of these can also be overridden from the CLI when needed (e.g., --localai-api-url, --summarizer-api-url).
|
||||
|
||||
## Dependencies
|
||||
@@ -240,6 +278,7 @@ Core runtime dependencies:
|
||||
- gradio
|
||||
- celery[redis]
|
||||
- redis
|
||||
- python-docx
|
||||
- ffmpeg (for audio preprocessing)
|
||||
|
||||
No local Whisper, PyTorch, or Pyannote models are required.
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
<body>
|
||||
<div class="container">
|
||||
{email_logo}
|
||||
<h1>Error Notification</h1>
|
||||
<h1 style="color:{accent_color};">Error Notification</h1>
|
||||
<p>Dear user,</p>
|
||||
<p>An error occurred while processing your audio file. This means that something went wrong during the processing of your file, and it could not be completed successfully.</p>
|
||||
<p class="error-message">Error details: {exception}</p>
|
||||
<p>Please check the file and try again. If the problem persists, our support team is here to help.</p>
|
||||
<div class="contact">
|
||||
<p>You can contact our support team at <a href="mailto:{contact_email}">{contact_email}</a>. They are available to assist with any questions or issues you may have.</p>
|
||||
<p>You can contact our support team at <a href="mailto:{contact_email}" style="color:{accent_color};">{contact_email}</a>. They are available to assist with any questions or issues you may have.</p>
|
||||
</div>
|
||||
<div class="disclaimer">
|
||||
<p>Please note that our support team does not have the ability to fix processing errors directly or access the files you have uploaded. They can provide guidance and help troubleshoot any issues you may encounter.</p>
|
||||
|
||||
+4
-4
@@ -43,7 +43,7 @@
|
||||
text-align: left;
|
||||
}}
|
||||
.footer a {{
|
||||
color: #333;
|
||||
color: {accent_color};
|
||||
transition: color 0.3s ease;
|
||||
}}
|
||||
.footer a:hover {{
|
||||
@@ -79,7 +79,7 @@
|
||||
font-size: 24px;
|
||||
}}
|
||||
.brand-icon a:hover, .brand-icon a:focus {{
|
||||
background-color: #50AF31;
|
||||
background-color: {accent_color};
|
||||
transform: scale(1.1);
|
||||
text-decoration: none;
|
||||
}}
|
||||
@@ -98,11 +98,11 @@
|
||||
|
||||
<div class="footer">
|
||||
<div class="foot-text">
|
||||
<h2 style="font-weight: bold; color: #7C6DA0;">Disclaimer</h2>
|
||||
<h2 style="font-weight: bold; color: {accent_color};">Disclaimer</h2>
|
||||
<p>The transcription completed by this application may contain errors.</p>
|
||||
<p>Users must take care to review transcripts before circulating to ensure that they are error-free and complete.</p>
|
||||
<p>The transcripts produced by this application do not replace a court reporter's transcription. The transcripts completed by this application are for the user's convenience only.</p>
|
||||
<h2 style="font-weight: bold; color: #7C6DA0;">Data retention</h2>
|
||||
<h2 style="font-weight: bold; color: {accent_color};">Data retention</h2>
|
||||
<p>Audio or video files uploaded to this application are only retained for the time that it takes to complete the transcription. All transcripts are deleted after they are transmitted to the user.</p>
|
||||
</div>
|
||||
<div class="brand-section">
|
||||
|
||||
+3
-3
@@ -34,7 +34,7 @@
|
||||
font-family: 'Cormorant Garamond', serif;
|
||||
font-size: 50px !important;
|
||||
font-weight: bold;
|
||||
color: #7C6DA0;
|
||||
color: {accent_color};
|
||||
margin: 0;
|
||||
position: relative;
|
||||
padding: 0.5em 0;
|
||||
@@ -45,7 +45,7 @@
|
||||
position: absolute;
|
||||
height: 2px;
|
||||
width: 80%;
|
||||
background-color: #7C6DA0;
|
||||
background-color: {accent_color};
|
||||
left: 10%;
|
||||
}}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<p>
|
||||
Upload, record, or provide a video with audio for transcription. Our toolkit is designed to transcribe content from multiple languages accurately. The integrated speaker diarisation feature identifies different speakers, ensuring a smooth transcription experience. For optimal results, indicate the number of speakers and the original language of the content.
|
||||
</p>
|
||||
<h2 style="font-weight: bold; color: #7C6DA0;">Start your transcription below.</h2>
|
||||
<h2 style="font-weight: bold; color: {accent_color};">Start your transcription below.</h2>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-2
@@ -14,9 +14,10 @@ body {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
h1 {
|
||||
h1, h2, h3 {
|
||||
font-size: 1.5em;
|
||||
margin-top: 0;
|
||||
color: {accent_color};
|
||||
}
|
||||
p {
|
||||
margin: 10px 0;
|
||||
@@ -39,12 +40,15 @@ p {
|
||||
color: #555;
|
||||
}
|
||||
.contact a {
|
||||
color: #0056b3;
|
||||
color: {accent_color};
|
||||
text-decoration: none;
|
||||
}
|
||||
.contact a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
a {
|
||||
color: {accent_color};
|
||||
}
|
||||
.disclaimer {
|
||||
margin-top: 20px;
|
||||
font-size: 0.8em;
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
<body>
|
||||
<div class="container">
|
||||
{email_logo}
|
||||
<h1>Transcript Ready</h1>
|
||||
<h1 style="color:{accent_color};">Transcript Ready</h1>
|
||||
<p>Dear user,</p>
|
||||
<p>Your file has been successfully processed, and the transcript is now ready. The transcript of your audio or video file is attached to this email.</p>
|
||||
<p>We hope you find the transcript useful. If you have any questions or need further assistance, please do not hesitate to contact our support team.</p>
|
||||
<div class="contact">
|
||||
<p>You can reach our support team at <a href="mailto:{contact_email}">{contact_email}</a>. They are available to help with any questions or issues you may have.</p>
|
||||
<p>You can reach our support team at <a href="mailto:{contact_email}" style="color:{accent_color};">{contact_email}</a>. They are available to help with any questions or issues you may have.</p>
|
||||
</div>
|
||||
<div class="disclaimer">
|
||||
<p>Please note that our support team cannot modify the content of the transcript. They can assist with any other questions or concerns you may have.</p>
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
<body>
|
||||
<div class="container">
|
||||
{email_logo}
|
||||
<h1>Upload Successful</h1>
|
||||
<h1 style="color:{accent_color};">Upload Successful</h1>
|
||||
<p>Dear user,</p>
|
||||
<p>Your file has been successfully uploaded and is now in our processing queue. This means that our system has received your file, and it is waiting to be processed. We will handle your file as soon as possible.</p>
|
||||
<p class="success-message">Your current position in the queue is: {queue_position}. This is the order in which your file will be processed. We appreciate your patience as we work through the queue.</p>
|
||||
<p>We will notify you once your file has been processed. If you have any urgent needs or further questions, feel free to reach out to our support team.</p>
|
||||
<div class="contact">
|
||||
<p>You can contact our support team at <a href="mailto:{contact_email}">{contact_email}</a>. Please note that our support team is here to help with any questions or issues you might have.</p>
|
||||
<p>You can contact our support team at <a href="mailto:{contact_email}" style="color:{accent_color};">{contact_email}</a>. Please note that our support team is here to help with any questions or issues you might have.</p>
|
||||
</div>
|
||||
<div class="disclaimer">
|
||||
<p>Please note that our support team does not have the ability to change your position in the queue or access the files you have uploaded. They are here to provide assistance and answer any questions you might have about the process.</p>
|
||||
|
||||
@@ -5,3 +5,4 @@ gradio>=5.0.0
|
||||
PyYAML>=6.0
|
||||
celery[redis]>=5.3.0
|
||||
redis>=5.0.0
|
||||
python-docx>=1.1.0
|
||||
|
||||
+68
-14
@@ -68,25 +68,40 @@ def _email_logo_html() -> str:
|
||||
"""
|
||||
Return logo HTML for emails.
|
||||
|
||||
Priority:
|
||||
1) EMAIL_LOGO_URL (direct URL to logo image)
|
||||
2) EMAIL_LOGO_PATH (local file; embedded as base64)
|
||||
3) empty string if neither is set.
|
||||
- Priority:
|
||||
1) EMAIL_LOGO_URL (direct URL)
|
||||
2) EMAIL_LOGO_PATH (local file as base64)
|
||||
- Size: max 200% of line height (small).
|
||||
"""
|
||||
logo_url = os.getenv("EMAIL_LOGO_URL")
|
||||
if logo_url:
|
||||
return f'<img src="{logo_url}" alt="Logo" style="max-width:180px; display:block; margin:0 auto 10px auto;"/>'
|
||||
src = logo_url
|
||||
|
||||
logo_path = os.getenv("EMAIL_LOGO_PATH", "/app/src/misc/logo1.png")
|
||||
if not os.path.exists(logo_path):
|
||||
if not logo_url:
|
||||
logo_path = os.getenv("EMAIL_LOGO_PATH", "/app/src/misc/logo1.png")
|
||||
if os.path.exists(logo_path):
|
||||
try:
|
||||
with open(logo_path, "rb") as f:
|
||||
b64 = base64.b64encode(f.read()).decode("utf-8")
|
||||
src = f"data:image/png;base64,{b64}"
|
||||
except Exception:
|
||||
src = None
|
||||
|
||||
if not src:
|
||||
return ""
|
||||
|
||||
try:
|
||||
with open(logo_path, "rb") as f:
|
||||
b64 = base64.b64encode(f.read()).decode("utf-8")
|
||||
return f'<img src="data:image/png;base64,{b64}" alt="Logo" style="max-width:180px; display:block; margin:0 auto 10px auto;"/>'
|
||||
except Exception:
|
||||
return ""
|
||||
# max-height limited to 200% of line height (approx 2em)
|
||||
return (
|
||||
f'<img src="{src}" alt="Logo" '
|
||||
f'style="max-height:2em; width:auto; display:block; margin:0 auto 0.5em auto;" />'
|
||||
)
|
||||
|
||||
|
||||
def _accent_color() -> str:
|
||||
"""
|
||||
Accent color for UI and emails.
|
||||
Default: #7C6DA0
|
||||
"""
|
||||
return os.getenv("EMAIL_ACCENT_COLOR", "#7C6DA0")
|
||||
|
||||
|
||||
def build_template_context(**runtime_kwargs: Any) -> Dict[str, Any]:
|
||||
@@ -100,6 +115,7 @@ def build_template_context(**runtime_kwargs: Any) -> Dict[str, Any]:
|
||||
- EMAIL_CSS_PATH: path to mail_style.css (optional; we inline it)
|
||||
- EMAIL_LOGO_URL: URL for email logo (preferred)
|
||||
- EMAIL_LOGO_PATH: fallback local path for email logo
|
||||
- EMAIL_ACCENT_COLOR: accent color (default #7C6DA0)
|
||||
"""
|
||||
# Load and inline mail_style.css for consistent email styling
|
||||
css_path = os.getenv("EMAIL_CSS_PATH", "/app/src/misc/mail_style.css")
|
||||
@@ -108,10 +124,14 @@ def build_template_context(**runtime_kwargs: Any) -> Dict[str, Any]:
|
||||
# Build logo HTML (URL or local fallback)
|
||||
logo_html = _email_logo_html()
|
||||
|
||||
# Accent color
|
||||
accent = _accent_color()
|
||||
|
||||
ctx: Dict[str, Any] = {
|
||||
"contact_email": os.getenv("EMAIL_CONTACT_ADDRESS", "support@example.com"),
|
||||
"email_css": css_text,
|
||||
"email_logo": logo_html,
|
||||
"accent_color": accent,
|
||||
}
|
||||
|
||||
# Runtime values override env if provided
|
||||
@@ -255,3 +275,37 @@ def send_email(
|
||||
except Exception as e:
|
||||
logger.error("Failed to send email: %s", e)
|
||||
raise EmailError(f"Failed to send email: {e}")
|
||||
|
||||
|
||||
def create_transcript_docx(text: str, filename: str):
|
||||
"""
|
||||
Create a .docx file from plain/markdown transcript text.
|
||||
"""
|
||||
from docx import Document
|
||||
from docx.shared import Pt
|
||||
|
||||
doc = Document()
|
||||
doc.add_heading("Transcript", level=1)
|
||||
|
||||
for line in text.splitlines():
|
||||
p = doc.add_paragraph(line)
|
||||
p.paragraph_format.space_after = Pt(4)
|
||||
|
||||
doc.save(filename)
|
||||
|
||||
|
||||
def create_summary_docx(text: str, filename: str):
|
||||
"""
|
||||
Create a .docx file from summary text.
|
||||
"""
|
||||
from docx import Document
|
||||
from docx.shared import Pt
|
||||
|
||||
doc = Document()
|
||||
doc.add_heading("Summary", level=1)
|
||||
|
||||
for line in text.splitlines():
|
||||
p = doc.add_paragraph(line)
|
||||
p.paragraph_format.space_after = Pt(4)
|
||||
|
||||
doc.save(filename)
|
||||
|
||||
+38
-18
@@ -12,6 +12,7 @@ from .celery_app import celery_app
|
||||
from .autotranscript import Scraibe
|
||||
from .misc import setup_logging
|
||||
from .email_sender import send_email, EmailError, load_template
|
||||
from .email_sender import create_transcript_docx, create_summary_docx
|
||||
|
||||
logger = logging.getLogger("scraibe.tasks")
|
||||
|
||||
@@ -19,7 +20,6 @@ logger = logging.getLogger("scraibe.tasks")
|
||||
def get_queue_position(task_id: str) -> int:
|
||||
"""
|
||||
Estimate the job's position in the queue.
|
||||
This is a simple count of ready/started tasks.
|
||||
"""
|
||||
try:
|
||||
inspect = celery_app.control.inspect()
|
||||
@@ -38,10 +38,13 @@ def get_queue_position(task_id: str) -> int:
|
||||
|
||||
def send_initial_email(to: str, queue_pos: int):
|
||||
"""
|
||||
Send initial confirmation email with queue position using HTML template.
|
||||
Static placeholders (contact_email, css, logo) come from env via load_template.
|
||||
Send initial confirmation email with queue position.
|
||||
Subject is customizable via EMAIL_SUBJECT_UPLOAD.
|
||||
"""
|
||||
subject = "ScrAIbe: Your transcription request has been received"
|
||||
subject = os.getenv(
|
||||
"EMAIL_SUBJECT_UPLOAD",
|
||||
"ScrAIbe: Your transcription request has been received",
|
||||
)
|
||||
|
||||
# Build plain-text fallback
|
||||
body = (
|
||||
@@ -88,10 +91,13 @@ def send_success_email(
|
||||
task_id: str,
|
||||
):
|
||||
"""
|
||||
Send final email with transcript and attachments using HTML template.
|
||||
Static placeholders (contact_email, css, logo) come from env via load_template.
|
||||
Send final email with transcript and attachments.
|
||||
Subject is customizable via EMAIL_SUBJECT_SUCCESS.
|
||||
"""
|
||||
subject = "ScrAIbe: Your transcript is ready"
|
||||
subject = os.getenv(
|
||||
"EMAIL_SUBJECT_SUCCESS",
|
||||
"ScrAIbe: Your transcript is ready",
|
||||
)
|
||||
|
||||
# Build plain-text fallback
|
||||
body = (
|
||||
@@ -140,10 +146,13 @@ def send_success_email(
|
||||
|
||||
def send_error_email(to: str, error_message: str, task_id: str):
|
||||
"""
|
||||
Send error notification email using HTML template.
|
||||
Static placeholders (contact_email, css, logo) come from env via load_template.
|
||||
Send error notification email.
|
||||
Subject is customizable via EMAIL_SUBJECT_ERROR.
|
||||
"""
|
||||
subject = "ScrAIbe: Error with your transcription request"
|
||||
subject = os.getenv(
|
||||
"EMAIL_SUBJECT_ERROR",
|
||||
"ScrAIbe: Error with your transcription request",
|
||||
)
|
||||
|
||||
# Build plain-text fallback
|
||||
body = (
|
||||
@@ -243,11 +252,17 @@ def process_transcription_task(
|
||||
# 4) Prepare files for email
|
||||
attachments = []
|
||||
|
||||
# TXT transcript
|
||||
txt_path = tempfile.mktemp(suffix=".txt")
|
||||
with open(txt_path, "w", encoding="utf-8") as f:
|
||||
# Transcript as .md
|
||||
md_transcript_path = tempfile.mktemp(suffix=".md")
|
||||
with open(md_transcript_path, "w", encoding="utf-8") as f:
|
||||
f.write("# Transcript\n\n")
|
||||
f.write(transcript_text)
|
||||
attachments.append(txt_path)
|
||||
attachments.append(md_transcript_path)
|
||||
|
||||
# Transcript as .docx
|
||||
docx_transcript_path = tempfile.mktemp(suffix=".docx")
|
||||
create_transcript_docx(transcript_text, docx_transcript_path)
|
||||
attachments.append(docx_transcript_path)
|
||||
|
||||
# JSON with diarization
|
||||
json_data = {
|
||||
@@ -271,13 +286,18 @@ def process_transcription_task(
|
||||
json.dump(json_data, f, indent=2, ensure_ascii=False)
|
||||
attachments.append(json_path)
|
||||
|
||||
# MD summary (only when summary is available)
|
||||
# Summary as .md (only when summary is available)
|
||||
if summary_text:
|
||||
md_path = tempfile.mktemp(suffix=".md")
|
||||
with open(md_path, "w", encoding="utf-8") as f:
|
||||
md_summary_path = tempfile.mktemp(suffix=".md")
|
||||
with open(md_summary_path, "w", encoding="utf-8") as f:
|
||||
f.write("# Summary\n\n")
|
||||
f.write(summary_text)
|
||||
attachments.append(md_path)
|
||||
attachments.append(md_summary_path)
|
||||
|
||||
# Summary as .docx
|
||||
docx_summary_path = tempfile.mktemp(suffix=".docx")
|
||||
create_summary_docx(summary_text, docx_summary_path)
|
||||
attachments.append(docx_summary_path)
|
||||
|
||||
# 5) Send success email
|
||||
send_success_email(
|
||||
|
||||
+38
-5
@@ -83,11 +83,12 @@ def create_app():
|
||||
header_path = layout_cfg.get("header", "/app/src/misc/header.html")
|
||||
footer_path = layout_cfg.get("footer", "/app/src/misc/footer.html")
|
||||
|
||||
# Configurable title and logo URL via environment
|
||||
# Configurable title, logo URL, and accent color via environment
|
||||
webui_title = os.getenv("WEBUI_TITLE", "A.P.Strom Transcription")
|
||||
logo_url = os.getenv("WEBUI_LOGO_URL", "https://apstrom.ca")
|
||||
accent_color = os.getenv("EMAIL_ACCENT_COLOR", "#7C6DA0")
|
||||
|
||||
# Prepare header HTML with logo URL
|
||||
# Prepare header HTML with logo URL and accent color
|
||||
header_html = ""
|
||||
if os.path.exists(header_path):
|
||||
header_html = load_html_template(
|
||||
@@ -95,15 +96,17 @@ def create_app():
|
||||
webui_title=webui_title,
|
||||
header_logo_url=logo_url,
|
||||
header_logo_src=logo_url,
|
||||
accent_color=accent_color,
|
||||
)
|
||||
|
||||
# Prepare footer HTML
|
||||
# Prepare footer HTML with accent color
|
||||
footer_html = ""
|
||||
if os.path.exists(footer_path):
|
||||
version = os.getenv("SCRABIE_VERSION", "0.1.1.dev")
|
||||
footer_html = load_html_template(
|
||||
footer_path,
|
||||
footer_scraibe_webui_version=version,
|
||||
accent_color=accent_color,
|
||||
)
|
||||
|
||||
# Build Gradio interface
|
||||
@@ -248,14 +251,44 @@ def create_app():
|
||||
outputs=[status_text],
|
||||
)
|
||||
|
||||
# Launch options
|
||||
# Launch options with accent color applied via CSS
|
||||
server_name = launch_cfg.get("server_name", os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"))
|
||||
server_port = launch_cfg.get("server_port", 7860)
|
||||
|
||||
accent_css = f"""
|
||||
:root {{
|
||||
--primary-accent: {accent_color};
|
||||
}}
|
||||
button.primary,
|
||||
.primary,
|
||||
.gradio-button-primary,
|
||||
.gradio-container button.primary {{
|
||||
background-color: var(--primary-accent) !important;
|
||||
border-color: var(--primary-accent) !important;
|
||||
}}
|
||||
button.primary:hover,
|
||||
.primary:hover,
|
||||
.gradio-button-primary:hover {{
|
||||
background-color: var(--primary-accent) !important;
|
||||
opacity: 0.95;
|
||||
}}
|
||||
.radio-item.selected,
|
||||
.radio-item.selected label {{
|
||||
color: var(--primary-accent) !important;
|
||||
}}
|
||||
a,
|
||||
.gradio-container a {{
|
||||
color: var(--primary-accent) !important;
|
||||
}}
|
||||
body {{
|
||||
font-family: Arial, sans-serif;
|
||||
}}
|
||||
"""
|
||||
|
||||
app.launch(
|
||||
server_name=str(server_name),
|
||||
server_port=int(server_port),
|
||||
css="body { font-family: Arial, sans-serif; }",
|
||||
css=accent_css,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user