Full Code of RayVentura/ShortGPT for AI

stable 3df4e0f7a422 cached
152 files
399.2 KB
105.8k tokens
343 symbols
1 requests
Download .txt
Showing preview only (435K chars total). Download the full file or copy to clipboard to get everything.
Repository: RayVentura/ShortGPT
Branch: stable
Commit: 3df4e0f7a422
Files: 152
Total size: 399.2 KB

Directory structure:
gitextract_zk_2yim7/

├── .database/
│   └── template_asset_db.json
├── .github/
│   ├── CHANGE_LOG.md
│   ├── CODEOWNERS
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yaml
│   │   ├── feature_request.yaml
│   │   └── question.yaml
│   ├── SECURITY.md
│   ├── config.yml
│   ├── issue_label_bot.yaml
│   ├── pull_request_template.md
│   ├── settings.yml
│   └── workflows/
│       └── generate_release-changelog.yaml
├── .gitignore
├── CHANGES.txt
├── Dockerfile
├── LICENSE
├── README-Docker.md
├── README.md
├── docs/
│   ├── .gitignore
│   ├── README.md
│   ├── babel.config.js
│   ├── docs/
│   │   ├── api-key-manager.mdx
│   │   ├── asset-database.mdx
│   │   ├── content-translation-engine.mdx
│   │   ├── content-video-engine.mdx
│   │   ├── facts-short-engine.mdx
│   │   ├── getting-started.mdx
│   │   └── how-to-install.mdx
│   ├── docusaurus.config.js
│   ├── package.json
│   ├── plugins/
│   │   ├── my-loaders/
│   │   │   └── index.js
│   │   └── tailwind-loader/
│   │       └── index.js
│   ├── sidebars.js
│   ├── src/
│   │   ├── components/
│   │   │   └── Home.js
│   │   ├── css/
│   │   │   ├── custom.css
│   │   │   └── fragments.css
│   │   └── pages/
│   │       └── index.js
│   └── tailwind.config.js
├── gui/
│   ├── asset_components.py
│   ├── content_automation_ui.py
│   ├── gui_gradio.py
│   ├── ui_abstract_base.py
│   ├── ui_abstract_component.py
│   ├── ui_components_html.py
│   ├── ui_tab_asset_library.py
│   ├── ui_tab_config.py
│   ├── ui_tab_short_automation.py
│   ├── ui_tab_video_automation.py
│   └── ui_tab_video_translation.py
├── installation-notes.md
├── requirements.txt
├── runShortGPT.py
├── runShortGPTColab.py
├── setup.py
├── shortGPT/
│   ├── __init__.py
│   ├── api_utils/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── eleven_api.py
│   │   ├── image_api.py
│   │   └── pexels_api.py
│   ├── audio/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── audio_duration.py
│   │   ├── audio_utils.py
│   │   ├── edge_voice_module.py
│   │   ├── eleven_voice_module.py
│   │   └── voice_module.py
│   ├── config/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── api_db.py
│   │   ├── asset_db.py
│   │   ├── config.py
│   │   ├── languages.py
│   │   └── path_utils.py
│   ├── database/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── content_data_manager.py
│   │   ├── content_database.py
│   │   └── db_document.py
│   ├── editing_framework/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── core_editing_engine.py
│   │   ├── editing_engine.py
│   │   ├── editing_steps/
│   │   │   ├── __init__.py
│   │   │   ├── add_background_video.json
│   │   │   ├── add_background_voiceover.json
│   │   │   ├── add_voiceover.json
│   │   │   ├── background_music.json
│   │   │   ├── crop_1920x1080_to_short.json
│   │   │   ├── extract_audio.json
│   │   │   ├── insert_audio.json
│   │   │   ├── make_caption.json
│   │   │   ├── make_caption_arabic.json
│   │   │   ├── make_caption_arabic_landscape.json
│   │   │   ├── make_caption_landscape.json
│   │   │   ├── show_reddit_image.json
│   │   │   ├── show_top_image.json
│   │   │   ├── show_watermark.json
│   │   │   └── subscribe_animation.json
│   │   ├── flows/
│   │   │   ├── __init__.py
│   │   │   └── build_reddit_image.json
│   │   └── rendering_logger.py
│   ├── editing_utils/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── captions.py
│   │   ├── editing_images.py
│   │   └── handle_videos.py
│   ├── engine/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── abstract_content_engine.py
│   │   ├── content_short_engine.py
│   │   ├── content_translation_engine.py
│   │   ├── content_video_engine.py
│   │   ├── facts_short_engine.py
│   │   ├── multi_language_translation_engine.py
│   │   └── reddit_short_engine.py
│   ├── gpt/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── facts_gpt.py
│   │   ├── gpt_chat_video.py
│   │   ├── gpt_editing.py
│   │   ├── gpt_translate.py
│   │   ├── gpt_utils.py
│   │   ├── gpt_voice.py
│   │   ├── gpt_yt.py
│   │   └── reddit_gpt.py
│   ├── prompt_templates/
│   │   ├── __init__.py
│   │   ├── chat_video_edit_script.yaml
│   │   ├── chat_video_script.yaml
│   │   ├── editing_generate_images.yaml
│   │   ├── editing_generate_videos.yaml
│   │   ├── facts_generator.yaml
│   │   ├── facts_subjects_generation.yaml
│   │   ├── reddit_extract_question.yaml
│   │   ├── reddit_filter_realistic.yaml
│   │   ├── reddit_generate_question.yaml
│   │   ├── reddit_generate_script.yaml
│   │   ├── reddit_story_filter.yaml
│   │   ├── reddit_username.yaml
│   │   ├── translate_content.yaml
│   │   ├── voice_identify_gender.yaml
│   │   └── yt_title_description.yaml
│   ├── tracking/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── api_tracking.py
│   │   └── cost_analytics.py
│   └── utils/
│       ├── cli.py
│       └── requirements.py
└── videos/
    └── .gitignore

================================================
FILE CONTENTS
================================================

================================================
FILE: .database/template_asset_db.json
================================================
{
    "asset_collection": {
        "1": {
            "_id": "local_assets",
            "white_reddit_template": {
                "path": "public/white_reddit_template.png",
                "type": "image",
                "ts": "2023-07-03 19:41:55",
                "required": true
            },
            "subscribe-animation": {
                "path": "public/subscribe-animation.mp4",
                "type": "video",
                "ts": "2023-07-03 21:37:53",
                "required": true
            }
        },
        "2": {
            "_id": "remote_assets",
            "Music joakim karud dreams": {
                "type": "background music",
                "url": "https://www.youtube.com/watch?v=p56gqDhUYbU",
                "ts": "2023-07-05 04:35:03"
            },
            "Music dj quads": {
                "type": "background music",
                "url": "https://www.youtube.com/watch?v=uUu1NcSHg2E",
                "ts": "2023-07-05 05:03:44"
            },
            "Car race gameplay": {
                "type": "background video",
                "url": "https://www.youtube.com/watch?v=gBsJA8tCeyc",
                "ts": "2023-07-04 23:07:44"
            },
            "Minecraft jumping circuit": {
                "url": "https://www.youtube.com/watch?v=Pt5_GSKIWQM",
                "type": "background video",
                "ts": "2023-07-07 04:13:36"
            },
            "Ski gameplay": {
                "url": "https://www.youtube.com/watch?v=8ao1NAOVKTU",
                "type": "background video",
                "ts": "2023-07-07 04:54:16"
            }
        }
    }
}

================================================
FILE: .github/CHANGE_LOG.md
================================================
# Changelog

All notable changes to this project will be documented in this file.

## [Unreleased]

<!--
Notes for any unreleased changes do here. When a new release is cut, move these from
the unreleased section to the section for the new release.
-->

Upcoming changes.

### Added

### Changed

### Removed

## [0.0.1] - YYYY-MM-DD

Initial Release.

### Added

- What was added.


<!--
These Markdown anchors provide a link to the diff for each release. They should be
updated any time a new release is cut.
-->
[Unreleased]: /
[0.0.1]: /v0.0.1


================================================
FILE: .github/CODEOWNERS
================================================
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
# @USER will be requested for
# review when someone opens a pull request.
# if you want to add more owners just write it after the demo user @DemoUser
*       @RayVentura


================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: .github/CONTRIBUTING.md
================================================
🌟💻📚

## Contributing

There are many exciting ways to contribute to ShortGPT, our AI automated content creation framework. 👏

See below for everything you can do and the processes to follow for each contribution method. Note that no matter how you contribute, your participation is governed by our ✨[Code of Conduct](CODE_OF_CONDUCT.md)✨.

## 🛠️ Make changes to the code or docs

- 🍴 Fork the project, 
- 💡 make your changes,
- 🔀 and send a pull request! 🙌

Make sure you read and follow the instructions in the [pull request template](pull_request_template.md). And note that all participation in this project (including code submissions) is governed by our ✨[Code of Conduct](CODE_OF_CONDUCT.md)✨.

## 🐞📝 Submit bug reports or feature requests

Just use the GitHub issue tracker to submit your bug reports and feature requests. We appreciate your feedback! 🐛🔧

Let's make ShortGPT even better together! 🚀❤️


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: rayventura
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: rayventura
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yaml
================================================
name: 🐛 Bug Report
description: File a bug report
title: '🐛 [Bug]: '
labels: ['bug']

body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this bug report!

  - type: textarea
    id: what-happened
    attributes:
      label: What happened?
      description: Describe the issue here.
      placeholder: Tell us what you see!
    validations:
      required: true

  - type: dropdown
    id: browsers
    attributes:
      label: What type of browser are you seeing the problem on?
      multiple: true
      options:
        - Firefox
        - Chrome
        - Safari
        - Microsoft Edge
    validations:
      required: true

  - type: dropdown
    id: operating-systems
    attributes:
      label: What type of Operating System are you seeing the problem on?
      multiple: true
      options:
        - Linux
        - Windows
        - Mac
        - Google Colab
        - Other
    validations:
      required: true

  - type: input
    id: python-version
    attributes:
      label: Python Version
      description: What version of Python are you using?
      placeholder: e.g. Python 3.9.0
    validations:
      required: true

  - type: input
    id: application-version
    attributes:
      label: Application Version
      description: What version of the application are you using?
      placeholder: e.g. v1.2.3
    validations:
      required: true

  - type: textarea
    id: expected-behavior
    attributes:
      label: Expected Behavior
      description: What did you expect to happen?
      placeholder: What did you expect?
    validations:
      required: true

  - type: textarea
    id: error-message
    attributes:
      label: Error Message
      description: What error message did you receive?
      placeholder:
      render: shell
    validations:
      required: false

  - type: textarea
    id: logs
    attributes:
      label: Code to produce this issue.
      description: Please copy and paste any relevant code to re-produce this issue.
      render: shell

  - type: textarea
    id: screenshots-assets
    attributes:
      label: Screenshots/Assets/Relevant links
      description: If applicable, add screenshots, assets or any relevant links that can help understand the issue.
      placeholder: Provide any relevant material here
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yaml
================================================
name: ✨ Feature request
description: Suggest an feature / idea for this project
title: '✨ [Feature Request / Suggestion]: '
labels: ['feature']
body:
  - type: markdown
    attributes:
      value: |
        We appreciate your feedback on how to improve this project. Please be sure to include as much details & any resources if possible!

  - type: textarea
    id: Suggestion
    attributes:
      label: Suggestion / Feature Request
      description: Describe the feature(s) you would like to see added.
      placeholder: Tell us your suggestion
    validations:
      required: true

  - type: textarea
    id: why-usage
    attributes:
      label: Why would this be useful?
      description: Describe why this feature would be useful.
      placeholder: Tell us why this would be useful to have this feature
    validations:
      required: false

  - type: textarea
    id: screenshots-assets
    attributes:
      label: Screenshots/Assets/Relevant links
      description: If applicable, add screenshots, assets or any relevant links that can help understand the issue.
      placeholder: Provide any relevant material here
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/question.yaml
================================================
name: ❓ Question
description: Ask a question about this project
title: '❓ [Question]: '
labels: ['question']
body:
  - type: markdown
    attributes:
      value: |
        We appreciate your interest in this project. Please be sure to include as much detail & context about your question as possible!

  - type: textarea
    id: Question
    attributes:
      label: Your Question
      description: Describe your question in detail.
    validations:
      required: true


================================================
FILE: .github/SECURITY.md
================================================
# Security Policy

## Supported Versions

| Version | Supported          |
| ------- | ------------------ |
| 0.0.x   | :x: |

## 🔒️ Reporting a Vulnerability

If you have identified a security vulnerability in system or product please `RayVentura` with your findings. We strongly recommend using our `PGP key` to prevent this information from falling into the wrong hands.

### Disclosure Policy

Upon receipt of a security report the following steps will be taken:

- Acknowledge your report within 48 hours, and provide a further more detailed update within 48 hours.
- Confirm the problem and determine the affected versions
- Keep you informed of the progress towards resolving the problem and notify you when the vulnerability has been fixed.
- Audit code to find any potential similar problems.
- Prepare fixes for all releases still under maintenance. These fixes will be released as fast as possible.
- Handle your report with strict confidentiality, and not pass on your personal details to third parties without your permission.

Whilst the issue is under investigation

- **Do** provide as much information as possible.
- **Do not** exploit of the vulnerability or problem you have discovered.
- **Do not** reveal the problem to others until it has been resolved.


================================================
FILE: .github/config.yml
================================================
# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome

# Comment to be posted to on first time issues
newIssueWelcomeComment: >
  Thanks for opening your first issue! Reports like these help improve the project!

# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome

# Comment to be posted to on PRs from first time contributors in your repository
newPRWelcomeComment: >
  Thanks for opening this pull request!

# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge

# Comment to be posted to on pull requests merged by a first time user
firstPRMergeComment: >
  Congrats on merging your first pull request!

# The keyword to find for Todo Bot issue
todo:
  keyword: '@todo'


================================================
FILE: .github/issue_label_bot.yaml
================================================
label-alias:
    bug: 'Type: Bug'
    feature_request: 'Type: Feature'
    question: 'Type: Question'


================================================
FILE: .github/pull_request_template.md
================================================
## Proposed changes

Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. 👀🔧

## Types of changes

What types of changes does your code introduce to this project?
_Put an `x` in the boxes that apply_ 😄🚀

- [ ] Bugfix (non-breaking change which fixes an issue) 🐛
- [ ] New feature (non-breaking change which adds functionality) ✨
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 💥
- [ ] Documentation Update (if none of the other choices apply) 📖

## Checklist

_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._ ✅

- [ ] I have read the CONTRIBUTING.md 📚
- [ ] I have added tests that prove my fix is effective or that my feature works ✅✔️
- [ ] I have added necessary documentation (if appropriate) 📝

## Further comments

If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... 💡❓


## References and related issues (e.g. #1234)

N/A 📌


================================================
FILE: .github/settings.yml
================================================
repository:
  # See https://developer.github.com/v3/repos/#edit for all available settings.

  # The name of the repository. Changing this will rename the repository
  #name: repo-name

  # A short description of the repository that will show up on GitHub
  #description: description of repo

  # A URL with more information about the repository
  #homepage: https://example.github.io/

  # A comma-separated list of topics to set on the repository
  #topics: project, template, project-template

  # Either `true` to make the repository private, or `false` to make it public.
  #private: false

  # Either `true` to enable issues for this repository, `false` to disable them.
  has_issues: true

  # Either `true` to enable the wiki for this repository, `false` to disable it.
  has_wiki: true

  # Either `true` to enable downloads for this repository, `false` to disable them.
  #has_downloads: true

  # Updates the default branch for this repository.
  default_branch: stable

  # Either `true` to allow squash-merging pull requests, or `false` to prevent
  # squash-merging.
  #allow_squash_merge: true

  # Either `true` to allow merging pull requests with a merge commit, or `false`
  # to prevent merging pull requests with merge commits.
  #allow_merge_commit: true

  # Either `true` to allow rebase-merging pull requests, or `false` to prevent
  # rebase-merging.
  #allow_rebase_merge: true

# Labels: define labels for Issues and Pull Requests
labels:
  - name: 'Type: Bug'
    color: e80c0c
    description: Something isn't working as expected.

  - name: 'Type: Enhancement'
    color: 54b2ff
    description: Suggest an improvement for an existing feature.

  - name: 'Type: Feature'
    color: 54b2ff
    description: Suggest a new feature.

  - name: 'Type: Security'
    color: fbff00
    description: A problem or enhancement related to a security issue.

  - name: 'Type: Question'
    color: 9309ab
    description: Request for information.

  - name: 'Type: Test'
    color: ce54e3
    description: A problem or enhancement related to a test.

  - name: 'Status: Awaiting Review'
    color: 24d15d
    description: Ready for review.

  - name: 'Status: WIP'
    color: 07b340
    description: Currently being worked on.

  - name: 'Status: Waiting'
    color: 38C968
    description: Waiting on something else to be ready.

  - name: 'Status: Stale'
    color: 66b38a
    description: Has had no activity for some time.

  - name: 'Duplicate'
    color: EB862D
    description: Duplicate of another issue.

  - name: 'Invalid'
    color: faef50
    description: This issue doesn't seem right.

  - name: 'Priority: High +'
    color: ff008c
    description: Task is considered higher-priority.

  - name: 'Priority: Low -'
    color: 690a34
    description: Task is considered lower-priority.

  - name: 'Documentation'
    color: 2fbceb
    description: An issue/change with the documentation.

  - name: "Won't fix"
    color: C8D9E6
    description: Reported issue is working as intended.

  - name: '3rd party issue'
    color: e88707
    description: This issue might be caused by a 3rd party script/package/other reasons

  - name: 'Os: Windows'
    color: AEB1C2
    description: Is Windows-specific

  - name: 'Os: Mac'
    color: AEB1C2
    description: Is Mac-specific

  - name: 'Os: Linux'
    color: AEB1C2
    description: Is Linux-specific

  - name: 'Os: Google Colab'
    color: AEB1C2
    description: Is Google Colab-specific
#
#
# # Collaborators: give specific users access to this repository.
# # See https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator for available options
# collaborators:
#   # - username: bkeepers
#   #   permission: push
#   # - username: hubot
#   #   permission: pull

#   # Note: `permission` is only valid on organization-owned repositories.
#   # The permission to grant the collaborator. Can be one of:
#   # * `pull` - can pull, but not push to or administer this repository.
#   # * `push` - can pull and push, but not administer this repository.
#   # * `admin` - can pull, push and administer this repository.
#   # * `maintain` - Recommended for project managers who need to manage the repository without access to sensitive or destructive actions.
#   # * `triage` - Recommended for contributors who need to proactively manage issues and pull requests without write access.

# # See https://developer.github.com/v3/teams/#add-or-update-team-repository for available options
# teams:
#   - name: core
#     # The permission to grant the team. Can be one of:
#     # * `pull` - can pull, but not push to or administer this repository.
#     # * `push` - can pull and push, but not administer this repository.
#     # * `admin` - can pull, push and administer this repository.
#     # * `maintain` - Recommended for project managers who need to manage the repository without access to sensitive or destructive actions.
#     # * `triage` - Recommended for contributors who need to proactively manage issues and pull requests without write access.
#     permission: admin
#   - name: docs
#     permission: push

# branches:
#   - name: master
#     # https://developer.github.com/v3/repos/branches/#update-branch-protection
#     # Branch Protection settings. Set to null to disable
#     protection:
#       # Required. Require at least one approving review on a pull request, before merging. Set to null to disable.
#       required_pull_request_reviews:
#         # The number of approvals required. (1-6)
#         required_approving_review_count: 1
#         # Dismiss approved reviews automatically when a new commit is pushed.
#         dismiss_stale_reviews: true
#         # Blocks merge until code owners have reviewed.
#         require_code_owner_reviews: true
#         # Specify which users and teams can dismiss pull request reviews. Pass an empty dismissal_restrictions object to disable. User and team dismissal_restrictions are only available for organization-owned repositories. Omit this parameter for personal repositories.
#         dismissal_restrictions:
#           users: []
#           teams: []
#       # Required. Require status checks to pass before merging. Set to null to disable
#       required_status_checks:
#         # Required. Require branches to be up to date before merging.
#         strict: true
#         # Required. The list of status checks to require in order to merge into this branch
#         contexts: []
#       # Required. Enforce all configured restrictions for administrators. Set to true to enforce required status checks for repository administrators. Set to null to disable.
#       enforce_admins: true
#       # Prevent merge commits from being pushed to matching branches
#       required_linear_history: true
#       # Required. Restrict who can push to this branch. Team and user restrictions are only available for organization-owned repositories. Set to null to disable.
#       restrictions:
#         apps: []
#         users: []
#         teams: []


================================================
FILE: .github/workflows/generate_release-changelog.yaml
================================================
name: Create Release

on:
  push:
    tags:
      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10

jobs:
  build:
    name: Create Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Changelog
        uses: Bullrich/generate-release-changelog@master
        id: Changelog
        env:
          REPO: ${{ github.repository }}
      - name: Create Release
        id: create_release
        uses: actions/create-release@latest
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          body: |
            ${{ steps.Changelog.outputs.changelog }}
          draft: false
          prerelease: false


================================================
FILE: .gitignore
================================================
!*.py
!*.json
!*.yaml
!*.template
*.pyc
**/__pycache__/
test.py
public/*
!public/white_reddit_template.png
!public/subscribe-animation.mp4
z_doc/*
z_other/*
videos/*
.logs/
.editing_assets/*
.database/api_db.json
.database/content_db.json
.database/asset_db.json
flagged/
.vscode
.env
ShortGPT.egg-info
dist
build
setup
test.ipynb
.venv/
MANIFEST.in
schema.json
video.mp4
Untitled-1.ipynb

================================================
FILE: CHANGES.txt
================================================
# CHANGES

## Version 0.1.31
- Fixing issue in AssetDatabase, where it was copying unexisting asset template file
## Version 0.1.3
- Requiring a youtube url as the subscribe animation url in the EditingStep.ADD_SUBSCRIBE_ANIMATION step.
- Adding a default subscribe animation youtube link by default shipped in the AssetDatabase
- Making path imports relative for gpt prompts and editing blocks and flows.
## Version 0.1.2
- Improving logs in content engines
## Version 0.1.1
- Adding AssetType in AssetDatabase
- Adding ApiProvider in api_db
- Fixing pip libary missing editing_framework module, prompt_template module
## Version 0.1.0
- Fixing the AssetDatabase when it's empty
## Version 0.0.2
- Implemented the content_translation_engine; a multilingual video dubbing content engine. The source can be found at shortGPT/engine/content_translation_engine.py.
- Implemented the new EdgeTTS voice module; it can be found at shortgpt/audio/edge_voice_module.
- Added documentation which can be found under docs/.

================================================
FILE: Dockerfile
================================================
# Use an official Python runtime as the parent image
FROM python:3.10-slim-bullseye
RUN apt-get update && apt-get install -y ffmpeg

# Set the working directory in the container to /app
WORKDIR /app

# Install any Python packages specified in requirements.txt
# Copy requirements file
COPY requirements.txt .

# Install dependencies
RUN pip install -r requirements.txt

# Copy the local package directory content into the container at /app
COPY . /app

EXPOSE 31415

# Define any environment variables
# ENV KEY Value

# Print environment variables (for debugging purposes, you can remove this line if not needed)
RUN ["printenv"]

# Run Python script when the container launches
CMD ["python", "-u", "./runShortGPT.py"]

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2024 Ray Ventura

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README-Docker.md
================================================
# To run ShortGPT docker:


First make a .env file with the API keys like this:

```bash
GEMINI_API_KEY=put_your_gemini_api_key_here
OPENAI_API_KEY=sk-_put_your_openai_api_key_here
ELEVENLABS_API_KEY=put_your_eleven_labs_api_key_here
PEXELS_API_KEY=put_your_pexels_api_key_here
```


To run Dockerfile do this:
```bash
docker build -t short_gpt_docker:latest .
docker run -p 31415:31415 --env-file .env short_gpt_docker:latest
```
Export Docker image:
```bash
docker save short_gpt_docker > short_gpt_docker.tar
```


================================================
FILE: README.md
================================================
# 🚀🎬 ShortGPT 
## AI video automation framework
<p align="center">
  <a href="https://discord.gg/uERx39ru3R">
    <img src="https://dcbadge.vercel.app/api/server/uERx39ru3R?compact=true&style=flat">
  </a>
  <a href="https://star-history.com/#rayventura/shortgpt)">
    <img src="https://img.shields.io/github/stars/rayventura/shortgpt?style=social">
  </a>
  <a href="https://pypi.org/project/shortgpt/">
    <img src="https://static.pepy.tech/personalized-badge/shortgpt?period=month&units=international_system&left_color=blue&right_color=green&left_text=Downloads/month">
  </a>
  <a href="https://docs.shortgpt.ai/">
    <img src="https://img.shields.io/badge/docs-visit-blue">
  </a>  
</p>

<div align="center" style="border-radius: 20px;" width="18%">
    <img src="https://github.com/RayVentura/ShortGPT/assets/121462835/083c8dc3-bac5-42c1-a08d-3ff9686d18c5" alt="ShortGPT-logo" style="border-radius: 20px;" width="18%"/>
</div>
<div align="center">
  <a href="https://discord.gg/uERx39ru3R">
    <img src="https://img.shields.io/discord/1126042224979886160?color=7289da&logo=discord&logoColor=blue&labelColor=white&color=cyan" alt="Join our Discord" height="34">
  </a>
</div>

<div align="center">
⚡ Automating video and short content creation with AI ⚡
</div>
</br>

Follow the installation steps below for running the web app locally (running the google Colab is highly recommanded). 
Please read "installation-notes.md" for more details.
## 🎥 Showcase ([Full video on YouTube](https://youtu.be/hpoSHq-ER8U))

https://github.com/RayVentura/ShortGPT/assets/121462835/a802faad-0fd7-4fcb-aa82-6365c27ea5fe
## 🎥 Voice Dubbing


https://github.com/RayVentura/ShortGPT/assets/121462835/06f51b2d-f8b1-4a23-b299-55e0e18902ef

## 🌟 Show Your Support
We hope you find ShortGPT helpful! If you do, let us know by giving us a star ⭐ on the repo. It's easy, just click on the 'Star' button at the top right of the page. Your support means a lot to us and keeps us motivated to improve and expand ShortGPT. Thank you and happy content creating! 🎉 

[![GitHub star chart](https://img.shields.io/github/stars/rayventura/shortgpt?style=social)](https://github.com/RayVentura/ShortGPT/stargazers)
## 🛠️ How it works
![alt text](https://github.com/RayVentura/ShortGPT/assets/121462835/fcee74d4-f856-4481-949f-244558bf3bfa)
## 📝 Introduction to ShortGPT 
ShortGPT is a powerful framework for automating content creation. It simplifies video creation, footage sourcing, voiceover synthesis, and editing tasks. Of the most popular use-cases of ShortGPT is youtube automation and Tiktok creativity program automation.

- 🎞️ **Automated editing framework**: Streamlines the video creation process with an LLM oriented video editing language.

- 📃 **Scripts and Prompts**: Provides ready-to-use scripts and prompts for various LLM automated editing processes.

- 🗣️ **Voiceover / Content Creation**: Supports multiple languages including English 🇺🇸, Spanish 🇪🇸, Arabic 🇦🇪, French 🇫🇷, Polish 🇵🇱, German 🇩🇪, Italian 🇮🇹, Portuguese 🇵🇹, Russian 🇷🇺, Mandarin Chinese 🇨🇳, Japanese 🇯🇵, Hindi 🇮🇳,Korean 🇰🇷, and way over 30 more languages (with EdgeTTS)

- 🔗 **Caption Generation**: Automates the generation of video captions.

- 🌐🎥 **Asset Sourcing**: Sources images and video footage from the internet, connecting with the web and Pexels API as necessary.

- 🧠 **Memory and persistency**: Ensures long-term persistency of automated editing variables with TinyDB.

## 🚀 Quick Start: Run ShortGPT on Google Colab (https://colab.research.google.com/drive/1_2UKdpF6lqxCqWaAcZb3rwMVQqtbisdE?usp=sharing)

If you prefer not to install the prerequisites on your local system, you can use the Google Colab notebook. This option is free and requires no installation setup.

1. Click on the link to the Google Colab notebook: [https://colab.research.google.com/drive/1_2UKdpF6lqxCqWaAcZb3rwMVQqtbisdE?usp=sharing](https://colab.research.google.com/drive/1_2UKdpF6lqxCqWaAcZb3rwMVQqtbisdE?usp=sharing)

2. Once you're in the notebook, simply run the cells in order from top to bottom. You can do this by clicking on each cell and pressing the 'Play' button, or by using the keyboard . Enjoy using ShortGPT!

# Instructions for running shortGPT locally
This guide provides step-by-step instructions for installing shortGPT and its dependencies.
To run ShortGPT locally, you need Docker.

## Installation Steps

To run ShortGPT, you need to have docker. Follow the instructions "installation-notes.md" for more details.

1. For running the Dockerfile, do this:
```bash
docker build -t short_gpt_docker:latest .
docker run -p 31415:31415 --env-file .env short_gpt_docker:latest
```
## Running runShortGPT.py Web Interface

2. After running the script, a Gradio interface should open at your local host on port 31415 (http://localhost:31415)
 

## Framework overview

- 🎬 The `ContentShortEngine` is designed for creating shorts, handling tasks from script generation to final rendering, including adding YouTube metadata.

- 🎥 The `ContentVideoEngine` is ideal for longer videos, taking care of tasks like generating audio, automatically sourcing background video footage, timing captions, and preparing background assets.

- 🗣️ The `ContentTranslationEngine` is designed to dub and translate entire videos, from mainstream languages to more specific target languages. It takes a video file, or youtube link, transcribe it's audio, translates the content, voices it in a target language, adds captions , and gives back a new video, in a totally different language.

- 🎞️ The automated `EditingEngine`, using Editing Markup Language and JSON, breaks down the editing process into manageable and customizable blocks, comprehensible to Large Language Models.

💡 ShortGPT offers customization options to suit your needs, from language selection to watermark addition.

🔧 As a framework, ShortGPT is adaptable and flexible, offering the potential for efficient, creative content creation.

More documentation incomming, please be patient.


## Technologies Used

ShortGPT utilizes the following technologies to power its functionality:

- **Moviepy**: Moviepy is used for video editing, allowing ShortGPT to make video editing and rendering

- **Openai**: Openai is used for automating the entire process, including generating scripts and prompts for LLM automated editing processes.

- **ElevenLabs**: ElevenLabs is used for voice synthesis, supporting multiple languages for voiceover creation.

- **EdgeTTS**: Microsoft's FREE EdgeTTS is used for voice synthesis, supporting way many more language than ElevenLabs currently.

- **Pexels**: Pexels is used for sourcing background footage, allowing ShortGPT to connect with the web and access a wide range of images and videos.

- **Bing Image**: Bing Image is used for sourcing images, providing a comprehensive database for ShortGPT to retrieve relevant visuals.

These technologies work together to provide a seamless and efficient experience in automating video and short content creation with AI.

## 💁 Contributing

As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it would be in the form of a new feature, improved infrastructure, or better documentation.
<p align="center">
  <a href="https://star-history.com/#RayVentura/ShortGPT&Date">
    <img src="https://api.star-history.com/svg?repos=RayVentura/ShortGPT&type=Date" alt="Star History Chart">
  </a>
</p>


================================================
FILE: docs/.gitignore
================================================
# Dependencies
/node_modules

# Production
/build

# Generated files
.docusaurus
.cache-loader

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*


================================================
FILE: docs/README.md
================================================
# ShortGPT Documentation
# Installation

1. `yarn install` in the root of this repository (two level above this directory).
1. In this directory, do `yarn start`.
1. A browser window will open up, pointing to the docs.

# Deployment

Vercel handles the deployment of this website.


================================================
FILE: docs/babel.config.js
================================================
module.exports = {
  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};


================================================
FILE: docs/docs/api-key-manager.mdx
================================================
---
title: ApiKeyManager in ShortGPT
sidebar_label: ApiKeyManager
---

# ApiKeyManager in ShortGPT

ApiKeyManager is a class in the ShortGPT framework that manages the API keys for different providers. It interacts with the database to get and set API keys.

## Importing ApiKeyManager

```python
from shortGPT.config.api_db import ApiKeyManager, ApiProvider
```

## Using ApiKeyManager

ApiKeyManager provides two main methods: `get_api_key` and `set_api_key`.

### set_api_key

This method is used to set the API key for a specific provider in the database. It takes two arguments: the key (provider name) and the value (API key).

```python
ApiKeyManager.set_api_key(ApiProvider.OPENAI, "your_openai_key")
ApiKeyManager.set_api_key(ApiProvider.ELEVEN_LABS, "your_eleven_labs_key")
```

In the above example, we are setting the API keys for OPENAI and ELEVEN_LABS.

### get_api_key

This method is used to retrieve the API key for a specific provider from the database. It takes one argument: the key (provider name).

```python
openai_key = ApiKeyManager.get_api_key(ApiProvider.OPENAI)
eleven_labs_key = ApiKeyManager.get_api_key(ApiProvider.ELEVEN_LABS)
```
In the above example, we are retrieving the API keys for OPENAI and ELEVEN_LABS.

## Note

The `key` argument in both methods can either be a string or an instance of the `ApiProvider` enum. If it is an instance of `ApiProvider`, the `value` attribute of the enum instance will be used as the key.

```python
ApiKeyManager.set_api_key("OPENAI_API_KEY", "your_openai_key")
ApiKeyManager.set_api_key("ELEVENLABS_API_KEY", "your_eleven_labs_key")

openai_key = ApiKeyManager.get_api_key("OPENAI_API_KEY")
eleven_labs_key = ApiKeyManager.get_api_key("ELEVENLABS_API_KEY")
```
In the above example, we are setting and retrieving the API keys using string keys instead of `ApiProvider` instances.

================================================
FILE: docs/docs/asset-database.mdx
================================================
---
title: AssetDatabase in ShortGPT
sidebar_label: AssetDatabase
---

# AssetDatabase in ShortGPT

The `AssetDatabase` in ShortGPT is a powerful tool that allows you to manage both local and remote assets. This guide will provide you with examples of how to use the `AssetDatabase`.

## Importing AssetDatabase and AssetType

```python
from shortGPT.config.asset_db import AssetDatabase, AssetType
```

## Adding Assets

You can add both remote and local assets to the `AssetDatabase`.

### Adding Remote Assets

```python
AssetDatabase.add_remote_asset("minecraft background cube", AssetType.BACKGROUND_VIDEO, "https://www.youtube.com/watch?v=Pt5_GSKIWQM")
AssetDatabase.add_remote_asset('chill music', AssetType.BACKGROUND_MUSIC, "https://www.youtube.com/watch?v=uUu1NcSHg2E")
```

### Adding Local Assets

```python
AssetDatabase.add_local_asset('my_music', AssetType.AUDIO, "./my_music.wav")
```

## Asset Types

The `AssetType` enum is used to specify the type of asset being added to the `AssetDatabase`. The available asset types are:

- VIDEO
- AUDIO
- IMAGE
- BACKGROUND_MUSIC
- BACKGROUND_VIDEO
- OTHER

## Getting Asset Information

You can retrieve information about an asset using the following methods:

### Get Asset Duration

This method returns the duration in seconds of a video or audio asset. If the asset is neither video nor audio, it returns `None`.

```python
AssetDatabase.get_asset_duration('minecraft background cube')
```

### Get Asset Link

This method returns a source URL, or the path of the resource. If the asset is a YouTube video or audio, it uses `yt-dlp` to extract a download URL or a direct video/audio link.

```python
AssetDatabase.get_asset_link('minecraft background cube')
```

## Synchronizing Local Assets

The `sync_local_assets` method synchronizes the database with local assets found in the `/public` folder. If it doesn't find one, it doesn't do anything.

```python
AssetDatabase.sync_local_assets()
```

## Removing Assets

You can remove an asset from the database by providing its name to the `remove_asset` method.

```python
AssetDatabase.remove_asset('name')
```

## Getting Database State

You can get the state of the asset database as a pandas dataframe using the `get_df` method.

```python
AssetDatabase.get_df()
```

This method returns a dataframe that includes the name, type, link, source, and timestamp of each asset in the database.

================================================
FILE: docs/docs/content-translation-engine.mdx
================================================
---
title: ContentTranslationEngine
sidebar_label: ContentTranslationEngine
---

The `ContentTranslationEngine` in ShortGPT is a powerful tool that automates the process of translating video content. This guide will provide you with an overview of how to use the `ContentTranslationEngine`.

## Importing ContentTranslationEngine

```python
from shortGPT.engine.content_translation_engine import ContentTranslationEngine
```

## Initializing ContentTranslationEngine

The `ContentTranslationEngine` requires a `VoiceModule`, a source URL (either a local video file path or a YouTube link), a target language, and an optional flag indicating whether to use captions for translation.

```python
content_engine = ContentTranslationEngine(voice_module, src_url, target_language, use_captions=False)
```

## Example

```python
from shortGPT.config.api_db import ApiKeyManager, ApiProvider
from shortGPT.engine.content_translation_engine import ContentTranslationEngine
from shortGPT.config.languages import Language
from shortGPT.audio.edge_voice_module import EdgeTTSVoiceModule, EDGE_TTS_VOICENAME_MAPPING

# Set API Keys
ApiKeyManager.set_api_key(ApiProvider.OPENAI, "your_openai_key")
ApiKeyManager.set_api_key(ApiProvider.ELEVEN_LABS, "your_eleven_labs_key")

# Configure the Voice Module
voice_name = EDGE_TTS_VOICENAME_MAPPING[Language.SPANISH]['male']
voice_module = EdgeTTSVoiceModule(voice_name)

# Configure Content Engine
src_url = "https://www.youtube.com/watch?v=QQz5hj8y1TE"
target_language = Language.SPANISH
use_captions = False
content_engine = ContentTranslationEngine(voice_module, src_url, target_language, use_captions)

# Generate Content
for step_num, step_logs in content_engine.makeContent():
    print(f" {step_logs}")

# Get Video Output Path
print(content_engine.get_video_output_path())
```

## How ContentTranslationEngine Works

The `ContentTranslationEngine` works by executing a series of steps defined in the `stepDict` dictionary. Each step is a method that performs a specific task in the video translation process. Here's what each step does:

1. `_transcribe_audio`: Transcribes the audio from the source video
2. `_translate_content`: Translates the transcribed content from the source language to the target language.
3. `_generate_translated_audio`: Generates translated audio using the translated content and the specified `VoiceModule`.
4. `_edit_and_render_video`: Edits and renders the translated video.
5. `_add_metadata`: Adds metadata to the translated video.

## Providing a Source URL

The `ContentTranslationEngine` requires a source URL, which can be either a local video file path or a YouTube link for a youtube Video, or a Youtube Shorts. The engine uses this source URL to retrieve the audio and video content for translation.

## Using Captions for Translation

Set the `use_captions` flag to `True` to see text captions on the video generated that are timed with the audio voice.



================================================
FILE: docs/docs/content-video-engine.mdx
================================================
---
title: ContentVideoEngine
sidebar_label: ContentVideoEngine
---

The `ContentVideoEngine` in ShortGPT is a powerful tool that encapsulates all the automation required to create a video. This guide will provide you with an overview of how to use the `ContentVideoEngine`.

## Importing ContentVideoEngine

```python
from shortGPT.engine.content_video_engine import ContentVideoEngine
```

## Initializing ContentVideoEngine

The `ContentVideoEngine` requires a `VoiceModule`, a script, and optionally a background music name, a watermark (string with the name of your channel / brand), a flag indicating whether the video you want is in vertical format, and a language.

```python
content_engine = ContentVideoEngine(voice_module, script, background_music_name="", watermark=None, isVerticalFormat=False, language=Language.ENGLISH)
```
## Example

```python
from shortGPT.config.api_db import ApiKeyManager, ApiProvider
from shortGPT.config.asset_db import AssetDatabase, AssetType
from shortGPT.engine.content_video_engine import ContentVideoEngine
from shortGPT.config.languages import Language
from shortGPT.audio.edge_voice_module import EdgeTTSVoiceModule, EDGE_TTS_VOICENAME_MAPPING

# Set API Keys
ApiKeyManager.set_api_key(ApiProvider.OPENAI, "your_openai_key")
ApiKeyManager.set_api_key(ApiProvider.PEXELS, "your_pexels_key")

# Add Assets
AssetDatabase.add_remote_asset('chill music', AssetType.BACKGROUND_MUSIC, "https://www.youtube.com/watch?v=uUu1NcSHg2E")

# Configure the Voice Module
voice_name = EDGE_TTS_VOICENAME_MAPPING[Language.SPANISH]['male']
voice_module = EdgeTTSVoiceModule(voice_name)

# Prepare the script
script = "La inteligencia artificial (IA) está revolucionando nuestro mundo de manera sorprendente. Los robots y asistentes virtuales nos ayudan en nuestras tareas diarias y simplifican nuestra vida. En la medicina, la IA permite diagnósticos más precisos y avances en tratamientos. En la industria automotriz, los vehículos autónomos están cambiando la forma en que nos desplazamos. Sin embargo, surgen interrogantes sobre el impacto en el empleo y la ética de su uso. A pesar de los desafíos, la IA promete un futuro emocionante y lleno de posibilidades. ¿Estamos preparados para abrazar este avance tecnológico?"

# Configure Content Engine
content_engine = ContentVideoEngine(voice_module, script, background_music_name='chill music', language=Language.SPANISH)

# Generate Content
for step_num, step_logs in content_engine.makeContent():
    print(f" {step_logs}")

# Get Video Output Path
print(content_engine.get_video_output_path())
```

In this example, we first set the API keys for OpenAI, and Pexels. We then add a remote asset for background music. We configure the voice module to use EdgeTTS for voice synthesis. We prepare a script for the video and then configure the `ContentVideoEngine` with the voice module, script, and background music. We then generate the content and print the output path of the video.
## How ContentVideoEngine Works

The `ContentVideoEngine` works by executing a series of steps defined in the `stepDict` dictionary. Each step is a method that performs a specific task in the video creation process. Here's what each step does:

1. `_generateTempAudio`: Generates a temporary audio file from the provided script using the specified `VoiceModule`.
2. `_speedUpAudio`: Speeds up the generated audio file to match the pace of a typical video.
3. `_timeCaptions`: Generates timed captions for the video based on the script.
4. `_generateVideoSearchTerms`: Generates search terms to find relevant videos on Pexels based on the script.
5. `_generateVideoUrls`: Retrieves video URLs from Pexels using the generated search terms.
6. `_chooseBackgroundMusic`: Chooses background music for the video.
7. `_prepareBackgroundAssets`: Prepares the background assets for the video.
8. `_prepareCustomAssets`: Prepares any custom assets for the video.
9. `_editAndRenderShort`: Edits and renders the video.
10. `_addMetadata`: Adds metadata to the video.

## Using Pexels API

The `ContentVideoEngine` sources video assets from the Pexels API. To use it, you need to provide your Pexels API key. The engine uses this key to retrieve relevant videos based on the search terms generated from the script.

## Providing a Script

The `ContentVideoEngine` requires a script to generate the video. The script is used to generate the audio, captions, and search terms for sourcing videos from Pexels. The script should be a string containing the narration for the video.

================================================
FILE: docs/docs/facts-short-engine.mdx
================================================
---
title: FactsShortEngine
sidebar_label: FactsShortEngine
---

The `FactsShortEngine` in ShortGPT is a content engine specifically designed for generating short videos that present interesting facts. This guide will provide you with an overview of how to use the `FactsShortEngine`.

## Importing FactsShortEngine

```python
from shortGPT.engine.facts_short_engine import FactsShortEngine
```

## Initializing FactsShortEngine

The `FactsShortEngine` requires a `VoiceModule`, the type of facts you want to generate, a background video name, a background music name,  the number of images to include in the video, a watermark (string with the name of your channel / brand), and a language.

```python
content_engine = FactsShortEngine(voice_module, facts_type, background_video_name, background_music_name, num_images=None, watermark=None, language=Language.ENGLISH)
```

## Example

```python
from shortGPT.config.api_db import ApiKeyManager, ApiProvider
from shortGPT.config.asset_db import AssetDatabase, AssetType
from shortGPT.engine.facts_short_engine import FactsShortEngine
from shortGPT.config.languages import Language
from shortGPT.audio.edge_voice_module import EdgeTTSVoiceModule, EDGE_TTS_VOICENAME_MAPPING

# Set API Keys
ApiKeyManager.set_api_key(ApiProvider.OPENAI, "your_openai_key")

# Add Assets
AssetDatabase.add_remote_asset("minecraft background cube", AssetType.BACKGROUND_VIDEO, "https://www.youtube.com/watch?v=Pt5_GSKIWQM")
AssetDatabase.add_remote_asset('chill music', AssetType.BACKGROUND_MUSIC, "https://www.youtube.com/watch?v=uUu1NcSHg2E")

# Configure the Voice Module
voice_name = EDGE_TTS_VOICENAME_MAPPING[Language.GERMAN]['male']
voice_module = EdgeTTSVoiceModule(voice_name)

# Configure Content Engine
facts_video_topic = "Interesting scientific facts from the 19th century"
content_engine = FactsShortEngine(voice_module=voice_module,
    facts_type=facts_video_topic,
    background_video_name="minecraft background cube", # <--- use the same name you saved in the AssetDatabase
    background_music_name='chill music', # <--- use the same name you saved in the AssetDatabase
    num_images=5, # If you don't want images in your video, put 0 or None
    language=Language.GERMAN)

# Generate Content
for step_num, step_logs in content_engine.makeContent():
    print(f" {step_logs}")

# Get Video Output Path
print(content_engine.get_video_output_path())
```

In this example, we first set the API keys for OpenAI. We then add remote assets for the background video and background music. We configure the voice module to use EdgeTTS for voice synthesis. We configure the `FactsShortEngine` with the voice module, facts type, background video name, background music name, number of images, and language. We then generate the content and print the output path of the video.

## How FactsShortEngine Works

The `FactsShortEngine` works by executing a series of steps defined in the `stepDict` dictionary. Each step is a method that performs a specific task in the video creation process. Here's what each step does:

1. `_generateScript`: Generates the script for the facts short using the provided `facts_type`.
2. `_generateTempAudio`: Generates a temporary audio file from the generated script using the specified `VoiceModule`.
3. `_speedUpAudio`: Speeds up the generated audio file to match the pace of a typical video.
4. `_timeCaptions`: Generates timed captions for the video based on the script.
5. `_generateImageSearchTerms`: Generates search terms to find relevant images using the Bing search engine based on the script.
6. `_generateImageUrls`: Retrieves image URLs from Bing using the generated search terms.
7. `_chooseBackgroundMusic`: Chooses background music for the video.
8. `_chooseBackgroundVideo`: Chooses a background video for the video.
9. `_prepareBackgroundAssets`: Prepares the background assets for the video.
10. `_prepareCustomAssets`: Prepares any custom assets for the video.
11. `_editAndRenderShort`: Edits and renders the video.
12. `_addYoutubeMetadata`: Adds metadata to the video.


## Providing a Facts Type

The `FactsShortEngine` requires a facts type to generate the script. The facts type should be a string indicating the specific category or topic of facts you want to include in the video.


That's it! You have now successfully generated a facts short video using the FactsShortEngine in the ShortGPT framework.

================================================
FILE: docs/docs/getting-started.mdx
================================================
---
title: ShortGPT Hello World Example
sidebar_label: ShortGPT Hello World Example
---
# ShortGPT Hello World Example

This guide provides a basic example of how to use the shortGPT framework. ShortGPT encapsulates the entire process of content automation into `content engines`. In this example, we'll show you how to instantiate the FactsShortEngine, which will automate the production of the "Interesting Facts" niche of Shorts.

## Prerequisites

Before you start, make sure you have [followed the installation steps](./how-to-install) and have your API keys ready.

## Code

```python
from shortGPT.config.api_db import ApiKeyManager, ApiProvider
from shortGPT.config.asset_db import AssetDatabase, AssetType
from shortGPT.engine.facts_short_engine import FactsShortEngine
from shortGPT.audio.eleven_voice_module import ElevenLabsVoiceModule
from shortGPT.config.languages import Language
from shortGPT.audio.edge_voice_module import EdgeTTSVoiceModule, EDGE_TTS_VOICENAME_MAPPING

# Set API Keys
ApiKeyManager.set_api_key(ApiProvider.OPENAI, "your_openai_key")
ApiKeyManager.set_api_key(ApiProvider.ELEVEN_LABS, "your_eleven_labs_key")

# Add Assets
AssetDatabase.add_remote_asset("minecraft background cube", AssetType.BACKGROUND_VIDEO, "https://www.youtube.com/watch?v=Pt5_GSKIWQM")
AssetDatabase.add_remote_asset('chill music', AssetType.BACKGROUND_MUSIC, "https://www.youtube.com/watch?v=uUu1NcSHg2E")
AssetDatabase.add_local_asset('my_music', AssetType.AUDIO, "./my_music.wav")

USE_ELEVEN_LABS = False
# Configure the ElevenLabs Voice Module
if USE_ELEVEN_LABS:
    eleven_labs_key = ApiKeyManager.get_api_key(ApiProvider.ELEVEN_LABS)
    voice_module = ElevenLabsVoiceModule(api_key = eleven_labs_key, voiceName="Chris")
else:
    ## You can also use the EdgeTTS for Free voice synthesis
    voice_name = EDGE_TTS_VOICENAME_MAPPING[Language.GERMAN]['male']
    voice_module = EdgeTTSVoiceModule(voice_name)

# Configure Content Engine
facts_video_topic = "Interesting scientific facts from the 19th century"
content_engine = FactsShortEngine(voiceModule=voice_module,
    facts_type=facts_video_topic,
    background_video_name="minecraft background cube", # <--- use the same name you saved in  the AssetDatabase
    background_music_name='chill music', # <--- use the same name you saved in  the AssetDatabase
    num_images=5, # If you don't want images in your video, put 0 or None
    language=Language.GERMAN)

# Generate Content
for step_num, step_logs in content_engine.makeContent():
    print(f" {step_logs}")

# Get Video Output Path
print(content_engine.get_video_output_path())
```

That's it! You have now successfully generated your first content using the shortGPT framework.


================================================
FILE: docs/docs/how-to-install.mdx
================================================
---
title: Step-by-Step Guide to Installing ShortGPT
sidebar_label: Installation Guide
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Launching Your ShortGPT Experience

This guide will walk you through the process of setting up your machine to run the **ShortGPT** library. The setup requires one  component: FFmpeg. Follow the steps below to get these dependencies installed.

## Before You Begin

Make sure you have the following installed on your machine:

- Python 3.x
- Pip (Python package installer)

## Installation Process

Here are the steps to install FFmpeg, and the ShortGPT library.

<Tabs groupId="operating-systems">
  <TabItem value="win" label="Windows">

After downloading, follow the installation instructions provided on the website.

### Step 1: Install FFmpeg (Essential for ShortGPT)

FFmpeg is another key component for ShortGPT. Download the FFmpeg binaries from the link below:

> **[👉 Download FFmpeg Here (click on 
FFmpeg_Full.msi ) 👈](https://github.com/icedterminal/ffmpeg-installer/releases/tag/6.0.0.20230306)**

The download will include ffmpeg and ffprobe and will add it to your path. Follow the installation instructions as guided.
<details open>
<summary><b>Step 3: Install ShortGPT Library</b></summary>

- Open a terminal or command prompt.
- Execute the following command:

```bash
pip install --upgrade shortgpt
```

</details>

  </TabItem>

  <TabItem value="mac" label="macOS">



### Step 1: Install FFmpeg (Essential for ShortGPT)

Run the command below in your command line:

```bash
brew install ffmpeg
```

<details open>
<summary><b>Step 3: Install ShortGPT Library</b></summary>

- Open a terminal or command prompt.
- Execute the following command:

```bash
pip install --upgrade shortgpt
```

</details>

  </TabItem>

  <TabItem value="ubuntu" label="Ubuntu/Debian-based systems">


### Step 1: Install FFmpeg

Execute the following command:

```bash
sudo apt-get install ffmpeg
```

<details open>
<summary><b>Step 3: Install ShortGPT Library</b></summary>

- Open a terminal or command prompt.
- Execute the following command:

```bash
pip install --upgrade shortgpt
```

</details>

  </TabItem>
</Tabs>

And there you have it! Your machine is now ready to run ShortGPT. Dive into the world of automated video content creation with ShortGPT!

================================================
FILE: docs/docusaurus.config.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
const lightCodeTheme = require('prism-react-renderer/themes/github');

// With JSDoc @type annotations, IDEs can provide config autocompletion
/** @type {import('@docusaurus/types').DocusaurusConfig} */
(
  module.exports = {
    title: 'ShortGPT',
    tagline:
      'Open-Source Framework for AI content automation',
    url: 'https://dev.shortgpt.ai',
    baseUrl: '/',
    favicon: 'img/favicon.ico',
    organizationName: 'RayVentura',
    projectName: 'ShortGPT',
    onBrokenLinks: 'throw',
    onBrokenMarkdownLinks: 'throw',
    presets: [
      [
        '@docusaurus/preset-classic',
        /** @type {import('@docusaurus/preset-classic').Options} */
        ({
          docs: {
            path: 'docs',
            sidebarPath: 'sidebars.js',
            editUrl:
              'https://github.com/RayVentura/ShortGPT/edit/stable/docs/',
            versions: {
              current: {
                label: 'current',
              },
            },
            lastVersion: 'current',
            showLastUpdateAuthor: true,
            showLastUpdateTime: true,
          },
          theme: {
            customCss: require.resolve('./src/css/custom.css'),
          },
        }),
      ],
    ],
    plugins: ['tailwind-loader'],
    themeConfig:
      /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
      ({
        
        navbar: {
          hideOnScroll: true,
          logo: {
            alt: 'ShortGPT',
            src: 'img/logo.png',
          },
          items: [
            // left
            {
              label: 'Docs',
              to: 'docs/how-to-install',
              position: 'right',
            },
            // right
            {
              type: 'docsVersionDropdown',
              position: 'right',
            },
            {
              href: 'https://github.com/RayVentura/ShortGPT',
              position: 'right',
              className: 'header-github-link',
            },
          ],
        },
        colorMode: {
          defaultMode: 'light',
          disableSwitch: false,
          respectPrefersColorScheme: true,
        },
        announcementBar: {
          content:
            '⭐️ If you like ShortGPT, give it a star on <a target="_blank" rel="noopener noreferrer" href="https://github.com/rayventura/shortgpt">GitHub</a>! ⭐️',
        },
        footer: {
          links: [
            {
              title: 'Docs',
              items: [
                {
                  label: 'Getting Started',
                  to: 'docs/how-to-install',
                },

              ],
            },
            {
              title: 'ShortGPT',
              items: [
                {
                  label: 'Issues',
                  to: 'https://github.com/RayVentura/ShortGPT/issues',
                },
              ],
            },
            {
              title: 'Community',
              items: [
                {
                  label: 'Discord',
                  to: 'https://discord.com/invite/bRTacwYrfX',
                },
              ],
            },
            {
              title: 'Social',
              items: [
                {
                  label: 'GitHub',
                  to: 'https://github.com/RayVentura/ShortGPT',
                },
                {
                  label: 'Twitter',
                  to: 'https://twitter.com/RayVenturaHQ',
                },
              ],
            },
          ],
          copyright: `ShortGPT ${new Date().getFullYear()}`,
        },
        prism: {
          theme: lightCodeTheme,
          darkTheme: darkCodeTheme,
        },
      }),
  }
);


================================================
FILE: docs/package.json
================================================
{
  "name": "shortgpt-documentation",
  "version": "3.5.1",
  "private": true,
  "scripts": {
    "build:clean": "rm -rf dist build .docusaurus node_modules",
    "docusaurus": "docusaurus",
    "start": "docusaurus start",
    "build": "docusaurus build",
    "swizzle": "docusaurus swizzle",
    "deploy": "docusaurus deploy",
    "clear": "docusaurus clear",
    "serve": "docusaurus serve",
    "write-translations": "docusaurus write-translations",
    "write-heading-ids": "docusaurus write-heading-ids"
  },
  "dependencies": {
    "@algolia/ui-library": "9.10.2",
    "@docsearch/react": "3.5.1",
    "@docusaurus/core": "2.4.1",
    "@docusaurus/preset-classic": "2.4.1",
    "@mdx-js/react": "^1.6.22",
    "clsx": "^1.1.1",
    "file-loader": "6.2.0",
    "my-loaders": "file:plugins/my-loaders",
    "postcss": "8.4.25",
    "postcss-import": "15.0.0",
    "postcss-preset-env": "7.8.2",
    "prism-react-renderer": "1.2.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "tailwind-loader": "file:plugins/tailwind-loader",
    "url-loader": "4.1.1"
  },
  "devDependencies": {
    "postcss-loader": "6.2.1",
    "tailwindcss": "npm:@tailwindcss/postcss7-compat"
  },
  "browserslist": {
    "production": [
      ">0.5%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

================================================
FILE: docs/plugins/my-loaders/index.js
================================================
module.exports = function () {
  return {
    name: 'loaders',
    configureWebpack() {
      return {
        module: {
          rules: [
            {
              test: /\.(gif|png|jpe?g|svg)$/i,
              exclude: /\.(mdx?)$/i,
              use: ['file-loader', { loader: 'image-webpack-loader' }],
            },
          ],
        },
      };
    },
  };
};


================================================
FILE: docs/plugins/tailwind-loader/index.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */
module.exports = function () {
  return {
    name: 'postcss-tailwindcss-loader',
    configurePostCss(postcssOptions) {
      postcssOptions.plugins.push(
        require('postcss-import'),
        require('tailwindcss'),
        require('postcss-preset-env')({
          autoprefixer: {
            flexbox: 'no-2009',
          },
          stage: 4,
        })
      );
      return postcssOptions;
    },
  };
};


================================================
FILE: docs/sidebars.js
================================================
/**
 * Creating a sidebar enables you to:
 * - create an ordered group of docs
 * - render a sidebar for each doc of that group
 * - provide next/previous navigation.
 *
 * The sidebars can be generated from the filesystem, or explicitly defined here.
 *
 * Create as many sidebars as you want.
 */

module.exports = {
  docs: [
    {
      type: 'category',
      label: 'Introduction',
      collapsed: false,
      items: ['how-to-install', 'getting-started'],
    },
    {
      type: 'category',
      label: 'Content Engines',
      collapsed: false,
      items: ['content-video-engine', 'content-translation-engine', 'facts-short-engine'],
    },
    {
      type: 'category',
      label: 'API Key and Asset',
      collapsed: false,
      items: ['api-key-manager', 'asset-database'],
    },
  ],
};


================================================
FILE: docs/src/components/Home.js
================================================
import { Hero } from '@algolia/ui-library';
import { useColorMode } from '@docusaurus/theme-common';
import { useBaseUrlUtils } from '@docusaurus/useBaseUrl';
import React from 'react';
import { Link } from 'react-router-dom';

function Home() {
  const { withBaseUrl } = useBaseUrlUtils();
  const { colorMode } = useColorMode();

  React.useEffect(() => {
    if (colorMode === 'dark') {
      document.querySelector('html').classList.add('dark');
    } else {
      document.querySelector('html').classList.remove('dark');
    }
  }, [colorMode]);

  function Header() {
    return (
      <Hero
        id="hero"
        title={
          <>

            <span className="hero-title text-4xl leading-10 font-extrabold text-blue-600 md:text-4xl lg:text-4xl md:leading-11 max-w-xs inline-block">
              🚀🎬 SHORTGPT
            </span>
            <span className="hero-title text-3xl leading-9 font-extrabold md:text-3xl lg:text-3xl md:leading-10 max-w-xxs inline-block">
              Opensource AI Content Automation Framework
            </span>
          </>
        }
        background="cubes"
        cta={[
          <Link
            key="get-started"
            to="/docs/how-to-install"
            className="inline-flex items-center justify-center px-6 py-3 border border-transparent text-base font-semibold rounded-full text-white bg-gradient-to-r from-purple-500 to-indigo-500 hover:from-purple-600 hover:to-indigo-600 hover:no-underline"
          >
            Get started
          </Link>
        ]}
      />
    );
  }

  function Description() {
    return (
      <>
        {/* Description */}
        <div className="py-8 overflow-hidden">
          <div className="relative max-w-xl mx-auto px-4 md:px-6 lg:px-8 lg:max-w-screen-xl">
            <div className="relative">
              <h3 className="text-center text-3xl leading-8 font-extrabold tracking-tight md:text-4xl md:leading-10">
                Automating video and short content creation with AI
              </h3>
              <p className="mt-4 max-w-3xl mx-auto text-center text-xl leading-7 text-description">
                ShortGPT is a powerful framework for automating content creation. It simplifies video creation, footage sourcing, voiceover synthesis, and editing tasks.
              </p>
            </div>

            <div className="pt-16">
              <ul className="lg:grid lg:grid-cols-3 lg:col-gap-8 lg:row-gap-10">
                <li>
                  <div className="flex">
                    <div className="flex-shrink-0">
                      <div className="flex items-center justify-center h-12 w-12 rounded-md bg-indigo-500 text-white">
                        <svg
                          viewBox="0 0 20 20"
                          fill="currentColor"
                          className="search w-6 h-6"
                        >
                          <path
                            fillRule="evenodd"
                            d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
                            clipRule="evenodd"
                          ></path>
                        </svg>
                      </div>
                    </div>
                    <div className="ml-4">
                      <h4 className="text-lg leading-6 font-medium">
                        Automated editing framework
                      </h4>
                      <p className="mt-2 text-base leading-6 text-description">
                        ShortGPT streamlines the video creation process with an LLM oriented video editing language, making it easier to automate editing tasks.
                      </p>
                    </div>
                  </div>
                </li>
                <li className="mt-10 lg:mt-0">
                  <div className="flex">
                    <div className="flex-shrink-0">
                      <div className="flex items-center justify-center h-12 w-12 rounded-md bg-indigo-500 text-white">
                        <svg
                          fill="none"
                          viewBox="0 0 24 24"
                          stroke="currentColor"
                          className="user-group w-6 h-6"
                        >
                          <path
                            strokeLinecap="round"
                            strokeLinejoin="round"
                            strokeWidth="2"
                            d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
                          ></path>
                        </svg>
                      </div>
                    </div>
                    <div className="ml-4">
                      <h4 className="text-lg leading-6 font-medium">
                        Voiceover / Content Creation
                      </h4>
                      <p className="mt-2 text-base leading-6 text-description">
                        ShortGPT supports multiple languages for voiceover synthesis, making it easy to create content in various languages.
                      </p>
                    </div>
                  </div>
                </li>
                <li className="mt-10 lg:mt-0">
                  <div className="flex">
                    <div className="flex-shrink-0">
                      <div className="flex items-center justify-center h-12 w-12 rounded-md bg-indigo-500 text-white">
                        <svg
                          fill="none"
                          viewBox="0 0 24 24"
                          stroke="currentColor"
                          className="device-mobile w-6 h-6"
                        >
                          <path
                            strokeLinecap="round"
                            strokeLinejoin="round"
                            strokeWidth="2"
                            d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"
                          ></path>
                        </svg>
                      </div>
                    </div>
                    <div className="ml-4">
                      <h4 className="text-lg leading-6 font-medium">
                        Asset Sourcing
                      </h4>
                      <p className="mt-2 text-base leading-6 text-description">
                        ShortGPT can source images and video footage from the internet, allowing you to easily find and use relevant visuals.
                      </p>
                    </div>
                  </div>
                </li>
              </ul>
            </div>
          </div>
        </div>

        {/* How it works */}
        <div className="diagonal-box py-16 bg-gray-200 overflow-hidden">
          <div className="diagonal-content max-w-xl mx-auto px-4 md:px-6 lg:px-8 lg:max-w-screen-xl">
            <div className="max-w-screen-xl mx-auto pt-6 px-4 md:px-6 lg:px-8">
              <div className="max-w-4xl mx-auto text-center">
                <h2 className="text-3xl leading-9 font-extrabold text-gray-900 md:text-4xl md:leading-10">
                  How it works
                </h2>
                <p className="mt-4 max-w-2xl text-xl leading-7 text-gray-500 lg:mx-auto">
                ShortGPT is an AI-powered framework that automates the process of content creation, from script generation to asset sourcing and video editing.
                </p>
              </div>
            </div>

            <div className="py-16">
              <div className="max-w-xl mx-auto px-4 md:px-6 lg:max-w-screen-lg lg:px-8 ">
                <div className="lg:grid lg:grid-cols-3 lg:gap-8">
                  <div>
                    <div className="flex items-center justify-center">
                      <img
                        className="h-200"
                        src={withBaseUrl('img/assets/scraping.svg')}
                        width="190px"
                        height="220px"
                      />
                    </div>
                    <div className="mt-10 lg:mt-0 p-4">
                      <h5 className="text-lg leading-6 font-medium text-gray-900">
                        Automated Editing Framework
                      </h5>
                      <p className="mt-2 text-base leading-6 text-gray-600">
                      ShortGPT employs a heavy usage of LLMs and automated video editing libraries to streamline the video creation process (Ffmpeg, moviepy, ffprobe).
                      </p>
                    </div>
                  </div>
                  <div className="mt-10 lg:mt-0 p-4">
                    <div className="h-200 flex items-center justify-center">
                      <img
                        src={withBaseUrl('img/assets/configuration.svg')}
                        width="140px"
                        height="220px"
                        alt="Configuration of your crawler"
                      />
                    </div>
                    <div>
                      <h5 className="text-lg leading-6 font-medium text-gray-900">
                        Voiceover / Content Creation
                      </h5>
                      <p className="mt-2 text-base leading-6 text-gray-600">
                      ShortGPT integrates multiple neural voice synthesis engines (ElevenLabs, EdgeTTS), to allow human-like voice quality in the audio generated.
                      </p>
                    </div>
                  </div>
                  <div className="mt-10 lg:mt-0 p-4">
                    <div className="h-200 flex items-center justify-center">
                      <img
                        src={withBaseUrl('img/assets/implementation.svg')}
                        width="220px"
                        height="220px"
                        alt="Implementation on your website"
                      />
                    </div>
                    <div>
                      <h5 className="text-lg leading-6 font-medium text-gray-900">
                        Asset Sourcing
                      </h5>
                      <p className="mt-2 text-base leading-6 text-gray-600">
                      ShortGPT is equipped with an advanced asset sourcing module that can retrieve images and video footage from the internet. This feature allows for the easy incorporation of relevant visuals into the content (Pexels, youtube, and more soon).
                      </p>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>

    

        {/* Powered by AI */}
        <div className="py-16 bg-indigo-600 overflow-hidden lg:py-24">
          <div className="text-center">
            <h3 className="mt-2 text-3xl leading-8 font-extrabold text-white tracking-tight md:text-4xl md:leading-10">
              Powered by AI
            </h3>
          </div>
          <div className="relative max-w-xl mx-auto px-4 md:px-6 lg:px-8 lg:max-w-screen-xl">
            <div className="relative lg:grid lg:grid-cols-2 lg:gap-8 lg:items-center">
              <div className="relative">
                <ul className="mt-10">
                  <li className="mt-10">
                    <div className="flex">
                      <div className="flex-shrink-0">
                        <div className="flex items-center justify-center h-12 w-12 rounded-md bg-white text-indigo-500">
                          <svg
                            fill="none"
                            viewBox="0 0 24 24"
                            stroke="currentColor"
                            className="chip w-6 h-6"
                          >
                            <path
                              strokeLinecap="round"
                              strokeLinejoin="round"
                              strokeWidth="2"
                              d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"
                            ></path>
                          </svg>
                        </div>
                      </div>
                      <div className="ml-4">
                        <h5 className="text-lg leading-6 font-medium text-white">
                          Automated Editing
                        </h5>
                        <p className="mt-2 text-base leading-6 text-gray-300">
                          ShortGPT automates the video editing process, making it faster and more efficient with the help of AI.
                        </p>
                      </div>
                    </div>
                  </li>
                  <li className="mt-10">
                    <div className="flex">
                      <div className="flex-shrink-0">
                        <div className="flex items-center justify-center h-12 w-12 rounded-md bg-white text-indigo-500">
                          <svg
                            fill="none"
                            viewBox="0 0 24 24"
                            stroke="currentColor"
                            className="chat w-6 h-6"
                          >
                            <path
                              strokeLinecap="round"
                              strokeLinejoin="round"
                              strokeWidth="2"
                              d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
                            ></path>
                          </svg>
                        </div>
                      </div>
                      <div className="ml-4">
                        <h5 className="text-lg leading-6 font-medium text-white">
                          Voiceover / Content Creation
                        </h5>
                        <p className="mt-2 text-base leading-6 text-gray-300">
                          ShortGPT supports multiple languages for voiceover synthesis, making it easy to create content in various languages.
                        </p>
                      </div>
                    </div>
                  </li>
                </ul>
              </div>

              <div className="relative">
                <ul className="mt-10">
                  <li className="mt-10">
                    <div className="flex">
                      <div className="flex-shrink-0">
                        <div className="flex items-center justify-center h-12 w-12 rounded-md bg-white text-indigo-500">
                          <svg
                            fill="none"
                            viewBox="0 0 24 24"
                            stroke="currentColor"
                            className="backspace w-6 h-6"
                          >
                            <path
                              strokeLinecap="round"
                              strokeLinejoin="round"
                              strokeWidth="2"
                              d="M12 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2M3 12l6.414 6.414a2 2 0 001.414.586H19a2 2 0 002-2V7a2 2 0 00-2-2h-8.172a2 2 0 00-1.414.586L3 12z"
                            ></path>
                          </svg>
                        </div>
                      </div>
                      <div className="ml-4">
                        <h5 className="text-lg leading-6 font-medium text-white">
                          Asset Sourcing
                        </h5>
                        <p className="mt-2 text-base leading-6 text-gray-300">
                          ShortGPT can source images and video footage from the internet, allowing you to easily find and use relevant visuals.
                        </p>
                      </div>
                    </div>
                  </li>
                </ul>
              </div>
            </div>
          </div>
        </div>
      </>
    )
  }



  return (
    <div id="tailwind">
      <Header />
      <Description />
    </div>
  );
}

export default Home;


================================================
FILE: docs/src/css/custom.css
================================================
@import url(fragments.css);
@import 'tailwindcss/tailwind.css';

:root {
  --ifm-font-size-base: 16px;
  --ifm-code-font-size: 90%;
  --ifm-background-color: var(--white);
  --ifm-color-primary: var(--nebula-500);
  --ifm-footer-background-color: var(--grey-100);
  --ifm-menu-color-background-active: var(--ifm-color-emphasis-200);
}

html[data-theme='dark'] {
  --ifm-font-base-color: #dee0f2;
  --ifm-navbar-link-hover-color: #8b9dff;
  --ifm-link-color: #8b9dff;
  --ifm-menu-color-active: #8b9dff;
  --ifm-background-color: #0a141c;
  --ifm-footer-background-color: #0a141c;
  --ifm-navbar-background-color: #21243d;
  --ifm-menu-color-background-active: #21243d;
}

.docusaurus-highlight-code-line {
  background-color: rgba(0, 0, 0, 0.1);
  display: block;
  margin: 0 calc(-1 * var(--ifm-pre-padding));
  padding: 0 var(--ifm-pre-padding);
}

html[data-theme='dark'] .docusaurus-highlight-code-line {
  background-color: rgba(0, 0, 0, 0.3);
}

.diagonal-box {
  transform: skewY(-6deg);
}

.diagonal-content {
  transform: skewY(6deg);
}

[class^='announcementBar'] {
  z-index: 10;
}

.showcase {
  background-color: #fff;
}

html[data-theme='dark'] .showcase {
  background-color: #21243d;
}

.showcase-border {
  border-color: rgba(243, 244, 246, 1);
}

html[data-theme='dark'] .showcase-border {
  border-color: rgba(55, 65, 81, 1);
}

.text-description {
  color: rgba(107, 114, 128, 1);
}

html[data-theme='dark'] .text-description {
  color: rgba(209, 213, 219, 1);
}

/* apply */
#hero-apply {
  z-index: -1;
  background-image: linear-gradient(
    var(--ifm-footer-background-color),
    var(--ifm-navbar-background-color)
  );
}

html[data-theme='dark'] #hero-apply {
  background-image: linear-gradient(
    var(--ifm-navbar-background-color),
    var(--ifm-background-color)
  );
}

html[data-theme='dark'] #hero-apply > div:first-child {
  opacity: 0.4;
}

.apply-form {
  background-image: linear-gradient(#fff, #f5f5fa);
  max-width: 600px;
}

html[data-theme='dark'] .apply-form {
  background-image: radial-gradient(
    circle at 50% 0px,
    rgb(72, 76, 122),
    rgb(35, 38, 59)
  );
}

.apply-text {
  color: #36395a;
}

html[data-theme='dark'] .apply-text {
  color: #fff;
}

/* index */
#hero {
  background-image: linear-gradient(
    var(--ifm-footer-background-color),
    var(--ifm-navbar-background-color)
  );
}

html[data-theme='dark'] #hero {
  background-image: linear-gradient(
    var(--ifm-navbar-background-color),
    var(--ifm-background-color)
  );
}

html[data-theme='dark'] #hero > div:first-child {
  opacity: 0.4;
}

/**
  * Hero component title overrides to match other heading styles
  */
.hero-title {
  color: rgb(28, 30, 33);
  font-family: var(--ifm-heading-font-family);
}

html[data-theme='dark'] .hero-title {
  color: rgb(227, 227, 227);
}


.apply-button:hover {
  color: #000000;
}

/* GitHub */
.header-github-link:hover {
  opacity: 0.6;
}

.header-github-link:before {
  content: '';
  width: 24px;
  height: 24px;
  display: flex;
  background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")
    no-repeat;
}

html[data-theme='dark'] .header-github-link:before {
  background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")
    no-repeat;
}

/* Images */
.image-rendering-crisp {
  image-rendering: crisp-edges;

  /* alias for google chrome */
  image-rendering: -webkit-optimize-contrast;
}

.image-rendering-pixel {
  image-rendering: pixelated;
}

/* Tailwindcss */

#tailwind dd,
#tailwind dt {
  margin: 0;
}

#tailwind *,
#tailwind ::before,
#tailwind ::after {
  border-width: 0;
  border-style: solid;
}

#tailwind ol,
#tailwind ul {
  list-style: none;
  margin: 0;
  padding: 0;
}


================================================
FILE: docs/src/css/fragments.css
================================================
:root {
  --transparent: transparent;
  --white: #fff;
  --grey-900: #23263b;
  --grey-800: #36395a;
  --grey-700: #484c7a;
  --grey-600: #5a5e9a;
  --grey-500: #777aaf;
  --grey-400: #9698c3;
  --grey-300: #b6b7d5;
  --grey-200: #d6d6e7;
  --grey-100: #f5f5fa;
  --grey-050: #fcfcfd;
  --grey-000: #fff;
  --pink-900: #59063d;
  --pink-800: #88085c;
  --pink-700: #b80979;
  --pink-600: #e90a96;
  --pink-500: #f82caa;
  --pink-400: #fb5abc;
  --pink-300: #fd89ce;
  --pink-200: #feb9e2;
  --pink-100: #ffeaf6;
  --nebula-900: #141d61;
  --nebula-800: #1e2b8f;
  --nebula-700: #2b3cbb;
  --nebula-600: #3c4fe0;
  --nebula-500: #5468ff;
  --nebula-400: #7c8aff;
  --nebula-300: #a3acff;
  --nebula-200: #cacfff;
  --nebula-100: #f2f3ff;
  --cyan-900: #00526c;
  --cyan-800: #00769b;
  --cyan-700: #009bcb;
  --cyan-600: #0db7eb;
  --cyan-500: #2cc8f7;
  --cyan-400: #5adaff;
  --cyan-300: #89e5ff;
  --cyan-200: #b9efff;
  --cyan-100: #e8faff;
  --green-900: #005e36;
  --green-800: #028950;
  --green-700: #06b66c;
  --green-600: #0de589;
  --green-500: #5feb9e;
  --green-400: #88f0b3;
  --green-300: #aaf4c8;
  --green-200: #c9f8de;
  --green-100: #e6fcf3;
  --orange-900: #963209;
  --orange-800: #bf470a;
  --orange-700: #e8600a;
  --orange-600: #f78125;
  --orange-500: #faa04b;
  --orange-400: #fcbc73;
  --orange-300: #fed59a;
  --orange-200: #ffe9c3;
  --orange-100: #fff9ec;
  --red-900: #83111e;
  --red-800: #ab1325;
  --red-700: #d4142a;
  --red-600: #ee243c;
  --red-500: #f4495d;
  --red-400: #f86e7e;
  --red-300: #fc95a1;
  --red-200: #febdc5;
  --red-100: #ffe6e9;
  --current: currentColor;
}
.uil-bgc-transparent {
  background-color: transparent;
}
.uil-bgc-white {
  background-color: #fff;
}
.uil-bgc-grey-900 {
  background-color: #23263b;
}
.uil-bgc-grey-800 {
  background-color: #36395a;
}
.uil-bgc-grey-200 {
  background-color: #d6d6e7;
}
.hover\:uil-bgc-grey-100:focus,
.hover\:uil-bgc-grey-100:hover,
.uil-bgc-grey-100 {
  background-color: #f5f5fa;
}
.uil-bgc-pink-200 {
  background-color: #feb9e2;
}
.uil-bgc-nebula-500 {
  background-color: #5468ff;
}
.uil-bgc-nebula-200 {
  background-color: #cacfff;
}
.uil-bgc-green-200 {
  background-color: #c9f8de;
}
.uil-bgc-orange-200 {
  background-color: #ffe9c3;
}
.uil-bgc-red-600 {
  background-color: #ee243c;
}
.uil-bgc-red-500 {
  background-color: #f4495d;
}
.uil-bgc-current {
  background-color: currentColor;
}
@media (min-width: 960px) {
  .md\:uil-bgc-transparent {
    background-color: transparent;
  }
}
@media (min-width: 960px) {
  .md\:uil-bgc-white {
    background-color: #fff;
  }
}
@media (min-width: 960px) {
  .md\:uil-bgc-grey-900 {
    background-color: #23263b;
  }
}
.uil-bgp-center {
  background-position: 50%;
}
.uil-bgp-bottom {
  background-position: bottom;
}
.uil-bgr-no-repeat {
  background-repeat: no-repeat;
}
@media (min-width: 960px) {
  .md\:uil-bgr-no-repeat {
    background-repeat: no-repeat;
  }
}
.uil-bgs-cover {
  background-size: cover;
}
.uil-bgs-contain {
  background-size: contain;
}
@media (min-width: 960px) {
  .md\:uil-bgs-contain {
    background-size: contain;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-bgs-cover {
    background-size: cover;
  }
}
.uil-bd-none {
  border: none;
}
.uil-bdc-transparent {
  border-color: transparent;
}
.uil-bdc-grey-800 {
  border-color: #36395a;
}
.uil-bdc-grey-700 {
  border-color: #484c7a;
}
.uil-bdc-grey-200 {
  border-color: #d6d6e7;
}
.uil-bdc-grey-100 {
  border-color: #f5f5fa;
}
.uil-bdc-pink-600 {
  border-color: #e90a96;
}
.uil-bdc-nebula-500 {
  border-color: #5468ff;
}
.uil-bdc-green-700 {
  border-color: #06b66c;
}
.uil-bdc-orange-600 {
  border-color: #f78125;
}
.uil-bdc-red-600 {
  border-color: #ee243c;
}
@media (min-width: 960px) {
  .md\:uil-bdc-transparent {
    border-color: transparent;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdc-white {
    border-color: #fff;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdc-grey-800 {
    border-color: #36395a;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdc-grey-200 {
    border-color: #d6d6e7;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdc-pink-600 {
    border-color: #e90a96;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdc-nebula-500 {
    border-color: #5468ff;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdc-green-700 {
    border-color: #06b66c;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdc-orange-600 {
    border-color: #f78125;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdc-red-600 {
    border-color: #ee243c;
  }
}
.uil-bdr-0 {
  border-radius: 0;
}
.uil-bdr-2 {
  border-radius: 2px;
}
.uil-bdr-4 {
  border-radius: 4px;
}
.uil-bdr-6 {
  border-radius: 6px;
}
.uil-bdr-8 {
  border-radius: 8px;
}
.uil-bdr-20 {
  border-radius: 20px;
}
.uil-bdr-max {
  border-radius: 9999px;
}
@media (min-width: 960px) {
  .md\:uil-bdr-4 {
    border-radius: 4px;
  }
}
.uil-bdtlr-0 {
  border-top-left-radius: 0;
}
.uil-bdtlr-2 {
  border-top-left-radius: 2px;
}
.uil-bdtlr-4 {
  border-top-left-radius: 4px;
}
.uil-bdtlr-6 {
  border-top-left-radius: 6px;
}
.uil-bdtlr-8 {
  border-top-left-radius: 8px;
}
.uil-bdtlr-20 {
  border-top-left-radius: 20px;
}
.uil-bdtrr-0 {
  border-top-right-radius: 0;
}
.uil-bdtrr-2 {
  border-top-right-radius: 2px;
}
.uil-bdtrr-4 {
  border-top-right-radius: 4px;
}
.uil-bdtrr-6 {
  border-top-right-radius: 6px;
}
.uil-bdtrr-8 {
  border-top-right-radius: 8px;
}
.uil-bdtrr-20 {
  border-top-right-radius: 20px;
}
.uil-bdblr-0 {
  border-bottom-left-radius: 0;
}
.uil-bdblr-6 {
  border-bottom-left-radius: 6px;
}
.uil-bdbrr-0 {
  border-bottom-right-radius: 0;
}
.uil-bdbrr-6 {
  border-bottom-right-radius: 6px;
}
@media (min-width: 960px) {
  .md\:uil-bdbr-6 {
    border-bottom-left-radius: 6px;
    border-bottom-right-radius: 6px;
  }
}
.uil-bds-solid {
  border-style: solid;
}
@media (min-width: 960px) {
  .md\:uil-bds-solid {
    border-style: solid;
  }
}
.uil-bdts-solid {
  border-top-style: solid;
}
.uil-bdrs-solid {
  border-right-style: solid;
}
.uil-bdbs-solid {
  border-bottom-style: solid;
}
@media (min-width: 960px) {
  .md\:uil-bdbs-solid {
    border-bottom-style: solid;
  }
}
.uil-bdw-0 {
  border-width: 0;
}
.uil-bdw-1 {
  border-width: 1px;
}
@media (min-width: 960px) {
  .md\:uil-bdw-0 {
    border-width: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdw-2 {
    border-width: 2px;
  }
}
@media (min-width: 960px) {
  .md\:uil-bdlw-1 {
    border-left-width: 1px;
  }
}
.uil-bdtw-1 {
  border-top-width: 1px;
}
.uil-bdtw-2 {
  border-top-width: 2px;
}
@media (min-width: 960px) {
  .md\:uil-bdtw-1 {
    border-top-width: 1px;
  }
}
.uil-bdrw-1 {
  border-right-width: 1px;
}
.uil-bdbw-0 {
  border-bottom-width: 0;
}
.uil-bdbw-1 {
  border-bottom-width: 1px;
}
@media (min-width: 960px) {
  .md\:uil-bdbw-1 {
    border-bottom-width: 1px;
  }
}
.uil-d-none {
  display: none;
}
.uil-d-block {
  display: block;
}
.uil-d-inline-block {
  display: inline-block;
}
.uil-d-flex {
  display: flex;
}
.uil-d-inline-flex {
  display: inline-flex;
}
.uil-d-grid {
  display: grid;
}
@media (min-width: 500px) {
  .xs\:uil-d-block {
    display: block;
  }
}
@media (min-width: 768px) {
  .sm\:uil-d-flex {
    display: flex;
  }
}
@media (min-width: 768px) {
  .sm\:uil-d-grid {
    display: grid;
  }
}
@media (min-width: 960px) {
  .md\:uil-d-none {
    display: none;
  }
}
@media (min-width: 960px) {
  .md\:uil-d-block {
    display: block;
  }
}
@media (min-width: 960px) {
  .md\:uil-d-flex {
    display: flex;
  }
}
@media (min-width: 960px) {
  .md\:uil-d-grid {
    display: grid;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-d-none {
    display: none;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-d-block {
    display: block;
  }
}
@media (min-width: 1440px) {
  .xl\:uil-d-inline-block {
    display: inline-block;
  }
}
.uil-m-0 {
  margin: 0;
}
.uil-m-8 {
  margin: 8px;
}
.uil-m-auto {
  margin: auto;
}
@media (min-width: 960px) {
  .md\:uil-m-0 {
    margin: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-m-auto {
    margin: auto;
  }
}
.uil-ml-0 {
  margin-left: 0;
}
.uil-ml-8 {
  margin-left: 8px;
}
.uil-ml-12 {
  margin-left: 12px;
}
.uil-ml-auto {
  margin-left: auto;
}
@media (min-width: 500px) {
  .xs\:uil-ml-24 {
    margin-left: 24px;
  }
}
@media (min-width: 768px) {
  .sm\:uil-ml-12 {
    margin-left: 12px;
  }
}
@media (min-width: 768px) {
  .sm\:uil-ml-24 {
    margin-left: 24px;
  }
}
@media (min-width: 960px) {
  .md\:uil-ml-0 {
    margin-left: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-ml-8 {
    margin-left: 8px;
  }
}
@media (min-width: 960px) {
  .md\:uil-ml-50p {
    margin-left: 50%;
  }
}
@media (min-width: 960px) {
  .md\:uil-ml-auto {
    margin-left: auto;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ml-16 {
    margin-left: 16px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ml-48 {
    margin-left: 48px;
  }
}
@media (min-width: 1440px) {
  .xl\:uil-ml-16 {
    margin-left: 16px;
  }
}
.uil-mt-0 {
  margin-top: 0;
}
.uil-mt-4 {
  margin-top: 4px;
}
.uil-mt-8 {
  margin-top: 8px;
}
.uil-mt-12 {
  margin-top: 12px;
}
.uil-mt-16 {
  margin-top: 16px;
}
.uil-mt-20 {
  margin-top: 20px;
}
.uil-mt-24 {
  margin-top: 24px;
}
.uil-mt-32 {
  margin-top: 32px;
}
.uil-mt-48 {
  margin-top: 48px;
}
.uil-mt-80 {
  margin-top: 80px;
}
@media (min-width: 500px) {
  .xs\:uil-mt-0 {
    margin-top: 0;
  }
}
@media (min-width: 768px) {
  .sm\:uil-mt-0 {
    margin-top: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-mt-0 {
    margin-top: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-mt-8 {
    margin-top: 8px;
  }
}
@media (min-width: 960px) {
  .md\:uil-mt-12 {
    margin-top: 12px;
  }
}
@media (min-width: 960px) {
  .md\:uil-mt-auto {
    margin-top: auto;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mt-8 {
    margin-top: 8px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mt-12 {
    margin-top: 12px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mt-20 {
    margin-top: 20px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mt-48 {
    margin-top: 48px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mt-120 {
    margin-top: 120px;
  }
}
.uil-mr-0 {
  margin-right: 0;
}
.uil-mr-4 {
  margin-right: 4px;
}
.uil-mr-8 {
  margin-right: 8px;
}
.uil-mr-16 {
  margin-right: 16px;
}
.uil-mr-32 {
  margin-right: 32px;
}
.uil-mr-auto {
  margin-right: auto;
}
@media (min-width: 960px) {
  .md\:uil-mr-0 {
    margin-right: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-mr-8 {
    margin-right: 8px;
  }
}
@media (min-width: 960px) {
  .md\:uil-mr-20 {
    margin-right: 20px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mr-12 {
    margin-right: 12px;
  }
}
.uil-mb-0 {
  margin-bottom: 0;
}
.uil-mb-8 {
  margin-bottom: 8px;
}
.uil-mb-12 {
  margin-bottom: 12px;
}
.uil-mb-16 {
  margin-bottom: 16px;
}
.uil-mb-20 {
  margin-bottom: 20px;
}
.uil-mb-24 {
  margin-bottom: 24px;
}
.uil-mb-48 {
  margin-bottom: 48px;
}
@media (min-width: 768px) {
  .sm\:uil-mb-0 {
    margin-bottom: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-mb-0 {
    margin-bottom: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-mb-16 {
    margin-bottom: 16px;
  }
}
@media (min-width: 960px) {
  .md\:uil-mb-24 {
    margin-bottom: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mb-20 {
    margin-bottom: 20px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mb-24 {
    margin-bottom: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-mb-80 {
    margin-bottom: 80px;
  }
}
.uil-mv-0 {
  margin-top: 0;
  margin-bottom: 0;
}
.uil-mv-8 {
  margin-top: 8px;
  margin-bottom: 8px;
}
.uil-mh-0 {
  margin-left: 0;
  margin-right: 0;
}
.uil-mh-auto {
  margin-left: auto;
  margin-right: auto;
}
@media (min-width: 960px) {
  .md\:uil-mh-12 {
    margin-left: 12px;
    margin-right: 12px;
  }
}
.uil-ov-visible {
  overflow: visible;
}
.uil-ov-hidden {
  overflow: hidden;
}
.uil-ov-auto {
  overflow: auto;
}
@media (min-width: 960px) {
  .md\:uil-ov-hidden {
    overflow: hidden;
  }
}
.uil-ovx-scroll {
  overflow-x: scroll;
}
.uil-ovx-auto {
  overflow-x: auto;
}
.uil-ovy-hidden {
  overflow-y: hidden;
}
.uil-ovy-auto {
  overflow-y: auto;
}
.uil-p-0 {
  padding: 0;
}
.uil-p-8 {
  padding: 8px;
}
.uil-p-12 {
  padding: 12px;
}
.uil-p-20 {
  padding: 20px;
}
.uil-p-24 {
  padding: 24px;
}
.uil-p-48 {
  padding: 48px;
}
@media (min-width: 960px) {
  .md\:uil-p-48 {
    padding: 48px;
  }
}
.uil-pl-0 {
  padding-left: 0;
}
.uil-pl-8 {
  padding-left: 8px;
}
.uil-pl-12 {
  padding-left: 12px;
}
.uil-pl-16 {
  padding-left: 16px;
}
.uil-pl-24 {
  padding-left: 24px;
}
.uil-pl-48 {
  padding-left: 48px;
}
@media (min-width: 960px) {
  .md\:uil-pl-24 {
    padding-left: 24px;
  }
}
@media (min-width: 960px) {
  .md\:uil-pl-48 {
    padding-left: 48px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pl-32 {
    padding-left: 32px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pl-48 {
    padding-left: 48px;
  }
}
.uil-pt-0 {
  padding-top: 0;
}
.uil-pt-12 {
  padding-top: 12px;
}
.uil-pt-16 {
  padding-top: 16px;
}
.uil-pt-24 {
  padding-top: 24px;
}
.uil-pt-32 {
  padding-top: 32px;
}
.uil-pt-48 {
  padding-top: 48px;
}
@media (min-width: 960px) {
  .md\:uil-pt-0 {
    padding-top: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-pt-24 {
    padding-top: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pt-24 {
    padding-top: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pt-32 {
    padding-top: 32px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pt-48 {
    padding-top: 48px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pt-80 {
    padding-top: 80px;
  }
}
.uil-pr-0 {
  padding-right: 0;
}
.uil-pr-8 {
  padding-right: 8px;
}
.uil-pr-16 {
  padding-right: 16px;
}
.uil-pr-24 {
  padding-right: 24px;
}
.uil-pr-32 {
  padding-right: 32px;
}
.uil-pr-48 {
  padding-right: 48px;
}
.uil-pr-80 {
  padding-right: 80px;
}
@media (min-width: 960px) {
  .md\:uil-pr-0 {
    padding-right: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-pr-24 {
    padding-right: 24px;
  }
}
@media (min-width: 960px) {
  .md\:uil-pr-48 {
    padding-right: 48px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pr-8 {
    padding-right: 8px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pr-48 {
    padding-right: 48px;
  }
}
.uil-pb-0 {
  padding-bottom: 0;
}
.uil-pb-12 {
  padding-bottom: 12px;
}
.uil-pb-16 {
  padding-bottom: 16px;
}
.uil-pb-24 {
  padding-bottom: 24px;
}
.uil-pb-48 {
  padding-bottom: 48px;
}
.uil-pb-80 {
  padding-bottom: 80px;
}
@media (min-width: 960px) {
  .md\:uil-pb-24 {
    padding-bottom: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pb-24 {
    padding-bottom: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pb-48 {
    padding-bottom: 48px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pb-80 {
    padding-bottom: 80px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pb-120 {
    padding-bottom: 120px;
  }
}
.uil-pv-8 {
  padding-top: 8px;
  padding-bottom: 8px;
}
.uil-pv-16 {
  padding-top: 16px;
  padding-bottom: 16px;
}
.uil-pv-20 {
  padding-top: 20px;
  padding-bottom: 20px;
}
.uil-pv-24 {
  padding-top: 24px;
  padding-bottom: 24px;
}
.uil-pv-32 {
  padding-top: 32px;
  padding-bottom: 32px;
}
.uil-pv-48 {
  padding-top: 48px;
  padding-bottom: 48px;
}
.uil-pv-80 {
  padding-top: 80px;
  padding-bottom: 80px;
}
@media (min-width: 960px) {
  .md\:uil-pv-120 {
    padding-top: 120px;
    padding-bottom: 120px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pv-32 {
    padding-top: 32px;
    padding-bottom: 32px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pv-48 {
    padding-top: 48px;
    padding-bottom: 48px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-pv-120 {
    padding-top: 120px;
    padding-bottom: 120px;
  }
}
.uil-ph-0 {
  padding-left: 0;
  padding-right: 0;
}
.uil-ph-4 {
  padding-left: 4px;
  padding-right: 4px;
}
.uil-ph-8 {
  padding-left: 8px;
  padding-right: 8px;
}
.uil-ph-12 {
  padding-left: 12px;
  padding-right: 12px;
}
.uil-ph-16 {
  padding-left: 16px;
  padding-right: 16px;
}
.uil-ph-20 {
  padding-left: 20px;
  padding-right: 20px;
}
.uil-ph-24 {
  padding-left: 24px;
  padding-right: 24px;
}
.uil-ph-32 {
  padding-left: 32px;
  padding-right: 32px;
}
@media (min-width: 768px) {
  .sm\:uil-ph-16 {
    padding-left: 16px;
    padding-right: 16px;
  }
}
@media (min-width: 960px) {
  .md\:uil-ph-0 {
    padding-left: 0;
    padding-right: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-ph-20 {
    padding-left: 20px;
    padding-right: 20px;
  }
}
@media (min-width: 960px) {
  .md\:uil-ph-48 {
    padding-left: 48px;
    padding-right: 48px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ph-20 {
    padding-left: 20px;
    padding-right: 20px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ph-32 {
    padding-left: 32px;
    padding-right: 32px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ph-48 {
    padding-left: 48px;
    padding-right: 48px;
  }
}
.uil-v-visible {
  visibility: visible;
}
.uil-v-hidden {
  visibility: hidden;
}
@media (min-width: 960px) {
  .md\:uil-v-visible {
    visibility: visible;
  }
}
@media (min-width: 960px) {
  .md\:uil-v-hidden {
    visibility: hidden;
  }
}
.hover\:uil-color-white:focus,
.hover\:uil-color-white:hover,
.uil-color-white {
  color: #fff;
}
.hover\:uil-color-grey-900:focus,
.hover\:uil-color-grey-900:hover,
.uil-color-grey-900 {
  color: #23263b;
}
.uil-color-grey-800 {
  color: #36395a;
}
.hover\:uil-color-grey-700:focus,
.hover\:uil-color-grey-700:hover,
.uil-color-grey-700 {
  color: #484c7a;
}
.hover\:uil-color-grey-600:focus,
.hover\:uil-color-grey-600:hover,
.uil-color-grey-600 {
  color: #5a5e9a;
}
.uil-color-grey-500 {
  color: #777aaf;
}
.hover\:uil-color-grey-400:focus,
.hover\:uil-color-grey-400:hover,
.uil-color-grey-400 {
  color: #9698c3;
}
.uil-color-grey-300 {
  color: #b6b7d5;
}
.hover\:uil-color-grey-200:focus,
.hover\:uil-color-grey-200:hover,
.uil-color-grey-200 {
  color: #d6d6e7;
}
.hover\:uil-color-grey-100:focus,
.hover\:uil-color-grey-100:hover,
.uil-color-grey-100 {
  color: #f5f5fa;
}
.uil-color-pink-600 {
  color: #e90a96;
}
.uil-color-nebula-500 {
  color: #5468ff;
}
.uil-color-green-700 {
  color: #06b66c;
}
.uil-color-orange-600 {
  color: #f78125;
}
.uil-color-red-600 {
  color: #ee243c;
}
.uil-color-red-500 {
  color: #f4495d;
}
.uil-color-current {
  color: currentColor;
}
.uil-fill-white {
  fill: #fff;
}
.uil-ai-center {
  align-items: center;
}
.uil-ai-end {
  align-items: flex-end;
}
@media (min-width: 768px) {
  .sm\:uil-ai-start {
    align-items: flex-start;
  }
}
@media (min-width: 960px) {
  .md\:uil-ai-start {
    align-items: flex-start;
  }
}
@media (min-width: 960px) {
  .md\:uil-ai-center {
    align-items: center;
  }
}
@media (min-width: 960px) {
  .md\:uil-ai-end {
    align-items: flex-end;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ai-end {
    align-items: flex-end;
  }
}
.uil-as-end {
  align-self: flex-end;
}
.uil-fxd-column {
  flex-direction: column;
}
.uil-fxd-row {
  flex-direction: row;
}
@media (min-width: 500px) {
  .xs\:uil-fxd-row {
    flex-direction: row;
  }
}
@media (min-width: 768px) {
  .sm\:uil-fxd-row {
    flex-direction: row;
  }
}
@media (min-width: 960px) {
  .md\:uil-fxd-column {
    flex-direction: column;
  }
}
@media (min-width: 960px) {
  .md\:uil-fxd-row {
    flex-direction: row;
  }
}
@media (min-width: 960px) {
  .md\:uil-fxd-row-reverse {
    flex-direction: row-reverse;
  }
}
.uil-fxg-0 {
  flex-grow: 0;
}
.uil-fxg-1 {
  flex-grow: 1;
}
@media (min-width: 960px) {
  .md\:uil-fxg-1 {
    flex-grow: 1;
  }
}
.uil-fxs-0 {
  flex-shrink: 0;
}
.uil-fxs-1 {
  flex-shrink: 1;
}
.uil-fx-1 {
  flex: 0 1 8.333333%;
}
.uil-fx-4 {
  flex: 0 1 33.333333%;
}
.uil-fx-5 {
  flex: 0 1 41.666667%;
}
.uil-fx-6 {
  flex: 0 1 50%;
}
.uil-fx-12 {
  flex: 0 1 100%;
}
@media (min-width: 960px) {
  .md\:uil-fx-5 {
    flex: 0 1 41.666667%;
  }
}
@media (min-width: 960px) {
  .md\:uil-fx-6 {
    flex: 0 1 50%;
  }
}
@media (min-width: 960px) {
  .md\:uil-fx-7 {
    flex: 0 1 58.333333%;
  }
}
@media (min-width: 960px) {
  .md\:uil-fx-9 {
    flex: 0 1 75%;
  }
}
.uil-jc-center {
  justify-content: center;
}
.uil-jc-end {
  justify-content: flex-end;
}
.uil-jc-between {
  justify-content: space-between;
}
.uil-jc-around {
  justify-content: space-around;
}
@media (min-width: 500px) {
  .xs\:uil-jc-center {
    justify-content: center;
  }
}
@media (min-width: 768px) {
  .sm\:uil-jc-start {
    justify-content: flex-start;
  }
}
@media (min-width: 768px) {
  .sm\:uil-jc-center {
    justify-content: center;
  }
}
@media (min-width: 960px) {
  .md\:uil-jc-start {
    justify-content: flex-start;
  }
}
@media (min-width: 960px) {
  .md\:uil-jc-center {
    justify-content: center;
  }
}
@media (min-width: 960px) {
  .md\:uil-jc-end {
    justify-content: flex-end;
  }
}
@media (min-width: 960px) {
  .md\:uil-jc-between {
    justify-content: space-between;
  }
}
@media (min-width: 960px) {
  .md\:uil-jc-around {
    justify-content: space-around;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-jc-end {
    justify-content: flex-end;
  }
}
@media (min-width: 960px) {
  .md\:uil-gcstart-1 {
    grid-column-start: 1;
  }
}
@media (min-width: 960px) {
  .md\:uil-gcstart-2 {
    grid-column-start: 2;
  }
}
@media (min-width: 960px) {
  .md\:uil-gcend-3 {
    grid-column-end: 3;
  }
}
@media (min-width: 960px) {
  .md\:uil-grstart-1 {
    grid-row-start: 1;
  }
}
@media (min-width: 960px) {
  .md\:uil-grstart-2 {
    grid-row-start: 2;
  }
}
@media (min-width: 960px) {
  .md\:uil-grend-3 {
    grid-row-end: 3;
  }
}
@media (min-width: 960px) {
  .md\:uil-grend-4 {
    grid-row-end: 4;
  }
}
.uil-g-2 {
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 768px) {
  .sm\:uil-g-2 {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 768px) {
  .sm\:uil-g-3 {
    grid-template-columns: repeat(3, 1fr);
  }
}
@media (min-width: 768px) {
  .sm\:uil-g-4 {
    grid-template-columns: repeat(4, 1fr);
  }
}
@media (min-width: 768px) {
  .sm\:uil-g-5 {
    grid-template-columns: repeat(5, 1fr);
  }
}
@media (min-width: 768px) {
  .sm\:uil-g-6 {
    grid-template-columns: repeat(6, 1fr);
  }
}
@media (min-width: 960px) {
  .md\:uil-g-2 {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 960px) {
  .md\:uil-g-3 {
    grid-template-columns: repeat(3, 1fr);
  }
}
@media (min-width: 960px) {
  .md\:uil-g-4 {
    grid-template-columns: repeat(4, 1fr);
  }
}
@media (min-width: 960px) {
  .md\:uil-g-5 {
    grid-template-columns: repeat(5, 1fr);
  }
}
@media (min-width: 960px) {
  .md\:uil-g-6 {
    grid-template-columns: repeat(6, 1fr);
  }
}
.uil-ggap-24 {
  grid-gap: 24px;
}
.uil-ggap-48 {
  grid-gap: 48px;
}
@media (min-width: 1200px) {
  .lg\:uil-ggap-24 {
    grid-gap: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ggap-32 {
    grid-gap: 32px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ggap-48 {
    grid-gap: 48px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-ggap-80 {
    grid-gap: 80px;
  }
}
.uil-gvgap-8 {
  grid-column-gap: 8px;
}
@media (min-width: 768px) {
  .sm\:uil-gvgap-48 {
    grid-column-gap: 48px;
  }
}
.uil-ghgap-48 {
  grid-row-gap: 48px;
}
.uil-obf-contain {
  -o-object-fit: contain;
  object-fit: contain;
}
.uil-obf-cover {
  -o-object-fit: cover;
  object-fit: cover;
}
.uil-obp-center {
  -o-object-position: center;
  object-position: center;
}
.uil-bot-0 {
  bottom: 0;
}
.uil-bot-70 {
  bottom: 70px;
}
@media (min-width: 960px) {
  .md\:uil-bot-0 {
    bottom: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-fl-right {
    float: right;
  }
}
.uil-left-0 {
  left: 0;
}
.uil-left-50p {
  left: 50%;
}
@media (min-width: 960px) {
  .md\:uil-left-0 {
    left: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-left-50p {
    left: 50%;
  }
}
.uil-pos-relative {
  position: relative;
}
.uil-pos-absolute {
  position: absolute;
}
.uil-pos-fixed {
  position: fixed;
}
.uil-pos-sticky {
  position: sticky;
}
@media (min-width: 768px) {
  .sm\:uil-pos-absolute {
    position: absolute;
  }
}
@media (min-width: 960px) {
  .md\:uil-pos-relative {
    position: relative;
  }
}
@media (min-width: 960px) {
  .md\:uil-pos-absolute {
    position: absolute;
  }
}
@media (min-width: 960px) {
  .md\:uil-pos-fixed {
    position: fixed;
  }
}
@media (min-width: 960px) {
  .md\:uil-pos-sticky {
    position: sticky;
  }
}
.uil-right-0 {
  right: 0;
}
@media (min-width: 960px) {
  .md\:uil-right-0 {
    right: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-right-50p {
    right: 50%;
  }
}
.uil-top-0 {
  top: 0;
}
.uil-top-32 {
  top: 32px;
}
.uil-top-50p {
  top: 50%;
}
@media (min-width: 768px) {
  .sm\:uil-top-0 {
    top: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-top-0 {
    top: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-top-50p {
    top: 50%;
  }
}
.uil-va-middle {
  vertical-align: middle;
}
.uil-z-1 {
  z-index: 1;
}
.uil-z-2 {
  z-index: 2;
}
.uil-z-3 {
  z-index: 3;
}
.uil-z-4 {
  z-index: 4;
}
.uil-z-5 {
  z-index: 5;
}
.uil-z-max {
  z-index: 100;
}
@media (min-width: 960px) {
  .md\:uil-z-5 {
    z-index: 5;
  }
}
@media (min-width: 960px) {
  .md\:uil-z-max {
    z-index: 100;
  }
}
.uil-app-none {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}
.uil-bxs-default {
  box-shadow: 0 5px 15px 0 rgba(37, 44, 97, 0.15),
    0 2px 4px 0 rgba(93, 100, 148, 0.2);
}
.uil-bxs-large {
  box-shadow: 0 24px 41px 0 rgba(37, 44, 97, 0.13);
}
.uil-bxs-none {
  box-shadow: none;
}
@media (min-width: 960px) {
  .md\:uil-bxs-default {
    box-shadow: 0 5px 15px 0 rgba(37, 44, 97, 0.15),
      0 2px 4px 0 rgba(93, 100, 148, 0.2);
  }
}
.uil-cursor-auto {
  cursor: auto;
}
.uil-cursor-pointer {
  cursor: pointer;
}
.uil-cursor-not-allowed {
  cursor: not-allowed;
}
.uil-op-0 {
  opacity: 0;
}
.uil-op-50p {
  opacity: 0.5;
}
.uil-op-40p {
  opacity: 0.4;
}
.uil-op-75p {
  opacity: 0.75;
}
.uil-op-100p {
  opacity: 1;
}
@media (min-width: 960px) {
  .md\:uil-op-0 {
    opacity: 0;
  }
}
@media (min-width: 960px) {
  .md\:uil-op-25p {
    opacity: 0.25;
  }
}
@media (min-width: 960px) {
  .md\:uil-op-100p {
    opacity: 1;
  }
}
.uil-pe-auto {
  pointer-events: auto;
}
.uil-pe-none {
  pointer-events: none;
}
@media (min-width: 960px) {
  .md\:uil-pe-none {
    pointer-events: none;
  }
}
.uil-us-none {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.uil-h-0 {
  height: 0;
}
.uil-h-10 {
  height: 10px;
}
.uil-h-14 {
  height: 14px;
}
.uil-h-16 {
  height: 16px;
}
.uil-h-18 {
  height: 18px;
}
.uil-h-20 {
  height: 20px;
}
.uil-h-24 {
  height: 24px;
}
.uil-h-25 {
  height: 25px;
}
.uil-h-30 {
  height: 30px;
}
.uil-h-40 {
  height: 40px;
}
.uil-h-50 {
  height: 50px;
}
.uil-h-60 {
  height: 60px;
}
.uil-h-70 {
  height: 70px;
}
.uil-h-80 {
  height: 80px;
}
.uil-h-200 {
  height: 200px;
}
.uil-h-10p {
  height: 10%;
}
.uil-h-20p {
  height: 20%;
}
.uil-h-25p {
  height: 25%;
}
.uil-h-30p {
  height: 30%;
}
.uil-h-40p {
  height: 40%;
}
.uil-h-50p {
  height: 50%;
}
.uil-h-60p {
  height: 60%;
}
.uil-h-70p {
  height: 70%;
}
.uil-h-80p {
  height: 80%;
}
.uil-h-90p {
  height: 90%;
}
.uil-h-100p {
  height: 100%;
}
.uil-h-100vh {
  height: 100vh;
}
.uil-h-auto {
  height: auto;
}
@media (min-width: 960px) {
  .md\:uil-h-10 {
    height: 10px;
  }
}
@media (min-width: 960px) {
  .md\:uil-h-30 {
    height: 30px;
  }
}
@media (min-width: 960px) {
  .md\:uil-h-60p {
    height: 60%;
  }
}
@media (min-width: 960px) {
  .md\:uil-h-100p {
    height: 100%;
  }
}
@media (min-width: 960px) {
  .md\:uil-h-100vh {
    height: 100vh;
  }
}
@media (min-width: 960px) {
  .md\:uil-h-auto {
    height: auto;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-18 {
    height: 18px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-20 {
    height: 20px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-24 {
    height: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-30 {
    height: 30px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-40 {
    height: 40px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-70 {
    height: 70px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-80 {
    height: 80px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-100 {
    height: 100px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-h-100p {
    height: 100%;
  }
}
.uil-mah-100p {
  max-height: 100%;
}
.uil-mah-100vh {
  max-height: 100vh;
}
@media (min-width: 960px) {
  .md\:uil-mah-100p {
    max-height: 100%;
  }
}
.uil-maw-500 {
  max-width: 500px;
}
.uil-maw-700 {
  max-width: 700px;
}
.uil-maw-800 {
  max-width: 800px;
}
.uil-maw-1200 {
  max-width: 1200px;
}
.uil-maw-1440 {
  max-width: 1440px;
}
.uil-maw-35ch {
  max-width: 35ch;
}
.uil-maw-100p {
  max-width: 100%;
}
@media (min-width: 960px) {
  .md\:uil-maw-600 {
    max-width: 600px;
  }
}
@media (min-width: 960px) {
  .md\:uil-maw-900 {
    max-width: 900px;
  }
}
@media (min-width: 960px) {
  .md\:uil-maw-1200 {
    max-width: 1200px;
  }
}
@media (min-width: 960px) {
  .md\:uil-maw-100p {
    max-width: 100%;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-maw-1200 {
    max-width: 1200px;
  }
}
.uil-miw-200 {
  min-width: 200px;
}
@media (min-width: 960px) {
  .md\:uil-miw-300 {
    min-width: 300px;
  }
}
.uil-w-10 {
  width: 10px;
}
.uil-w-14 {
  width: 14px;
}
.uil-w-16 {
  width: 16px;
}
.uil-w-18 {
  width: 18px;
}
.uil-w-20 {
  width: 20px;
}
.uil-w-25 {
  width: 25px;
}
.uil-w-30 {
  width: 30px;
}
.uil-w-40 {
  width: 40px;
}
.uil-w-50 {
  width: 50px;
}
.uil-w-60 {
  width: 60px;
}
.uil-w-100 {
  width: 100px;
}
.uil-w-200 {
  width: 200px;
}
.uil-w-50p {
  width: 50%;
}
.uil-w-70p {
  width: 70%;
}
.uil-w-80p {
  width: 80%;
}
.uil-w-100p {
  width: 100%;
}
.uil-w-auto {
  width: auto;
}
@media (min-width: 500px) {
  .xs\:uil-w-60p {
    width: 60%;
  }
}
@media (min-width: 500px) {
  .xs\:uil-w-70p {
    width: 70%;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-10 {
    width: 10px;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-30 {
    width: 30px;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-400 {
    width: 400px;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-40p {
    width: 40%;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-50p {
    width: 50%;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-60p {
    width: 60%;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-70p {
    width: 70%;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-100p {
    width: 100%;
  }
}
@media (min-width: 960px) {
  .md\:uil-w-auto {
    width: auto;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-18 {
    width: 18px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-20 {
    width: 20px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-24 {
    width: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-30 {
    width: 30px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-40 {
    width: 40px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-50 {
    width: 50px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-80 {
    width: 80px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-200 {
    width: 200px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-50p {
    width: 50%;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-70p {
    width: 70%;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-80p {
    width: 80%;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-90p {
    width: 90%;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-w-100p {
    width: 100%;
  }
}
.uil-ff-hind {
  font-family: Hind, Arial, sans-serif;
}
.uil-ff-poppins {
  font-family: Poppins, Arial, sans-serif;
}
.uil-ff-mono {
  font-family: SFMono-Regular, Consolas, Andale Mono WT, Andale Mono,
    Lucida Console, Lucida Sans Typewriter, DejaVu Sans Mono,
    Bitstream Vera Sans Mono, Liberation Mono, Nimbus Mono L, Monaco,
    Courier New, Courier, monospace;
}
@media (min-width: 1200px) {
  .lg\:uil-ff-hind {
    font-family: Hind, Arial, sans-serif;
  }
}
.uil-fsz-10 {
  font-size: 10px;
}
.uil-fsz-11 {
  font-size: 11px;
}
.uil-fsz-12 {
  font-size: 12px;
}
.uil-fsz-14 {
  font-size: 14px;
}
.uil-fsz-16 {
  font-size: 16px;
}
.uil-fsz-18 {
  font-size: 18px;
}
.uil-fsz-24 {
  font-size: 24px;
}
.uil-fsz-36 {
  font-size: 36px;
}
@media (min-width: 960px) {
  .md\:uil-fsz-16 {
    font-size: 16px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-fsz-12 {
    font-size: 12px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-fsz-14 {
    font-size: 14px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-fsz-16 {
    font-size: 16px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-fsz-18 {
    font-size: 18px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-fsz-24 {
    font-size: 24px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-fsz-36 {
    font-size: 36px;
  }
}
@media (min-width: 1200px) {
  .lg\:uil-fsz-56 {
    font-size: 56px;
  }
}
.uil-fst-normal {
  font-style: normal;
}
.uil-fw-light {
  font-weight: 300;
}
.uil-fw-normal {
  font-weight: 400;
}
.uil-fw-semibold {
  font-weight: 600;
}
.uil-fw-bold {
  font-weight: 700;
}
.uil-lsp-small {
  letter-spacing: -1px;
}
.uil-lsp-big {
  letter-spacing: 1.5px;
}
.uil-lsp-normal {
  letter-spacing: normal;
}
@media (min-width: 1200px) {
  .lg\:uil-lsp-medium {
    letter-spacing: 0.7px;
  }
}
.uil-lh-small {
  line-height: 1;
}
.uil-lh-big {
  line-height: 1.33;
}
.uil-lh-bigger {
  line-height: 1.78;
}
.uil-lis-none {
  list-style: none;
}
.uil-ta-left {
  text-align: left;
}
.uil-ta-center {
  text-align: center;
}
.uil-ta-right {
  text-align: right;
}
@media (min-width: 768px) {
  .sm\:uil-ta-left {
    text-align: left;
  }
}
@media (min-width: 960px) {
  .md\:uil-ta-left {
    text-align: left;
  }
}
@media (min-width: 960px) {
  .md\:uil-ta-center {
    text-align: center;
  }
}
@media (min-width: 960px) {
  .md\:uil-ta-right {
    text-align: right;
  }
}
.hover\:uil-td-none:focus,
.hover\:uil-td-none:hover,
.uil-td-none {
  text-decoration: none;
}
@media (min-width: 960px) {
  .md\:uil-td-none {
    text-decoration: none;
  }
}
.uil-to-ellipsis {
  text-overflow: ellipsis;
}
@media (min-width: 1200px) {
  .lg\:uil-to-ellipsis {
    text-overflow: ellipsis;
  }
}
.uil-tt-upper {
  text-transform: uppercase;
}
.uil-tt-lower {
  text-transform: lowercase;
}
.uil-ws-nowrap {
  white-space: nowrap;
}
@media (min-width: 1200px) {
  .lg\:uil-ws-nowrap {
    white-space: nowrap;
  }
}
.uil-wb-break {
  word-break: break-word;
}


================================================
FILE: docs/src/pages/index.js
================================================
import Layout from '@theme/Layout';
import React from 'react';

import Home from '../components/Home';

function HomePage() {
  return (
    <Layout
      title="ShortGPT: Automate Content Creation with AI"
      description="Automating video and short content creation with AI "
    >
      <Home />
    </Layout>
  );
}

export default HomePage;


================================================
FILE: docs/tailwind.config.js
================================================
module.exports = {
  purge: ['./src/**/*.html', './src/**/*.js', './src/**/*.tsx'],
  corePlugins: { preflight: false, container: false },
  important: '#tailwind',
  theme: {
    extend: {
      maxWidth: {
        xxs: '18rem',
      },
    },
  },
};


================================================
FILE: gui/asset_components.py
================================================
import os
import platform
import random
import subprocess

import gradio as gr

from shortGPT.api_utils.eleven_api import ElevenLabsAPI
from shortGPT.config.api_db import ApiKeyManager
from shortGPT.config.asset_db import AssetDatabase


class AssetComponentsUtils:
    EDGE_TTS = "Free EdgeTTS (lower quality)"
    ELEVEN_TTS = "ElevenLabs(Very High Quality)"


    instance_background_video_checkbox = None
    instance_background_music_checkbox = None
    instance_voiceChoice: dict[gr.Radio] = {}
    instance_voiceChoiceTranslation: dict[gr.Radio] = {}

    @classmethod
    def getBackgroundVideoChoices(cls):
        df = AssetDatabase.get_df()
        choices = list(df.loc["background video" == df["type"]]["name"])[:20]
        return choices

    @classmethod
    def getBackgroundMusicChoices(cls):
        df = AssetDatabase.get_df()
        choices = list(df.loc["background music" == df["type"]]["name"])[:20]
        return choices

    @classmethod
    def getElevenlabsVoices(cls):
        api_key = ApiKeyManager.get_api_key("ELEVENLABS_API_KEY")
        voices = list(reversed(ElevenLabsAPI(api_key).get_voices().keys()))
        return voices

    @classmethod
    def start_file(cls, path):
        if platform.system() == "Windows":
            os.startfile(path)
        elif platform.system() == "Darwin":
            subprocess.Popen(["open", path])
        else:
            subprocess.Popen(["xdg-open", path])

    @classmethod
    def background_video_checkbox(cls):
        if cls.instance_background_video_checkbox is None:
            choices = cls.getBackgroundVideoChoices()
            cls.instance_background_video_checkbox = gr.CheckboxGroup(
                choices=choices,
                interactive=True,
                label="Choose background video",
                value=random.choice(choices)
            )
        return cls.instance_background_video_checkbox

    @classmethod
    def background_music_checkbox(cls):
        if cls.instance_background_music_checkbox is None:
            choices = cls.getBackgroundMusicChoices()
            cls.instance_background_music_checkbox = gr.CheckboxGroup(
                choices=choices,
                interactive=True,
                label="Choose background music",
                value=random.choice(choices)
            )
        return cls.instance_background_music_checkbox

    @classmethod
    def voiceChoice(cls, provider: str = None):
        if provider == None:
            provider = cls.ELEVEN_TTS
        if cls.instance_voiceChoice.get(provider, None) is None:
            if provider == cls.ELEVEN_TTS:
                cls.instance_voiceChoice[provider] = gr.Radio(
                    cls.getElevenlabsVoices(),
                    label="Elevenlabs voice",
                    value="Chris",
                    interactive=True,
                )
        return cls.instance_voiceChoice[provider]

    @classmethod
    def voiceChoiceTranslation(cls, provider: str = None):
        if provider == None:
            provider = cls.ELEVEN_TTS
        if cls.instance_voiceChoiceTranslation.get(provider, None) is None:
            if provider == cls.ELEVEN_TTS:
                cls.instance_voiceChoiceTranslation[provider] = gr.Radio(
                    cls.getElevenlabsVoices(),
                    label="Elevenlabs voice",
                    value="Chris",
                    interactive=True,
                )
        return cls.instance_voiceChoiceTranslation[provider]


================================================
FILE: gui/content_automation_ui.py
================================================
import time
import gradio as gr

from gui.ui_tab_short_automation import ShortAutomationUI
from gui.ui_tab_video_automation import VideoAutomationUI
from gui.ui_tab_video_translation import VideoTranslationUI


class GradioContentAutomationUI:
    def __init__(self, shortGPTUI):
        self.shortGPTUI = shortGPTUI
        self.content_automation_ui = None

    def create_ui(self):
        '''Create Gradio interface'''
        with gr.Tab("Content Automation") as self.content_automation_ui:
            gr.Markdown("# 🏆 Content Automation 🚀")
            gr.Markdown("## Choose your desired automation task.")
            choice = gr.Radio(['🎬 Automate the creation of shorts', '🎞️ Automate a video with stock assets', '🌐 Automate multilingual video dubbing'], label="Choose an option")
            video_automation_ui = VideoAutomationUI(self.shortGPTUI).create_ui()
            short_automation_ui = ShortAutomationUI(self.shortGPTUI).create_ui()
            video_translation_ui = VideoTranslationUI(self.shortGPTUI).create_ui()
            def onChange(x):
                showShorts= x == choice.choices[0][0]
                showVideo = x == choice.choices[1][0]
                showTranslation= x == choice.choices[2][0]
                return gr.update(visible=showShorts), gr.update(visible=showVideo), gr.update(visible=showTranslation)
            choice.change(onChange, [choice], [short_automation_ui,video_automation_ui, video_translation_ui])
        return self.content_automation_ui


================================================
FILE: gui/gui_gradio.py
================================================
import gradio as gr

from gui.content_automation_ui import GradioContentAutomationUI
from gui.ui_abstract_base import AbstractBaseUI
from gui.ui_components_html import GradioComponentsHTML
from gui.ui_tab_asset_library import AssetLibrary
from gui.ui_tab_config import ConfigUI
from shortGPT.utils.cli import CLI


class ShortGptUI(AbstractBaseUI):
    '''Class for the GUI. This class is responsible for creating the UI and launching the server.'''

    def __init__(self, colab=False):
        super().__init__(ui_name='gradio_shortgpt')
        self.colab = colab
        CLI.display_header()

    def create_interface(self):
        '''Create Gradio interface'''
        with gr.Blocks(theme=gr.themes.Default(spacing_size=gr.themes.sizes.spacing_sm), css="footer {visibility: hidden}", title="ShortGPT Demo") as shortGptUI:
            with gr.Row(variant='compact'):
                gr.HTML(GradioComponentsHTML.get_html_header())

            self.content_automation = GradioContentAutomationUI(shortGptUI).create_ui()
            self.asset_library_ui = AssetLibrary().create_ui()
            self.config_ui = ConfigUI().create_ui()
        return shortGptUI

    def launch(self):
        '''Launch the server'''
        shortGptUI = self.create_interface()
        if not getattr(self, 'colab', False):
                    print("\n\n********************* STARTING SHORGPT **********************")
                    print("\nShortGPT is running here 👉 http://localhost:31415\n")
                    print("********************* STARTING SHORGPT **********************\n\n")
        shortGptUI.queue().launch(server_port=31415, height=1000, allowed_paths=["public/","videos/","fonts/"], share=self.colab, server_name="0.0.0.0")



if __name__ == "__main__":
    app = ShortGptUI()
    app.launch()


import signal

def signal_handler(sig, frame):
    print("Closing Gradio server...")
    import gradio as gr
    gr.close_all()
    exit(0)

signal.signal(signal.SIGINT, signal_handler)

================================================
FILE: gui/ui_abstract_base.py
================================================

import gradio as gr


class AbstractBaseUI:
    '''Base class for the GUI. This class is responsible for creating the UI and launching the server.'''
    max_choices = 20
    ui_asset_dataframe = gr.Dataframe(interactive=False)
    LOGO_PATH = "http://localhost:31415/gradio_api/file=public/logo.png"
    LOGO_DIM = 64

    def __init__(self, ui_name='default'):
        self.ui_name = ui_name
        self.content_automation = None
        self.asset_library_ui = None
        self.config_ui = None

    def create_interface(self):
        raise NotImplementedError


================================================
FILE: gui/ui_abstract_component.py
================================================


class AbstractComponentUI:
    def create_ui(self):
        raise NotImplementedError


================================================
FILE: gui/ui_components_html.py
================================================
class GradioComponentsHTML:

    @staticmethod
    def get_html_header() -> str:
        '''Create HTML for the header'''
        return '''
            <div style="display: flex; justify-content: space-between; align-items: center; padding: 5px;">
            <h1 style="margin-left: 0px; font-size: 35px;">ShortGPT</h1>
            <div style="flex-grow: 1; text-align: right;">
                <a href="https://discord.gg/bWreuAyRaj" target="_blank" style="text-decoration: none;">
                <button style="margin-right: 10px; padding: 10px 20px; font-size: 16px; color: #fff; background-color: #7289DA; border: none; border-radius: 5px; cursor: pointer;">Join Discord</button>
                </a>
                <a href="https://github.com/RayVentura/ShortGPT" target="_blank" style="text-decoration: none;">
                <button style="padding: 10px 20px; font-size: 16px; color: #fff; background-color: #333; border: none; border-radius: 5px; cursor: pointer;">Like the concept? Add a Star on Github 👉 ⭐</button>
                </a>
            </div>
            </div>
        '''

    @staticmethod
    def get_html_error_template() -> str:
        return '''
        <div style='text-align: center; background: #ff7f7f; color: #a94442; padding: 20px; border-radius: 5px; margin: 10px;'>
          <h2 style='margin: 0; color: black'>ERROR : {error_message}</h2>
          <p style='margin: 10px 0; color: black'>Traceback Info : {stack_trace}</p>
          <p style='margin: 10px 0; color: black'>If the problem persists, don't hesitate to contact our support. We're here to assist you.</p>
          <a href='https://discord.gg/qn2WJaRH' target='_blank' style='background: #a94442; color: #fff; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; text-decoration: none;'>Get Help on Discord</a>
        </div>
        '''

    @staticmethod
    def get_html_video_template(file_url_path, file_name, width="auto", height="auto"):
        """
        Generate an HTML code snippet for embedding and downloading a video.

        Parameters:
        file_url_path (str): The URL or path to the video file.
        file_name (str): The name of the video file.
        width (str, optional): The width of the video. Defaults to "auto".
        height (str, optional): The height of the video. Defaults to "auto".

        Returns:
        str: The generated HTML code snippet.
        """
        html = f'''
            <div style="display: flex; flex-direction: column; align-items: center;">
                <video width="{width}" height="{height}" style="max-height: 100%;" controls>
                    <source src="{file_url_path}" type="video/mp4">
                    Your browser does not support the video tag.
                </video>
                <a href="{file_url_path}" download="{file_name}" style="margin-top: 10px;">
                    <button style="font-size: 1em; padding: 10px; border: none; cursor: pointer; color: white; background: #007bff;">Download Video</button>
                </a>
            </div>
        '''
        return html


================================================
FILE: gui/ui_tab_asset_library.py
================================================
import os
import re
import shutil

import gradio as gr

from gui.asset_components import AssetComponentsUtils
from gui.ui_abstract_component import AbstractComponentUI
from shortGPT.config.asset_db import AssetDatabase, AssetType


class AssetLibrary(AbstractComponentUI):
    def __init__(self):
        pass

    def create_ui(self):
        '''Create the asset library UI'''
        with gr.Tab("Asset library") as asset_library_ui:
            with gr.Column():
                with gr.Accordion("➕ Add your own local assets or from Youtube", open=False) as accordion:
                    remote = "Add youtube video / audio"
                    local = "Add local video / audio / image    "
                    assetFlows = gr.Radio([remote, local], label="", value=remote)
                    with gr.Column(visible=True) as youtubeFlow:
                        asset_name = gr.Textbox(label="Name (required)")
                        asset_type = gr.Radio([AssetType.BACKGROUND_VIDEO.value, AssetType.BACKGROUND_MUSIC.value,], value=AssetType.BACKGROUND_VIDEO.value, label="Type")
                        youtube_url = gr.Textbox(label="URL (https://youtube.com/xyz)")
                        add_youtube_link = gr.Button("ADD")

                    with gr.Column(visible=False) as localFileFlow:
                        local_upload_name = gr.Textbox(label="Name (required)")
                        upload_type = gr.Radio([AssetType.BACKGROUND_VIDEO.value, AssetType.BACKGROUND_MUSIC.value, AssetType.IMAGE.value], value="background video", interactive=True, label="Type")
                        video_upload = gr.Video(visible=True, sources="upload", interactive=True)
                        audio_upload = gr.Audio(visible=False, sources="upload", type="filepath", interactive=True)
                        image_upload = gr.Image(visible=False, sources="upload", type="filepath", interactive=True)
                        upload_button = gr.Button("ADD")
                        upload_type.change(lambda x: (gr.update(visible='video' in x),
                                                      gr.update(visible=any(type in x for type in ['audio', 'music'])),
                                                      gr.update(visible=x == 'image')),
                                           [upload_type], [video_upload, audio_upload, image_upload])
                    assetFlows.change(lambda x: (gr.update(visible=x == remote), gr.update(visible=x == local)), [assetFlows], [youtubeFlow, localFileFlow])
                with gr.Row():
                    with gr.Column(scale=3):
                        asset_dataframe_ui = gr.Dataframe(self.__fulfill_df, interactive=False)
                        video_choise = gr.Radio(["background video", "background music"], value="background video", label="Type")
                    with gr.Column(scale=2):
                        gr.Markdown("Preview")
                        asset_preview_ui = gr.HTML(self.__get_first_preview)
                        delete_button = gr.Button("🗑️ Delete", scale=0, variant="primary")
                        delete_button.click(self.__delete_clicked, [delete_button], [asset_dataframe_ui, asset_preview_ui, delete_button, AssetComponentsUtils.background_video_checkbox(), AssetComponentsUtils.background_music_checkbox()])
                        asset_dataframe_ui.select(self.__preview_asset, [asset_dataframe_ui], [asset_preview_ui, delete_button])

                add_youtube_link.click(
                    self.__verify_youtube_asset_inputs, [asset_name, youtube_url, asset_type], []).success(self.__add_youtube_asset, [asset_name, youtube_url, asset_type], [asset_dataframe_ui, asset_preview_ui, delete_button, accordion, AssetComponentsUtils.background_video_checkbox(), AssetComponentsUtils.background_music_checkbox()]).success(lambda: gr.update(open=False), [accordion])

                upload_button.click(
                    self.__verify_and_upload_local_asset, [upload_type, local_upload_name, video_upload, audio_upload, image_upload, ], []).success(self.__upload_local_asset, [upload_type, local_upload_name, video_upload, audio_upload, image_upload, ], [asset_dataframe_ui, asset_preview_ui, delete_button, accordion, AssetComponentsUtils.background_video_checkbox(), AssetComponentsUtils.background_music_checkbox()]).success(lambda: gr.update(open=False), [accordion])

        return asset_library_ui

    def __fulfill_df(self):
        '''Get the dataframe of assets'''
        return AssetDatabase.get_df()

    def __verify_youtube_asset_inputs(self, asset_name, yt_url, type):
        if not asset_name or not re.match("^[A-Za-z0-9 _-]*$", asset_name):
            raise gr.Error('Invalid asset name. Please provide a valid name that you will recognize (Only use letters and numbers)')
        if not yt_url.startswith("https://youtube.com/") and not yt_url.startswith("https://www.youtube.com/"):
            raise gr.Error('Invalid YouTube URL. Please provide a valid URL.')
        if AssetDatabase.asset_exists(asset_name):
            raise gr.Error('An asset already exists with this name, please choose a different name.')

    def __validate_asset_name(self, asset_name):
        '''Validate asset name'''
        if not asset_name or not re.match("^[A-Za-z0-9 _-]*$", asset_name):
            raise gr.Error('Invalid asset name. Please provide a valid name that you will recognize (Only use letters and numbers)')
        if AssetDatabase.asset_exists(asset_name):
            raise gr.Error('An asset already exists with this name, please choose a different name.')

    def __validate_youtube_url(self, yt_url):
        '''Validate YouTube URL'''
        if not yt_url.startswith("https://youtube.com/") and not yt_url.startswith("https://www.youtube.com/"):
            raise gr.Error('Invalid YouTube URL. Please provide a valid URL.')

    def __verify_and_add_youtube_asset(self, asset_name, yt_url, type):
        '''Verify and add a youtube asset to the database'''
        self.__validate_asset_name(asset_name)
        self.__validate_youtube_url(yt_url)
        return self.__add_youtube_asset(asset_name, yt_url, type)

    def __add_youtube_asset(self, asset_name, yt_url, type):
        '''Add a youtube asset'''
        AssetDatabase.add_remote_asset(asset_name, AssetType(type), yt_url)
        latest_df = AssetDatabase.get_df()
        return gr.DataFrame.update(value=latest_df), gr.update(value=self.__get_asset_embed(latest_df, 0)),\
            gr.update(value=f"🗑️ Delete {latest_df.iloc[0]['name']}"),\
            gr.update(open=False),\
            gr.update(choices=AssetComponentsUtils.getBackgroundVideoChoices(), interactive=True),\
            gr.update(choices=AssetComponentsUtils.getBackgroundMusicChoices(), interactive=True)

    def __get_first_preview(self):
        '''Get the first preview'''
        return self.__get_asset_embed(AssetDatabase.get_df(), 0)

    def __delete_clicked(self, button_name):
        '''Delete an asset'''
        asset_name = button_name.split("🗑️ Delete ")[-1]
        AssetDatabase.remove_asset(asset_name)
        data = AssetDatabase.get_df()
        if len(data) > 0:
            return gr.update(value=data),\
                gr.update(value=self.__get_asset_embed(data, 0)),\
                gr.update(value=f"🗑️ Delete {data.iloc[0]['name']}"),\
                gr.update(choices=AssetComponentsUtils.getBackgroundVideoChoices(), interactive=True),\
                gr.update(choices=AssetComponentsUtils.getBackgroundMusicChoices(), interactive=True)
        return gr.Dataframe.update(value=data),\
            gr.update(visible=True),\
            gr.update(value="🗑️ Delete"),\
            gr.update(choices=AssetComponentsUtils.getBackgroundVideoChoices(), interactive=True),\
            gr.update(choices=AssetComponentsUtils.getBackgroundMusicChoices(), interactive=True)

    def __preview_asset(self, data, evt: gr.SelectData):
        '''Preview the asset with the given name'''
        html_embed = self.__get_asset_embed(data, evt.index[0])
        return gr.update(value=html_embed), gr.update(value=f"🗑️ Delete {data.iloc[evt.index[0]]['name']}")

    def __get_asset_embed(self, data, row):
        '''Get the embed html for the asset at the given row'''
        embed_height = 300
        embed_width = 300
        asset_link = data.iloc[row]['link']
        embed_html = ''
        if 'youtube.com' in asset_link:
            asset_link_split = asset_link.split('?v=')
            if asset_link_split[0] == asset_link:
                asset_link_split = asset_link.split('/')
                # if the last character is a /, remove it
                if asset_link_split[-1] == '/':
                    asset_link_split = asset_link_split[:-1]
                asset_link_split = asset_link_split[-1]
            else:
                asset_link_split = asset_link_split[-1]
            asset_link = f"https://youtube.com/embed/{asset_link_split}"
            embed_html = f'<iframe width="{embed_width}" height="{embed_height}" src="{asset_link}"></iframe>'
        elif 'public/' in asset_link or 'public/' in asset_link:
            asset_link = f"http://localhost:31415/gradio_api/file={asset_link}"
            file_ext = asset_link.split('.')[-1]

            if file_ext in ['mp3', 'wav', 'ogg']:
                audio_type = 'audio/mpeg' if file_ext == 'mp3' else f'audio/{file_ext}'
                embed_html = f'<audio controls><source src="{asset_link}" type="{audio_type}">Your browser does not support the audio tag.</audio>'
            elif file_ext in ['mp4', 'webm', 'ogg', 'mov']:
                video_type = 'video/mp4' if file_ext == 'mp4' else f'video/{file_ext}'
                embed_html = f'<video width="{embed_width}" height="{embed_height}" style="max-height: 100%;" controls><source src="{asset_link}" type="{video_type}">Your browser does not support the video tag.</video>'
            elif file_ext in ['jpg', 'jpeg', 'png', 'gif']:
                embed_html = f'<img src="{asset_link}" width="{embed_width}" height="{embed_height}">'
            else:
                embed_html = 'Unsupported file type'
        return embed_html

    @staticmethod
    def __clean_filename(filename):
        '''Clean the filename'''
        return re.sub('[\\\\/:*?"<>|]', '', filename)

    def __verify_and_upload_local_asset(self, upload_type, upload_name, video_path, audio_path, image_path):
        '''Verify and upload a local asset to the database'''
        self.__validate_asset_name(upload_name)
        path_dict = {
            AssetType.VIDEO.value: video_path,
            AssetType.BACKGROUND_VIDEO.value: video_path,
            AssetType.AUDIO.value: audio_path,
            AssetType.BACKGROUND_MUSIC.value: audio_path,
            AssetType.IMAGE.value: image_path
        }
        if not os.path.exists(path_dict[upload_type]):
            raise gr.Error(f'The file does not exist at the given path.')
        return self.__upload_local_asset(upload_type, upload_name, video_path, audio_path, image_path)

    def __upload_local_asset(self, upload_type, upload_name, video_path, audio_path, image_path):
        '''Upload a local asset to the database'''
        path_dict = {
            AssetType.VIDEO.value: video_path,
            AssetType.BACKGROUND_VIDEO.value: video_path,
            AssetType.AUDIO.value: audio_path,
            AssetType.BACKGROUND_MUSIC.value: audio_path,
            AssetType.IMAGE.value: image_path
        }
        new_path = "public/" + self.__clean_filename(upload_name) + "." + path_dict[upload_type].split(".")[-1]
        shutil.move(path_dict[upload_type], new_path)
        AssetDatabase.add_local_asset(upload_name, AssetType(upload_type), new_path)
        latest_df = AssetDatabase.get_df()
        return gr.DataFrame.update(value=latest_df), gr.update(value=self.__get_asset_embed(latest_df, 0)),\
            gr.update(value=f"🗑️ Delete {latest_df.iloc[0]['name']}"),\
            gr.update(open=False),\
            gr.update(choices=AssetComponentsUtils.getBackgroundVideoChoices(), interactive=True),\
            gr.update(choices=AssetComponentsUtils.getBackgroundMusicChoices(), interactive=True)


================================================
FILE: gui/ui_tab_config.py
================================================
import time

import gradio as gr

from gui.asset_components import AssetComponentsUtils
from gui.ui_abstract_component import AbstractComponentUI
from shortGPT.api_utils.eleven_api import ElevenLabsAPI
from shortGPT.config.api_db import ApiKeyManager


class ConfigUI(AbstractComponentUI):
    def __init__(self):
        self.api_key_manager = ApiKeyManager()
        eleven_key = self.api_key_manager.get_api_key('ELEVENLABS_API_KEY')
        self.eleven_labs_api = ElevenLabsAPI(eleven_key) if eleven_key else None

    def on_show(self, button_text, textbox, button):
        '''Show or hide the API key'''
        if button_text == "Show":
            return gr.update(type="text"), gr.update(value="Hide")
        return gr.update(type="password"), gr.update(value="Show")

    def verify_eleven_key(self, eleven_key, remaining_chars):
        '''Verify the ElevenLabs API key'''
        if (eleven_key and self.api_key_manager.get_api_key('ELEVENLABS_API_KEY') != eleven_key):
            try:
                self.eleven_labs_api = ElevenLabsAPI(eleven_key)
                print(self.eleven_labs_api)
                return self.eleven_labs_api.get_remaining_characters()
            except Exception as e:
                raise gr.Error(e.args[0])
        return remaining_chars

    def save_keys(self, openai_key, eleven_key, pexels_key, gemini_key):
        '''Save the keys in the database'''
        if (self.api_key_manager.get_api_key("OPENAI_API_KEY") != openai_key):
            self.api_key_manager.set_api_key("OPENAI_API_KEY", openai_key)
        if (self.api_key_manager.get_api_key("PEXELS_API_KEY") != pexels_key):
            self.api_key_manager.set_api_key("PEXELS_API_KEY", pexels_key)
        if (self.api_key_manager.get_api_key('ELEVENLABS_API_KEY') != eleven_key):
            self.api_key_manager.set_api_key("ELEVENLABS_API_KEY", eleven_key)
            new_eleven_voices = AssetComponentsUtils.getElevenlabsVoices()
            return gr.update(value=openai_key),\
                gr.update(value=eleven_key),\
                gr.update(value=pexels_key),\
                gr.update(value=gemini_key),\
                gr.update(choices=new_eleven_voices),\
                gr.update(choices=new_eleven_voices)
        if (self.api_key_manager.get_api_key("GEMINI_API_KEY") != gemini_key):
            self.api_key_manager.set_api_key("GEMINI_API_KEY", gemini_key)

        return gr.update(value=openai_key),\
            gr.update(value=eleven_key),\
            gr.update(value=pexels_key),\
            gr.update(value=gemini_key),\
            gr.update(visible=True),\
            gr.update(visible=True)

    def get_eleven_remaining(self,):
        '''Get the remaining characters from ElevenLabs API'''
        if (self.eleven_labs_api):
            try:
                return self.eleven_labs_api.get_remaining_characters()
            except Exception as e:
                return e.args[0]
        return ""

    def back_to_normal(self):
        '''Back to normal after 3 seconds'''
        time.sleep(3)
        return gr.update(value="save")

    def create_ui(self):
        '''Create the config UI'''
        with gr.Tab("Config") as config_ui:
            with gr.Row():
                with gr.Column():
                    with gr.Row():
                        openai_textbox = gr.Textbox(value=self.api_key_manager.get_api_key("OPENAI_API_KEY"), label=f"OPENAI API KEY", show_label=True, interactive=True, show_copy_button=True, type="password", scale=40)
                        show_openai_key = gr.Button("Show", size="sm", scale=1)
                        show_openai_key.click(self.on_show, [show_openai_key], [openai_textbox, show_openai_key])
                    with gr.Row():
                        eleven_labs_textbox = gr.Textbox(value=self.api_key_manager.get_api_key("ELEVENLABS_API_KEY"), label=f"ELEVENLABS_API_KEY", show_label=True, interactive=True, show_copy_button=True, type="password", scale=40)
                        eleven_characters_remaining = gr.Textbox(value=self.get_eleven_remaining(), label=f"CHARACTERS REMAINING", show_label=True, interactive=False, type="text", scale=40)
                        show_eleven_key = gr.Button("Show", size="sm", scale=1)
                        show_eleven_key.click(self.on_show, [show_eleven_key], [eleven_labs_textbox, show_eleven_key])
                    with gr.Row():
                        pexels_textbox = gr.Textbox(value=self.api_key_manager.get_api_key("PEXELS_API_KEY"), label=f"PEXELS KEY", show_label=True, interactive=True, show_copy_button=True, type="password", scale=40)
                        show_pexels_key = gr.Button("Show", size="sm", scale=1)
                        show_pexels_key.click(self.on_show, [show_pexels_key], [pexels_textbox, show_pexels_key])
                    with gr.Row():
                        gemini_textbox = gr.Textbox(value=self.api_key_manager.get_api_key("GEMINI_API_KEY"), label=f"GEMINI API KEY", show_label=True, interactive=True, show_copy_button=True, type="password", scale=40)
                        show_gemini_key = gr.Button("Show", size="sm", scale=1)
                        show_gemini_key.click(self.on_show, [show_gemini_key], [gemini_textbox, show_gemini_key])

                    save_button = gr.Button("save", size="sm", scale=1)
                    save_button.click(self.verify_eleven_key, [eleven_labs_textbox, eleven_characters_remaining], [eleven_characters_remaining]).success(
                        self.save_keys, [openai_textbox, eleven_labs_textbox, pexels_textbox, gemini_textbox], [openai_textbox, eleven_labs_textbox, pexels_textbox, gemini_textbox, AssetComponentsUtils.voiceChoice(), AssetComponentsUtils.voiceChoiceTranslation()])
                    save_button.click(lambda _: gr.update(value="Keys Saved !"), [], [save_button])
                    save_button.click(self.back_to_normal, [], [save_button])
        return config_ui

================================================
FILE: gui/ui_tab_short_automation.py
================================================
import os
import time
import traceback

import gradio as gr

from gui.asset_components import AssetComponentsUtils
from gui.ui_abstract_component import AbstractComponentUI
from gui.ui_components_html import GradioComponentsHTML
from shortGPT.audio.edge_voice_module import EdgeTTSVoiceModule
from shortGPT.audio.eleven_voice_module import ElevenLabsVoiceModule
from shortGPT.config.api_db import ApiKeyManager
from shortGPT.config.languages import (EDGE_TTS_VOICENAME_MAPPING,
                                       ELEVEN_SUPPORTED_LANGUAGES,
                                       LANGUAGE_ACRONYM_MAPPING,
                                       Language)
from shortGPT.engine.facts_short_engine import FactsShortEngine
from shortGPT.engine.reddit_short_engine import RedditShortEngine
class ShortAutomationUI(AbstractComponentUI):
    def __init__(self, shortGptUI: gr.Blocks):
        self.shortGptUI = shortGptUI
        self.embedHTML = '<div style="display: flex; overflow-x: auto; gap: 20px;">'
        self.progress_counter = 0
        self.short_automation = None

    def create_ui(self):
        with gr.Row(visible=False) as short_automation:
            with gr.Column():
                numShorts = gr.Number(label="Number of shorts", minimum=1, value=1)
                short_type = gr.Radio(["Reddit Story shorts", "Historical Facts shorts", "Scientific Facts shorts", "Custom Facts shorts"], label="Type of shorts generated", value="Reddit Story shorts", interactive=True)
                facts_subject = gr.Textbox(label="Write a subject for your facts (example: Football facts)", interactive=True, visible=False)
                short_type.change(lambda x: gr.update(visible=x == "Custom Facts shorts"), [short_type], [facts_subject])
                tts_engine = gr.Radio([AssetComponentsUtils.ELEVEN_TTS, AssetComponentsUtils.EDGE_TTS], label="Text to speech engine", value=AssetComponentsUtils.EDGE_TTS, interactive=True)
                self.tts_engine = tts_engine.value
                with gr.Column(visible=False) as eleven_tts:
                    language_eleven = gr.Radio([lang.value for lang in ELEVEN_SUPPORTED_LANGUAGES], label="Language", value="English", interactive=True)
                    voice_eleven = AssetComponentsUtils.voiceChoice(provider=AssetComponentsUtils.ELEVEN_TTS)
                with gr.Column(visible=True) as edge_tts:
                    language_edge = gr.Dropdown([lang.value.upper() for lang in Language], label="Language", value="ENGLISH", interactive=True)
                def tts_engine_change(x):
                    self.tts_engine = x
                    return gr.update(visible=x == AssetComponentsUtils.ELEVEN_TTS), gr.update(visible=x == AssetComponentsUtils.EDGE_TTS)
                tts_engine.change(tts_engine_change, tts_engine, [eleven_tts, edge_tts])

                useImages = gr.Checkbox(label="Use images", value=True)
                numImages = gr.Radio([5, 10, 25], value=10, label="Number of images per short", visible=True, interactive=True)
                useImages.change(lambda x: gr.update(visible=x), useImages, numImages)

                addWatermark = gr.Checkbox(label="Add watermark")
                watermark = gr.Textbox(label="Watermark (your channel name)", visible=False)
                addWatermark.change(lambda x: gr.update(visible=x), [addWatermark], [watermark])

                AssetComponentsUtils.background_video_checkbox()
                AssetComponentsUtils.background_music_checkbox()
                createButton = gr.Button("Create Shorts")

                generation_error = gr.HTML(visible=False)
                video_folder = gr.Button("📁", visible=True)
                output = gr.HTML('<div style="min-height: 80px;"></div>')

            video_folder.click(lambda _: AssetComponentsUtils.start_file(os.path.abspath("videos/")))

            createButton.click(self.inspect_create_inputs, inputs=[AssetComponentsUtils.background_video_checkbox(), AssetComponentsUtils.background_music_checkbox(), watermark, short_type, facts_subject], outputs=[generation_error]).success(self.create_short, inputs=[
                numShorts,
                short_type,
                tts_engine,
                language_eleven,
                language_edge,
                numImages,
                watermark,
                AssetComponentsUtils.background_video_checkbox(),
                AssetComponentsUtils.background_music_checkbox(),
                facts_subject,
                voice_eleven,
            ], outputs=[output, video_folder, generation_error])
        self.short_automation = short_automation
        return self.short_automation

    def create_short(self, numShorts, short_type, tts_engine, language_eleven, language_edge, numImages, watermark, background_video_list, background_music_list, facts_subject, voice_eleven, progress=gr.Progress()):
        '''Creates a short'''

        try:
            numShorts = int(numShorts)
            numImages = int(numImages) if numImages else None
            background_videos = (background_video_list * ((numShorts // len(background_video_list)) + 1))[:numShorts]
            background_musics = (background_music_list * ((numShorts // len(background_music_list)) + 1))[:numShorts]
            if tts_engine == AssetComponentsUtils.ELEVEN_TTS:
                language = Language(language_eleven.lower().capitalize())
                voice_module = ElevenLabsVoiceModule(ApiKeyManager.get_api_key('ELEVENLABS_API_KEY'), voice_eleven, checkElevenCredits=True)
            elif tts_engine == AssetComponentsUtils.EDGE_TTS:
                language = Language(language_edge.lower().capitalize())
                voice_module = EdgeTTSVoiceModule(EDGE_TTS_VOICENAME_MAPPING[language]['male'])
            for i in range(numShorts):
                shortEngine = self.create_short_engine(short_type=short_type, voice_module=voice_module, language=language, numImages=numImages, watermark=watermark,
                                                       background_video=background_videos[i], background_music=background_musics[i], facts_subject=facts_subject)
                num_steps = shortEngine.get_total_steps()

                def logger(prog_str):
                    progress(self.progress_counter / (num_steps * numShorts), f"Making short {i+1}/{numShorts} - {prog_str}")
                shortEngine.set_logger(logger)

                for step_num, step_info in shortEngine.makeContent():
                    print(step_num, step_info,self.progress_counter )
                    progress(self.progress_counter / (num_steps * numShorts), f"Making short {i+1}/{numShorts} - {step_info}")
                    self.progress_counter += 1

                video_path = shortEngine.get_video_output_path()
                current_url = self.shortGptUI.share_url+"/" if self.shortGptUI.share else self.shortGptUI.local_url
                file_url_path = f"{current_url}gradio_api/file={video_path}"
                file_name = video_path.split("/")[-1].split("\\")[-1]
                self.embedHTML += f'''
                <div style="display: flex; flex-direction: column; align-items: center;">
                    <video width="{250}" height="{500}" style="max-height: 100%;" controls>
                        <source src="{file_url_path}" type="video/mp4">
                        Your browser does not support the video tag.
                    </video>
                    <a href="{file_url_path}" download="{file_name}" style="margin-top: 10px;">
                        <button style="font-size: 1em; padding: 10px; border: none; cursor: pointer; color: white; background: #007bff;">Download Video</button>
                    </a>
                </div>'''
                yield self.embedHTML + '</div>', gr.update(visible=True), gr.update(visible=False)
        except Exception as e:
            traceback_str = ''.join(traceback.format_tb(e.__traceback__))
            error_name = type(e).__name__.capitalize() + " : " + f"{e.args[0]}"
            print("Error", traceback_str)
            error_html = GradioComponentsHTML.get_html_error_template().format(error_message=error_name, stack_trace=traceback_str)
            yield self.embedHTML + '</div>', gr.update(visible=True), gr.update(value=error_html, visible=True)
    def inspect_create_inputs(self, background_video_list, background_music_list, watermark, short_type, facts_subject, progress=gr.Progress()):
        if short_type == "Custom Facts shorts":
            if not facts_subject:
                raise gr.Error("Please write down your facts short's subject")
        if not background_video_list:
            raise gr.Error("Please select at least one background video.")

        if not background_music_list:
            raise gr.Error("Please select at least one background music.")

        if watermark != "":
            if not watermark.replace(" ", "").isalnum():
                raise gr.Error("Watermark should only contain letters and numbers.")
            if len(watermark) > 25:
                raise gr.Error("Watermark should not exceed 25 characters.")
            if len(watermark) < 3:
                raise gr.Error("Watermark should be at least 3 characters long.")

        openai_key = ApiKeyManager.get_api_key("OPENAI_API_KEY")
        gemini_key = ApiKeyManager.get_api_key("GEMINI_API_KEY")
        if not openai_key and not gemini_key:
            raise gr.Error("GEMINI OR OPENAI API key is missing. Please go to the config tab and enter the API key.")
        eleven_labs_key = ApiKeyManager.get_api_key("ELEVENLABS_API_KEY")
        if self.tts_engine == AssetComponentsUtils.ELEVEN_TTS and not eleven_labs_key:
            raise gr.Error("ELEVENLABS_API_KEY API key is missing. Please go to the config tab and enter the API key.")
        return gr.update(visible=False)

    def create_short_engine(self, short_type, voice_module, language, numImages, watermark, background_video, background_music, facts_subject):
        if short_type == "Reddit Story shorts":
            return RedditShortEngine(voice_module, background_video_name=background_video, background_music_name=background_music, num_images=numImages, watermark=watermark, language=language)
        if "fact" in short_type.lower():
            if "custom" in short_type.lower():
                facts_subject = facts_subject
            else:
                facts_subject = short_type
            return FactsShortEngine(voice_module, facts_type=facts_subject, background_video_name=background_video, background_music_name=background_music, num_images=numImages, watermark=watermark, language=language)
        raise gr.Error(f"Short type does not have a valid short engine: {short_type}")


================================================
FILE: gui/ui_tab_video_automation.py
================================================
import os
import traceback
from enum import Enum

import gradio as gr

from gui.asset_components import AssetComponentsUtils
from gui.ui_abstract_component import AbstractComponentUI
from gui.ui_components_html import GradioComponentsHTML
from shortGPT.audio.edge_voice_module import EdgeTTSVoiceModule
from shortGPT.audio.eleven_voice_module import ElevenLabsVoiceModule
from shortGPT.config.api_db import ApiKeyManager
from shortGPT.config.languages import (EDGE_TTS_VOICENAME_MAPPING,
                                        ELEVEN_SUPPORTED_LANGUAGES,
                                        LANGUAGE_ACRONYM_MAPPING,
                                        Language)
from shortGPT.engine.content_video_engine import ContentVideoEngine
from shortGPT.gpt import gpt_chat_video


class Chatstate(Enum):
    ASK_ORIENTATION = 1
    ASK_VOICE_MODULE = 2
    ASK_LANGUAGE = 3
    ASK_DESCRIPTION = 4
    GENERATE_SCRIPT = 5
    ASK_SATISFACTION = 6
    MAKE_VIDEO = 7
    ASK_CORRECTION = 8


class VideoAutomationUI(AbstractComponentUI):
    def __init__(self, shortGptUI: gr.Blocks):
        self.shortGptUI = shortGptUI
        self.state = Chatstate.ASK_ORIENTATION
        self.isVertical = None
        self.voice_module = None
        self.language = None
        self.script = ""
        self.video_html = ""
        self.videoVisible = False
        self.video_automation = None
        self.chatbot = None
        self.msg = None
        self.restart_button = None
        self.video_folder = None
        self.errorHTML = None
        self.outHTML = None

    def is_key_missing(self):
        openai_key = ApiKeyManager.get_api_key("OPENAI_API_KEY")
        gemini_key = ApiKeyManager.get_api_key("GEMINI_API_KEY")
        if not openai_key and not gemini_key:
            return "Your Genmini or OpenAI key is missing. Please go to the config tab and enter the API key."

        pexels_api_key = ApiKeyManager.get_api_key("PEXELS_API_KEY")
        if not pexels_api_key:
            return "Your Pexels API key is missing. Please go to the config tab and enter the API key."

    def generate_script(self, message, language):
        return gpt_chat_video.generateScript(message, language)

    def correct_script(self, script, correction):
        return gpt_chat_video.correctScript(script, correction)

    def make_video(self, script, voice_module, isVertical, progress):
        videoEngine = ContentVideoEngine(voiceModule=voice_module, script=script, isVerticalFormat=isVertical)
        num_steps = videoEngine.get_total_steps()
        progress_counter = 0

        def logger(prog_str):
            progress(progress_counter / (num_steps), f"Creating video - {progress_counter} - {prog_str}")
        videoEngine.set_logger(logger)
        for step_num, step_info in videoEngine.makeContent():
            progress(progress_counter / (num_steps), f"Creating video - {step_info}")
            progress_counter += 1

        video_path = videoEngine.get_video_output_path()
        return video_path

    def reset_components(self):
        return gr.update(value=self.initialize_conversation()), gr.update(visible=True), gr.update(value="", visible=False), gr.update(value="", visible=False)

    def chatbot_conversation(self):
        def respond(message, chat_history, progress=gr.Progress()):
            # global self.state, isVertical, voice_module, language, script, videoVisible, video_html
            error_html = ""
            errorVisible = False
            inputVisible = True
            folderVisible = False
            if self.state == Chatstate.ASK_ORIENTATION:
                errorMessage = self.is_key_missing()
                if errorMessage:
                    bot_message = errorMessage
                else:
                    self.isVertical = "vertical" in message.lower() or "short" in message.lower()
                    self.state = Chatstate.ASK_VOICE_MODULE
                    bot_message = "Which voice module do you want to use? Please type 'ElevenLabs' for high quality, 'EdgeTTS' for free medium quality voice."
            elif self.state == Chatstate.ASK_VOICE_MODULE:
                if "elevenlabs" in message.lower():
                    eleven_labs_key = ApiKeyManager.get_api_key("ELEVENLABS_API_KEY")
                    if not eleven_labs_key:
                        bot_message = "Your ELEVENLABS_API_KEY API key is missing. Please go to the config tab and enter the API key."
                        return
                    self.voice_module = ElevenLabsVoiceModule
                    language_choices = [lang.value for lang in ELEVEN_SUPPORTED_LANGUAGES]
                elif "edgetts" in message.lower():
                    self.voice_module = EdgeTTSVoiceModule
                    language_choices = [lang.value for lang in Language]
                else:
                    bot_message = "Invalid voice module. Please type 'ElevenLabs' or 'EdgeTTS'."
                    return
                self.state = Chatstate.ASK_LANGUAGE
                bot_message = f"🌐What language will be used in the video?🌐 Choose from one of these ({', '.join(language_choices)})"
            elif self.state == Chatstate.ASK_LANGUAGE:
                self.language = next((lang for lang in Language if lang.value.lower() in message.lower()), None)
                self.language = self.language if self.language else Language.ENGLISH
                if self.voice_module == ElevenLabsVoiceModule:
                    self.voice_module = ElevenLabsVoiceModule(ApiKeyManager.get_api_key('ELEVENLABS_API_KEY'), "Chris", checkElevenCredits=True)
                elif self.voice_module == EdgeTTSVoiceModule:
                    self.voice_module = EdgeTTSVoiceModule(EDGE_TTS_VOICENAME_MAPPING[self.language]['male'])
                self.state = Chatstate.ASK_DESCRIPTION
                bot_message = "Amazing 🔥 ! 📝Can you describe thoroughly the subject of your video?📝 I will next generate you a script based on that description"
            elif self.state == Chatstate.ASK_DESCRIPTION:
                self.script = self.generate_script(message, self.language.value)
                self.state = Chatstate.ASK_SATISFACTION
                bot_message = f"📝 Here is your generated script: \n\n--------------\n{self.script}\n\n・Are you satisfied with the script and ready to proceed with creating the video? Please respond with 'YES' or 'NO'. 👍👎"
            elif self.state == Chatstate.ASK_SATISFACTION:
                if "yes" in message.lower():
                    self.state = Chatstate.MAKE_VIDEO
                    inputVisible = False
                    yield gr.update(visible=False), gr.update(value=[[None, "Your video is being made now! 🎬"]]), gr.update(value="", visible=False), gr.update(value=error_html, visible=errorVisible), gr.update(visible=folderVisible), gr.update(visible=False)
                    try:
                        video_path = self.make_video(self.script, self.voice_module, self.isVertical, progress=progress)
                        file_name = video_path.split("/")[-1].split("\\")[-1]
                        current_url = self.shortGptUI.share_url+"/" if self.shortGptUI.share else self.shortGptUI.local_url
                        file_url_path = f"{current_url}gradio_api/file={video_path}"
                        self.video_html = f'''
                            <div style="display: flex; flex-direction: column; align-items: center;">
                                <video width="{600}" height="{300}" style="max-height: 100%;" controls>
                                    <source src="{file_url_path}" type="video/mp4">
                                    Your browser does not support the video tag.
                                </video>
                                <a href="{file_url_path}" download="{file_name}" style="margin-top: 10px;">
                                    <button style="font-size: 1em; padding: 10px; border: none; cursor: pointer; color: white; background: #007bff;">Download Video</button>
                                </a>
                            </div>'''
                        self.videoVisible = True
                        folderVisible = True
                        bot_message = "Your video is completed !🎬. Scroll down below to open its file location."
                    except Exception as e:
                        traceback_str = ''.join(traceback.format_tb(e.__traceback__))
                        error_name = type(e).__name__.capitalize() + " : " + f"{e.args[0]}"
                        errorVisible = True
                        gradio_content_automation_ui_error_template = GradioComponentsHTML.get_html_error_template()
                        error_html = gradio_content_automation_ui_error_template.format(error_message=error_name, stack_trace=traceback_str)
                        bot_message = "We encountered an error while making this video ❌"
                        print("Error", traceback_str)
                        yield gr.update(visible=False), gr.update(value=[[None, "Your video is being made now! 🎬"]]), gr.update(value="", visible=False), gr.update(value=error_html, visible=errorVisible), gr.update(visible=folderVisible), gr.update(visible=True)

                else:
                    self.state = Chatstate.ASK_CORRECTION  # change self.state to ASK_CORRECTION
                    bot_message = "Explain me what you want different in the script"
            elif self.state == Chatstate.ASK_CORRECTION:  # new self.state
                self.script = self.correct_script(self.script, message)  # call generateScript with correct=True
                self.state = Chatstate.ASK_SATISFACTION
                bot_message = f"📝 Here is your corrected script: \n\n--------------\n{self.script}\n\n・Are you satisfied with the script and ready to proceed with creating the video? Please respond with 'YES' or 'NO'. 👍👎"
            chat_history.append((message, bot_message))
            yield gr.update(value="", visible=inputVisible), gr.update(value=chat_history), gr.update(value=self.video_html, visible=self.videoVisible), gr.update(value=error_html, visible=errorVisible), gr.update(visible=folderVisible), gr.update(visible=True)

        return respond

    def initialize_conversation(self):
        self.state = Chatstate.ASK_ORIENTATION
        self.isVertical = None
        self.language = None
        self.script = ""
        self.video_html = ""
        self.videoVisible = False
        return [[None, "🤖 Welcome to ShortGPT! 🚀 I'm a python framework aiming to simplify and automate your video editing tasks.\nLet's get started! 🎥🎬\n\n Do you want your video to be in landscape or vertical format? (landscape OR vertical)"]]

    def reset_conversation(self):
        self.state = Chatstate.ASK_ORIENTATION
        self.isVertical = None
        self.language = None
        self.script = ""
        self.video_html = ""
        self.videoVisible = False

    def create_ui(self):
        with gr.Row(visible=False) as self.video_automation:
            with gr.Column():
                self.chatbot = gr.Chatbot(self.initialize_conversation, height=365)
                self.msg = gr.Textbox()
                self.restart_button = gr.Button("Restart")
                self.video_folder = gr.Button("📁", visible=False)
                self.video_folder.click(lambda _: AssetComponentsUtils.start_file(os.path.abspath("videos/")))
                respond = self.chatbot_conversation()

            self.errorHTML = gr.HTML(visible=False)
            self.outHTML = gr.HTML('<div style="min-height: 80px;"></div>')
            self.restart_button.click(self.reset_components, [], [self.chatbot, self.msg, self.errorHTML, self.outHTML])
            self.restart_button.click(self.reset_conversation, [])
            self.msg.submit(respond, [self.msg, self.chatbot], [self.msg, self.chatbot, self.outHTML, self.errorHTML, self.video_folder, self.restart_button])
        return self.video_automation


================================================
FILE: gui/ui_tab_video_translation.py
================================================
import os
import time
import traceback

import gradio as gr

from gui.asset_components import AssetComponentsUtils
from gui.ui_abstract_component import AbstractComponentUI
from gui.ui_components_html import GradioComponentsHTML
from shortGPT.audio.edge_voice_module import EdgeTTSVoiceModule
from shortGPT.audio.eleven_voice_module import ElevenLabsVoiceModule
from shortGPT.config.api_db import ApiKeyManager
from shortGPT.config.languages import (EDGE_TTS_VOICENAME_MAPPING,
                                       ELEVEN_SUPPORTED_LANGUAGES,
                                       LANGUAGE_ACRONYM_MAPPING,
                                          Language)
from shortGPT.engine.multi_language_translation_engine import MultiLanguageTranslationEngine


class VideoTranslationUI(AbstractComponentUI):
    def __init__(self, shortGptUI: gr.Blocks):
        self.shortGptUI = shortGptUI
        self.eleven_language_choices = [lang.value.upper() for lang in ELEVEN_SUPPORTED_LANGUAGES]
        self.embedHTML = '<div style="display: flex; overflow-x: auto; gap: 20px;">'
        self.progress_counter = 0
        self.video_translation_ui = None

    def create_ui(self):
        with gr.Row(visible=False) as video_translation_ui:
            with gr.Column():
                videoType = gr.Radio(["Youtube link", "Video file"], label="Input your video", value="Youtube link", interactive=True)
                video_path = gr.Video(sources="upload", interactive=True, width=533.33, height=300, visible=False)
                yt_link = gr.Textbox(label="Youtube link (https://youtube.com/xyz): ", interactive=True, visible=False)
                videoType.change(lambda x: (gr.update(visible=x == "Video file"), gr.update(visible=x == "Youtube link")), [videoType], [video_path, yt_link])
                tts_engine = gr.Radio([AssetComponentsUtils.ELEVEN_TTS, AssetComponentsUtils.EDGE_TTS], label="Text to speech engine", value=AssetComponentsUtils.EDGE_TTS, interactive=True)
                with gr.Column(visible=False) as eleven_tts:
                    language_eleven = gr.CheckboxGroup(self.eleven_language_choices, label="Language", value="ENGLISH", interactive=True)
                    voice_eleven = AssetComponentsUtils.voiceChoiceTranslation(provider=AssetComponentsUtils.ELEVEN_TTS)
                with gr.Column(visible=True) as edge_tts:
                    language_edge = gr.CheckboxGroup([lang.value.upper() for lang in Language], label="Language", value="ENGLISH", interactive=True)
               
                tts_engine.change(lambda x: (gr.update(visible=x == AssetComponentsUtils.ELEVEN_TTS), gr.update(visible=x == AssetComponentsUtils.EDGE_TTS)), [tts_engine], [eleven_tts, edge_tts])

                useCaptions = gr.Checkbox(label="Caption video", value=False)

                translateButton = gr.Button("Translate Video")

                generation_error = gr.HTML(visible=False)
                video_folder = gr.Button("📁", visible=True)
                output = gr.HTML('<div style="min-height: 80px;"></div>')

            video_folder.click(lambda _: AssetComponentsUtils.start_file(os.path.abspath("videos/")))
            translateButton.click(self.inspect_create_inputs, inputs=[videoType, video_path, yt_link, tts_engine, language_eleven, language_edge, ], outputs=[generation_error]).success(self.translate_video, inputs=[
                videoType, yt_link, video_path, tts_engine, language_eleven, language_edge, useCaptions, voice_eleven
            ], outputs=[output, video_folder, generation_error])
        self.video_translation_ui = video_translation_ui
        return self.video_translation_ui

    def translate_video(self, videoType, yt_link, video_path, tts_engine, language_eleven, language_edge, use_captions: bool, voice_eleven: str, progress=gr.Progress()) -> str:
        if tts_engine == AssetComponentsUtils.ELEVEN_TTS:
            languages = [Language(lang.lower().capitalize()) for lang in language_eleven]
        elif tts_engine == AssetComponentsUtils.EDGE_TTS:
            languages = [Language(lang.lower().capitalize()) for lang in language_edge]

        try:
            for i, language in enumerate(languages):
                if tts_engine == AssetComponentsUtils.EDGE_TTS:
                    voice_module = EdgeTTSVoiceModule(EDGE_TTS_VOICENAME_MAPPING[language]['male'])
                if tts_engine == AssetComponentsUtils.ELEVEN_TTS:
                    voice_module = ElevenLabsVoiceModule(ApiKeyManager.get_api_key('ELEVENLABS_API_KEY'), voice_eleven, checkElevenCredits=True)
                content_translation_engine = MultiLanguageTranslationEngine(voiceModule=voice_module, src_url=yt_link if videoType == "Youtube link" else video_path, target_language=language, use_captions=use_captions)
                num_steps = content_translation_engine.get_total_steps()
                def logger(prog_str):
                    progress(self.progress_counter / (num_steps), f"Translating your video ({i+1}/{len(languages)}) - {prog_str}")
                content_translation_engine.set_logger(logger)

                for step_num, step_info in content_translation_engine.makeContent():
                    progress(self.progress_counter / (num_steps), f"Translating your video ({i+1}/{len(languages)}) - {step_info}")
                    self.progress_counter += 1

                video_path = content_translation_engine.get_video_output_path()
                current_url = self.shortGptUI.share_url+"/" if self.shortGptUI.share else self.shortGptUI.local_url
                file_url_path = f"{current_url}gradio_api/file={video_path}"
                file_name = video_path.split("/")[-1].split("\\")[-1]
                self.embedHTML += f'''
                <div style="display: flex; flex-direction: column; align-items: center;">
                    <video width="{500}"  style="max-height: 100%;" controls>
                        <source src="{file_url_path}" type="video/mp4">
                        Your browser does not support the video tag.
                    </video>
                    <a href="{file_url_path}" download="{file_name}" style="margin-top: 10px;">
                        <button style="font-size: 1em; padding: 10px; border: none; cursor: pointer; color: white; background: #007bff;">Download Video</button>
                    </a>
                </div>'''
                yield "<div>"+self.embedHTML + '</div>', gr.update(visible=True), gr.update(visible=False)

        except Exception as e:
            traceback_str = ''.join(traceback.format_tb(e.__traceback__))
            error_name = type(e).__name__.capitalize() + " : " + f"{e.args[0]}"
            print("Error", traceback_str)
            error_html = GradioComponentsHTML.get_html_error_template().format(error_message=error_name, stack_trace=traceback_str)
            return self.embedHTML + '</div>', gr.update(visible=True), gr.update(value=error_html, visible=True)

    def inspect_create_inputs(self, videoType, video_path, yt_link,  tts_engine, language_eleven, language_edge,):
        supported_extensions = ['.mp4', '.avi', '.mov']  # Add more supported video extensions if needed
        print(videoType, video_path, yt_link)
        if videoType == "Youtube link":
            if not yt_link.startswith("https://youtube.com/") and not yt_link.startswith("https://www.youtube.com/"):
                raise gr.Error('Invalid YouTube URL. Please provide a valid URL. Link example: https://www.youtube.com/watch?v=dQw4w9WgXcQ')
        else:
            if not video_path or not os.path.exists(video_path):
                raise gr.Error('You must drag and drop a valid video file.')

            file_ext = os.path.splitext(video_path)[-1].lower()
            if file_ext not in supported_extensions:
                raise gr.Error('Invalid video file. Supported video file extensions are: {}'.format(', '.join(supported_extensions)))
        if tts_engine == AssetComponentsUtils.ELEVEN_TTS:
            if not len(language_eleven) >0:
                raise gr.Error('You must select one or more target languages')
        if tts_engine == AssetComponentsUtils.EDGE_TTS:
            if not len(language_edge) >0:
                raise gr.Error('You must select one or more target languages')
        return gr.update(visible=False)


def update_progress(progress, progress_counter, num_steps, num_shorts, stop_event):
    start_time = time.time()
    while not stop_event.is_set():
        elapsed_time = time.time() - start_time
        dynamic = int(3649 * elapsed_time / 600)
        progress(progress_counter / (num_steps * num_shorts), f"Rendering progress - {dynamic}/3649")
        time.sleep(0.1)  # update every 0.1 second


================================================
FILE: installation-notes.md
================================================
** Thanks for Son Tran for the fixes on the installation guide. Here are the recommanded steps for installing ShortGPT:


### You now need Docker to now run ShortGPT. If you can't run it with docker, please use the Google Colab.
# To run ShortGPT docker:


First make a .env file with the API keys like this:

```bash
GEMINI_API_KEY=put_your_gemini_api_key_here
OPENAI_API_KEY=sk-_put_your_openai_api_key_here
ELEVENLABS_API_KEY=put_your_eleven_labs_api_key_here
PEXELS_API_KEY=put_your_pexels_api_key_here
```


To run Dockerfile do this:
```bash
docker build -t short_gpt_docker:latest .
docker run -p 31415:31415 --env-file .env short_gpt_docker:latest
```
Export Docker image:
```bash
docker save short_gpt_docker > short_gpt_docker.tar
```





### Here are the steps to install it from scratch on Linux, Debian 11 x64:

In short, you need to use:
- Python 3.10
- openai package, then upgrade openai-whisper
- ffmpeg 4.2.3

### 1. OS: Debian 11 x64
```bash
sudo apt update && sudo apt upgrade 
sudo apt install wget git libltdl-dev libjpeg-dev libpng-dev libtiff-dev libgif-dev libfreetype6-dev liblcms2-dev libxml2-dev wget build-essential libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev zlib1g-dev
```

### 2. Install Python version: 3.10.3
```bash
wget https://www.python.org/ftp/python/3.10.3/Python-3.10.3.tgz 
tar xzf Python-3.10.3.tgz 
cd Python-3.10.3 
./configure --enable-optimizations
make install
```

To check the Python version, use this command:
```bash
python3.10 -V
```
To use pip, use this command:
```bash
pip3.10 install <package-name>
```

### 3. Install ffmpeg version: 4.2.3
ShortGPT will accept this version of FFmpeg:

3.1. Install Build Dependencies:

```bash
sudo apt update
sudo apt build-dep ffmpeg
```

3.2. Clone FFmpeg Source Code:

```bash
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
git checkout n4.2.3
```

3.3. Configure FFmpeg Build:

```bash
./configure --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-avisynth --enable-libopenmpt --enable-shared --disable-static
```

This step checks for the necessary dependencies and configures the build based on your system.

3.4. Build FFmpeg:

```bash
make -j$(nproc)
```

This step may take some time as it compiles the FFmpeg source code.

3.5. Install FFmpeg:

```bash
sudo make install
```

3.6. Verify Installation:

```bash
ffmpeg -version
```

This should display the version information, and you should see version 4.2.3.

Optional: Update Library Cache:

```bash
sudo ldconfig
```

This updates the dynamic linker run-time bindings.

That's it! You should now have FFmpeg version 4.2.3 installed on your Debian 11 system.

If you are still facing with "libavdevice.so.58" error when running ffmpeg, run this command to fix it, remember to change the path:
```bash
echo 'export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64/:/usr/local/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc
```

### 4. Upgrade openai-whisper:
```bash
pip3.10 install -U openai-whisper
```


================================================
FILE: requirements.txt
================================================
python-dotenv
gradio_client==1.5.4
gradio==5.12.0
openai==1.37.0
httpx==0.27.2
tiktoken
tinydb
tinymongo
proglog
yt-dlp>=2025.1.12
torch
torchaudio
### whisper timestamped 
whisper-timestamped
protobuf==3.20.3
pillow==10.4.0
moviepy==2.1.2
progress
questionary
edge-tts


================================================
FILE: runShortGPT.py
================================================
from gui.gui_gradio import ShortGptUI

app = ShortGptUI(colab=False)
app.launch()

================================================
FILE: runShortGPTColab.py
================================================
from gui.gui_gradio import ShortGptUI

app = ShortGptUI(colab=True)
app.launch()


================================================
FILE: setup.py
================================================
from setuptools import setup, find_packages
import codecs
import os

here = os.path.abspath(os.path.dirname(__file__))

with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh:
    long_description = "\n" + fh.read()

VERSION = '0.1.31'
DESCRIPTION = 'Automating video and short content creation with AI'
LONG_DESCRIPTION = 'A powerful tool for automating content creation. It simplifies video creation, footage sourcing, voiceover synthesis, and editing tasks.'


setup(
    name="shortgpt",
    version=VERSION,
    author="RayVentura",
    author_email="",
    description=DESCRIPTION,
    long_description_content_type="text/markdown",
    long_description=long_description,
    packages=find_packages(),
    package_data={'': ['*.yaml', '*.json']},    # This will include all yaml files in package
    install_requires=[
        'python-dotenv', 
        "openai==1.37.2", 
        'tiktoken',
        'tinydb',
        'tinymongo',
        'proglog',
        'yt-dlp',
        'torch',
        'whisper-timestamped',
        'torchaudio',
        'pillow==10.4.0',
        'edge-tts',
        'moviepy==2.1.2',
        'progress',
        'questionary',
    ],
    keywords=['python', 'video', 'content creation', 'AI', 'automation', 'editing', 'voiceover synthesis', 'video captions', 'asset sourcing', 'tinyDB'],
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: Developers",
        "Programming Language :: Python :: 3",
        "Operating System :: Unix",
        "Operating System :: MacOS :: MacOS X",
        "Operating System :: Microsoft :: Windows",
    ]
)

================================================
FILE: shortGPT/__init__.py
================================================
# import time
# t1 = time.time()
# from . import config
# print("Took", time.time() - t1, "seconds to import config")
# t1 = time.time()
# from . import editing
# print("Took", time.time() - t1, "seconds to import editing")
# t1 = time.time()
# from . import audio
# print("Took", time.time() - t1, "seconds to import audio")
# t1 = time.time()
# from . import engine
# print("Took", time.time() - t1, "seconds to import engine")
# t1 = time.time()
# from . import database
# print("Took", time.time() - t1, "seconds to import database")
# t1 = time.time()
# from . import gpt
# print("Took", time.time() - t1, "seconds to import gpt")
# t1 = time.time()
# from . import tracking
# print("Took", time.time() - t1, "seconds to import tracking")

# from . import config
# from . import database
# from . import editing_functions
# from . import audio
# from . import engine
# from . import gpt
# from . import tracking

================================================
FILE: shortGPT/api_utils/README.md
================================================
# Module: api_utils

The `api_utils` module provides utility functions for working with different APIs. It includes three files: `image_api.py`, `pexels_api.py`, and `eleven_api.py`. Each file contains functions related to a specific API.

## File: image_api.py

This file contains functions for interacting with the Bing Images API and extracting image URLs from the HTML response.

### Functions:

#### `_extractBingImages(html)`

This function takes an HTML response as input and extracts image URLs, widths, and heights from it. It uses regular expressions to find the necessary information. The extracted image URLs are returned as a list of dictionaries, where each dictionary contains the URL, width, and height of an image.

#### `_extractGoogleImages(html)`

This function takes an HTML response as input and extracts image URLs from it. It uses regular expressions to find the necessary information. The extracted image URLs are returned as a list.

#### `getBingImages(query, retries=5)`

This function takes a query string as input and retrieves a list of image URLs from the Bing Images API. It replaces spaces in the query string with `+` and sends a GET request to the API. If the request is successful (status code 200), the HTML response is passed to `_extractBingImages` to extract the image URLs. If the request fails or no images are found, an exception is raised.

## File: pexels_api.py

This file contains functions for interacting with the Pexels Videos API and retrieving video URLs based on a query string.

### Functions:

#### `search_videos(query_string, orientation_landscape=True)`

This function takes a query string and an optional boolean parameter `orientation_landscape` as input. It sends a GET request to the Pexels Videos API to search for videos based on the query string. The orientation of the videos can be specified as landscape or portrait. The function returns the JSON response from the API.

#### `getBestVideo(query_string, orientation_landscape=True, used_vids=[])`

This function takes a query string, an optional boolean parameter `orientation_landscape`, and an optional list `used_vids` as input. It calls the `search_videos` function to retrieve a list of videos based on the query string. It then filters and sorts the videos based on their dimensions and duration, and returns the URL of the best matching video. The `used_vids` parameter can be used to exclude previously used videos from the search results.

## File: eleven_api.py

This file contains functions for interacting with the Eleven API and generating voice recordings based on text input.

### Functions:

#### `getVoices(api_key="")`

This function takes an optional API key as input and retrieves a dictionary of available voices from the Eleven API. The voices are returned as a dictionary, where the keys are voice names and the values are voice IDs.

#### `getCharactersFromKey(key)`

This function takes an API key as input and retrieves the remaining character limit for the given key. It sends a GET request to the Eleven API and extracts the character limit and count from the response.

#### `generateVoice(text, character, fileName, stability=0.2, clarity=0.1, api_key="")`

This function takes a text input, a character name, a file name, and optional parameters `stability`, `clarity`, and `api_key` as input. It generates a voice recording using the Eleven API and saves it to the specified file. The character name is used to select the appropriate voice. The stability and clarity parameters control the quality of the voice recording. The API key is required for authentication. If the request is successful, the file name is returned. Otherwise, an empty string is returned.

================================================
FILE: shortGPT/api_utils/__init__.py
================================================
from . import image_api
from . import eleven_api

================================================
FILE: shortGPT/api_utils/eleven_api.py
================================================
import json

import requests


class ElevenLabsAPI:

    def __init__(self, api_key):
        self.api_key = api_key
  
Download .txt
gitextract_zk_2yim7/

├── .database/
│   └── template_asset_db.json
├── .github/
│   ├── CHANGE_LOG.md
│   ├── CODEOWNERS
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yaml
│   │   ├── feature_request.yaml
│   │   └── question.yaml
│   ├── SECURITY.md
│   ├── config.yml
│   ├── issue_label_bot.yaml
│   ├── pull_request_template.md
│   ├── settings.yml
│   └── workflows/
│       └── generate_release-changelog.yaml
├── .gitignore
├── CHANGES.txt
├── Dockerfile
├── LICENSE
├── README-Docker.md
├── README.md
├── docs/
│   ├── .gitignore
│   ├── README.md
│   ├── babel.config.js
│   ├── docs/
│   │   ├── api-key-manager.mdx
│   │   ├── asset-database.mdx
│   │   ├── content-translation-engine.mdx
│   │   ├── content-video-engine.mdx
│   │   ├── facts-short-engine.mdx
│   │   ├── getting-started.mdx
│   │   └── how-to-install.mdx
│   ├── docusaurus.config.js
│   ├── package.json
│   ├── plugins/
│   │   ├── my-loaders/
│   │   │   └── index.js
│   │   └── tailwind-loader/
│   │       └── index.js
│   ├── sidebars.js
│   ├── src/
│   │   ├── components/
│   │   │   └── Home.js
│   │   ├── css/
│   │   │   ├── custom.css
│   │   │   └── fragments.css
│   │   └── pages/
│   │       └── index.js
│   └── tailwind.config.js
├── gui/
│   ├── asset_components.py
│   ├── content_automation_ui.py
│   ├── gui_gradio.py
│   ├── ui_abstract_base.py
│   ├── ui_abstract_component.py
│   ├── ui_components_html.py
│   ├── ui_tab_asset_library.py
│   ├── ui_tab_config.py
│   ├── ui_tab_short_automation.py
│   ├── ui_tab_video_automation.py
│   └── ui_tab_video_translation.py
├── installation-notes.md
├── requirements.txt
├── runShortGPT.py
├── runShortGPTColab.py
├── setup.py
├── shortGPT/
│   ├── __init__.py
│   ├── api_utils/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── eleven_api.py
│   │   ├── image_api.py
│   │   └── pexels_api.py
│   ├── audio/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── audio_duration.py
│   │   ├── audio_utils.py
│   │   ├── edge_voice_module.py
│   │   ├── eleven_voice_module.py
│   │   └── voice_module.py
│   ├── config/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── api_db.py
│   │   ├── asset_db.py
│   │   ├── config.py
│   │   ├── languages.py
│   │   └── path_utils.py
│   ├── database/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── content_data_manager.py
│   │   ├── content_database.py
│   │   └── db_document.py
│   ├── editing_framework/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── core_editing_engine.py
│   │   ├── editing_engine.py
│   │   ├── editing_steps/
│   │   │   ├── __init__.py
│   │   │   ├── add_background_video.json
│   │   │   ├── add_background_voiceover.json
│   │   │   ├── add_voiceover.json
│   │   │   ├── background_music.json
│   │   │   ├── crop_1920x1080_to_short.json
│   │   │   ├── extract_audio.json
│   │   │   ├── insert_audio.json
│   │   │   ├── make_caption.json
│   │   │   ├── make_caption_arabic.json
│   │   │   ├── make_caption_arabic_landscape.json
│   │   │   ├── make_caption_landscape.json
│   │   │   ├── show_reddit_image.json
│   │   │   ├── show_top_image.json
│   │   │   ├── show_watermark.json
│   │   │   └── subscribe_animation.json
│   │   ├── flows/
│   │   │   ├── __init__.py
│   │   │   └── build_reddit_image.json
│   │   └── rendering_logger.py
│   ├── editing_utils/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── captions.py
│   │   ├── editing_images.py
│   │   └── handle_videos.py
│   ├── engine/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── abstract_content_engine.py
│   │   ├── content_short_engine.py
│   │   ├── content_translation_engine.py
│   │   ├── content_video_engine.py
│   │   ├── facts_short_engine.py
│   │   ├── multi_language_translation_engine.py
│   │   └── reddit_short_engine.py
│   ├── gpt/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── facts_gpt.py
│   │   ├── gpt_chat_video.py
│   │   ├── gpt_editing.py
│   │   ├── gpt_translate.py
│   │   ├── gpt_utils.py
│   │   ├── gpt_voice.py
│   │   ├── gpt_yt.py
│   │   └── reddit_gpt.py
│   ├── prompt_templates/
│   │   ├── __init__.py
│   │   ├── chat_video_edit_script.yaml
│   │   ├── chat_video_script.yaml
│   │   ├── editing_generate_images.yaml
│   │   ├── editing_generate_videos.yaml
│   │   ├── facts_generator.yaml
│   │   ├── facts_subjects_generation.yaml
│   │   ├── reddit_extract_question.yaml
│   │   ├── reddit_filter_realistic.yaml
│   │   ├── reddit_generate_question.yaml
│   │   ├── reddit_generate_script.yaml
│   │   ├── reddit_story_filter.yaml
│   │   ├── reddit_username.yaml
│   │   ├── translate_content.yaml
│   │   ├── voice_identify_gender.yaml
│   │   └── yt_title_description.yaml
│   ├── tracking/
│   │   ├── README.md
│   │   ├── __init__.py
│   │   ├── api_tracking.py
│   │   └── cost_analytics.py
│   └── utils/
│       ├── cli.py
│       └── requirements.py
└── videos/
    └── .gitignore
Download .txt
SYMBOL INDEX (343 symbols across 55 files)

FILE: docs/plugins/my-loaders/index.js
  method configureWebpack (line 4) | configureWebpack() {

FILE: docs/plugins/tailwind-loader/index.js
  method configurePostCss (line 5) | configurePostCss(postcssOptions) {

FILE: docs/src/components/Home.js
  function Home (line 7) | function Home() {

FILE: docs/src/pages/index.js
  function HomePage (line 6) | function HomePage() {

FILE: gui/asset_components.py
  class AssetComponentsUtils (line 13) | class AssetComponentsUtils:
    method getBackgroundVideoChoices (line 24) | def getBackgroundVideoChoices(cls):
    method getBackgroundMusicChoices (line 30) | def getBackgroundMusicChoices(cls):
    method getElevenlabsVoices (line 36) | def getElevenlabsVoices(cls):
    method start_file (line 42) | def start_file(cls, path):
    method background_video_checkbox (line 51) | def background_video_checkbox(cls):
    method background_music_checkbox (line 63) | def background_music_checkbox(cls):
    method voiceChoice (line 75) | def voiceChoice(cls, provider: str = None):
    method voiceChoiceTranslation (line 89) | def voiceChoiceTranslation(cls, provider: str = None):

FILE: gui/content_automation_ui.py
  class GradioContentAutomationUI (line 9) | class GradioContentAutomationUI:
    method __init__ (line 10) | def __init__(self, shortGPTUI):
    method create_ui (line 14) | def create_ui(self):

FILE: gui/gui_gradio.py
  class ShortGptUI (line 11) | class ShortGptUI(AbstractBaseUI):
    method __init__ (line 14) | def __init__(self, colab=False):
    method create_interface (line 19) | def create_interface(self):
    method launch (line 30) | def launch(self):
  function signal_handler (line 48) | def signal_handler(sig, frame):

FILE: gui/ui_abstract_base.py
  class AbstractBaseUI (line 5) | class AbstractBaseUI:
    method __init__ (line 12) | def __init__(self, ui_name='default'):
    method create_interface (line 18) | def create_interface(self):

FILE: gui/ui_abstract_component.py
  class AbstractComponentUI (line 3) | class AbstractComponentUI:
    method create_ui (line 4) | def create_ui(self):

FILE: gui/ui_components_html.py
  class GradioComponentsHTML (line 1) | class GradioComponentsHTML:
    method get_html_header (line 4) | def get_html_header() -> str:
    method get_html_error_template (line 21) | def get_html_error_template() -> str:
    method get_html_video_template (line 32) | def get_html_video_template(file_url_path, file_name, width="auto", he...

FILE: gui/ui_tab_asset_library.py
  class AssetLibrary (line 12) | class AssetLibrary(AbstractComponentUI):
    method __init__ (line 13) | def __init__(self):
    method create_ui (line 16) | def create_ui(self):
    method __fulfill_df (line 61) | def __fulfill_df(self):
    method __verify_youtube_asset_inputs (line 65) | def __verify_youtube_asset_inputs(self, asset_name, yt_url, type):
    method __validate_asset_name (line 73) | def __validate_asset_name(self, asset_name):
    method __validate_youtube_url (line 80) | def __validate_youtube_url(self, yt_url):
    method __verify_and_add_youtube_asset (line 85) | def __verify_and_add_youtube_asset(self, asset_name, yt_url, type):
    method __add_youtube_asset (line 91) | def __add_youtube_asset(self, asset_name, yt_url, type):
    method __get_first_preview (line 101) | def __get_first_preview(self):
    method __delete_clicked (line 105) | def __delete_clicked(self, button_name):
    method __preview_asset (line 122) | def __preview_asset(self, data, evt: gr.SelectData):
    method __get_asset_embed (line 127) | def __get_asset_embed(self, data, row):
    method __clean_filename (line 162) | def __clean_filename(filename):
    method __verify_and_upload_local_asset (line 166) | def __verify_and_upload_local_asset(self, upload_type, upload_name, vi...
    method __upload_local_asset (line 180) | def __upload_local_asset(self, upload_type, upload_name, video_path, a...

FILE: gui/ui_tab_config.py
  class ConfigUI (line 11) | class ConfigUI(AbstractComponentUI):
    method __init__ (line 12) | def __init__(self):
    method on_show (line 17) | def on_show(self, button_text, textbox, button):
    method verify_eleven_key (line 23) | def verify_eleven_key(self, eleven_key, remaining_chars):
    method save_keys (line 34) | def save_keys(self, openai_key, eleven_key, pexels_key, gemini_key):
    method get_eleven_remaining (line 59) | def get_eleven_remaining(self,):
    method back_to_normal (line 68) | def back_to_normal(self):
    method create_ui (line 73) | def create_ui(self):

FILE: gui/ui_tab_short_automation.py
  class ShortAutomationUI (line 19) | class ShortAutomationUI(AbstractComponentUI):
    method __init__ (line 20) | def __init__(self, shortGptUI: gr.Blocks):
    method create_ui (line 26) | def create_ui(self):
    method create_short (line 79) | def create_short(self, numShorts, short_type, tts_engine, language_ele...
    method inspect_create_inputs (line 128) | def inspect_create_inputs(self, background_video_list, background_musi...
    method create_short_engine (line 155) | def create_short_engine(self, short_type, voice_module, language, numI...

FILE: gui/ui_tab_video_automation.py
  class Chatstate (line 21) | class Chatstate(Enum):
  class VideoAutomationUI (line 32) | class VideoAutomationUI(AbstractComponentUI):
    method __init__ (line 33) | def __init__(self, shortGptUI: gr.Blocks):
    method is_key_missing (line 50) | def is_key_missing(self):
    method generate_script (line 60) | def generate_script(self, message, language):
    method correct_script (line 63) | def correct_script(self, script, correction):
    method make_video (line 66) | def make_video(self, script, voice_module, isVertical, progress):
    method reset_components (line 81) | def reset_components(self):
    method chatbot_conversation (line 84) | def chatbot_conversation(self):
    method initialize_conversation (line 173) | def initialize_conversation(self):
    method reset_conversation (line 182) | def reset_conversation(self):
    method create_ui (line 190) | def create_ui(self):

FILE: gui/ui_tab_video_translation.py
  class VideoTranslationUI (line 20) | class VideoTranslationUI(AbstractComponentUI):
    method __init__ (line 21) | def __init__(self, shortGptUI: gr.Blocks):
    method create_ui (line 28) | def create_ui(self):
    method translate_video (line 59) | def translate_video(self, videoType, yt_link, video_path, tts_engine, ...
    method inspect_create_inputs (line 104) | def inspect_create_inputs(self, videoType, video_path, yt_link,  tts_e...
  function update_progress (line 126) | def update_progress(progress, progress_counter, num_steps, num_shorts, s...

FILE: shortGPT/api_utils/eleven_api.py
  class ElevenLabsAPI (line 6) | class ElevenLabsAPI:
    method __init__ (line 8) | def __init__(self, api_key):
    method get_voices (line 13) | def get_voices(self):
    method get_remaining_characters (line 23) | def get_remaining_characters(self):
    method generate_voice (line 35) | def generate_voice(self, text, character, filename, stability=0.2, cla...

FILE: shortGPT/api_utils/image_api.py
  function _extractBingImages (line 8) | def _extractBingImages(html):
  function _extractGoogleImages (line 21) | def _extractGoogleImages(html):
  function getBingImages (line 38) | def getBingImages(query, retries=5):

FILE: shortGPT/api_utils/pexels_api.py
  function search_videos (line 6) | def search_videos(query_string, orientation_landscape=True):
  function getBestVideo (line 26) | def getBestVideo(query_string, orientation_landscape=True, used_vids=[]):

FILE: shortGPT/audio/audio_duration.py
  function get_duration_yt_dlp (line 9) | def get_duration_yt_dlp(url):
  function get_duration_ffprobe (line 25) | def get_duration_ffprobe(signed_url):
  function get_asset_duration (line 50) | def get_asset_duration(url, isVideo=True):
  function getYoutubeAudioLink (line 68) | def getYoutubeAudioLink(url):

FILE: shortGPT/audio/audio_utils.py
  function downloadYoutubeAudio (line 15) | def downloadYoutubeAudio(url, outputFile):
  function speedUpAudio (line 45) | def speedUpAudio(tempAudioPath, outputFile, expected_duration=None):
  function ChunkForAudio (line 57) | def ChunkForAudio(alltext, chunk_size=2500):
  function audioToText (line 72) | def audioToText(filename, model_size="base"):
  function getWordsPerSec (line 81) | def getWordsPerSec(filename):
  function getCharactersPerSec (line 86) | def getCharactersPerSec(filename):
  function run_background_audio_split (line 90) | def run_background_audio_split(sound_file_path):

FILE: shortGPT/audio/edge_voice_module.py
  function run_async_func (line 12) | def run_async_func(loop, func):
  class EdgeTTSVoiceModule (line 16) | class EdgeTTSVoiceModule(VoiceModule):
    method __init__ (line 17) | def __init__(self, voiceName):
    method update_usage (line 21) | def update_usage(self):
    method get_remaining_characters (line 24) | def get_remaining_characters(self):
    method generate_voice (line 27) | def generate_voice(self, text, outputfile):
    method async_generate_voice (line 42) | async def async_generate_voice(self, text, outputfile):

FILE: shortGPT/audio/eleven_voice_module.py
  class ElevenLabsVoiceModule (line 5) | class ElevenLabsVoiceModule(VoiceModule):
    method __init__ (line 6) | def __init__(self, api_key, voiceName, checkElevenCredits=False):
    method update_usage (line 16) | def update_usage(self):
    method get_remaining_characters (line 20) | def get_remaining_characters(self):
    method generate_voice (line 23) | def generate_voice(self, text, outputfile):

FILE: shortGPT/audio/voice_module.py
  class VoiceModule (line 2) | class VoiceModule(ABC):
    method __init__ (line 4) | def __init__(self):
    method update_usage (line 7) | def update_usage(self):
    method get_remaining_characters (line 11) | def get_remaining_characters(self):
    method generate_voice (line 15) | def generate_voice(self,text, outputfile):

FILE: shortGPT/config/api_db.py
  class ApiProvider (line 6) | class ApiProvider(enum.Enum):
  class ApiKeyManager (line 13) | class ApiKeyManager:
    method get_api_key (line 17) | def get_api_key(cls, key: str | ApiProvider):
    method set_api_key (line 35) | def set_api_key(cls, key: str | ApiProvider, value: str):

FILE: shortGPT/config/asset_db.py
  class AssetType (line 19) | class AssetType(enum.Enum):
  class AssetDatabase (line 27) | class AssetDatabase:
    method asset_exists (line 49) | def asset_exists(cls, name: str) -> bool:
    method add_local_asset (line 53) | def add_local_asset(cls, name: str, asset_type: AssetType, path: str):
    method add_remote_asset (line 63) | def add_remote_asset(cls, name: str, asset_type: AssetType, url: str):
    method remove_asset (line 73) | def remove_asset(cls, name: str):
    method get_df (line 82) | def get_df(cls, source=None) -> pd.DataFrame:
    method sync_local_assets (line 109) | def sync_local_assets(cls):
    method get_asset_link (line 121) | def get_asset_link(cls, key: str) -> str:
    method get_asset_duration (line 139) | def get_asset_duration(cls, key: str) -> str:
    method _remove_local_asset (line 157) | def _remove_local_asset(cls, name: str):
    method _add_local_asset_from_path (line 173) | def _add_local_asset_from_path(cls, path: Path):
    method _update_local_asset_timestamp_and_get_link (line 198) | def _update_local_asset_timestamp_and_get_link(cls, key: str) -> str:
    method _get_remote_asset_link (line 214) | def _get_remote_asset_link(cls, key: str) -> str:
    method _get_local_asset_duration (line 232) | def _get_local_asset_duration(cls, key: str) -> str:
    method _get_remote_asset_duration (line 251) | def _get_remote_asset_duration(cls, key: str) -> str:
    method _update_local_asset_duration (line 270) | def _update_local_asset_duration(cls, key: str) -> str:
    method _update_youtube_asset_duration (line 291) | def _update_youtube_asset_duration(cls, key: str) -> str:
    method _get_youtube_asset_link (line 312) | def _get_youtube_asset_link(cls, key: str, asset: dict) -> str:

FILE: shortGPT/config/config.py
  function read_yaml_config (line 13) | def read_yaml_config(file_path: str) -> dict:
  function write_yaml_config (line 19) | def write_yaml_config(file_path: str, data: dict):
  function load_editing_assets (line 24) | def load_editing_assets() -> dict:

FILE: shortGPT/config/languages.py
  class Language (line 4) | class Language(Enum):

FILE: shortGPT/config/path_utils.py
  function search_program (line 7) | def search_program(program_name):
  function get_program_path (line 14) | def get_program_path(program_name):
  function is_running_in_colab (line 18) | def is_running_in_colab():
  function handle_path (line 21) | def handle_path(path, extension = ".mp4"):

FILE: shortGPT/database/content_data_manager.py
  class ContentDataManager (line 4) | class ContentDataManager():
    method __init__ (line 6) | def __init__(self, db_doc: AbstractDatabaseDocument, content_type: str...
    method save (line 16) | def save(self, key, value):
    method get (line 19) | def get(self, key):
    method _getId (line 22) | def _getId(self):
    method delete (line 25) | def delete(self):
    method __str__ (line 28) | def __str__(self):

FILE: shortGPT/database/content_database.py
  class ContentDatabase (line 5) | class ContentDatabase:
    method __init__ (line 6) | def __init__(self, ):
    method instanciateContentDataManager (line 9) | def instanciateContentDataManager(self, id: str, content_type: str, ne...
    method getContentDataManager (line 13) | def getContentDataManager(self, id, content_type: str):
    method createContentDataManager (line 20) | def createContentDataManager(self, content_type: str) -> ContentDataMa...

FILE: shortGPT/database/db_document.py
  class AbstractDatabaseDocument (line 8) | class AbstractDatabaseDocument(ABC):
    method _save (line 11) | def _save(self, key, data):
    method _get (line 16) | def _get(self, key):
    method _getId (line 21) | def _getId(self):
    method __str__ (line 26) | def __str__(self):
    method _delete (line 31) | def _delete(self):
  class TinyMongoClient (line 36) | class TinyMongoClient(tm.TinyMongoClient):
    method _storage (line 38) | def _storage(self):
  class TinyMongoDocument (line 45) | class TinyMongoDocument(AbstractDatabaseDocument):
    method __init__ (line 48) | def __init__(self, db_name: str, collection_name: str, document_id: st...
    method exists (line 58) | def exists(self):
    method _save (line 62) | def _save(self, data):
    method _get (line 84) | def _get(self, key=None):
    method _delete (line 100) | def _delete(self, key):
    method _getId (line 113) | def _getId(self):
    method __str__ (line 116) | def __str__(self):

FILE: shortGPT/editing_framework/core_editing_engine.py
  function load_schema (line 14) | def load_schema(json_path):
  class CoreEditingEngine (line 17) | class CoreEditingEngine:
    method generate_image (line 19) | def generate_image(self, schema:Dict[str, Any],output_file , logger=No...
    method generate_video (line 39) | def generate_video(self, schema:Dict[str, Any], output_file, logger=No...
    method generate_audio (line 88) | def generate_audio(self, schema:Dict[str, Any], output_file, logger=No...
    method process_common_actions (line 110) | def process_common_actions(self,
    method process_common_visual_actions (line 129) | def process_common_visual_actions(self,
    method process_audio_actions (line 172) | def process_audio_actions(self, clip: AudioClip,
    method process_video_asset (line 193) | def process_video_asset(self, asset: Dict[str, Any]) -> VideoFileClip:
    method process_image_asset (line 202) | def process_image_asset(self, asset: Dict[str, Any]) -> ImageClip:
    method process_text_asset (line 206) | def process_text_asset(self, asset: Dict[str, Any]) -> TextClip:
    method process_audio_asset (line 227) | def process_audio_asset(self, asset: Dict[str, Any]) -> AudioFileClip:
    method __normalize_image (line 231) | def __normalize_image(self, clip):
    method __normalize_frame (line 245) | def __normalize_frame(self, frame):

FILE: shortGPT/editing_framework/editing_engine.py
  function update_dict (line 8) | def update_dict(d, u):
  class EditingStep (line 17) | class EditingStep(Enum):
  class Flow (line 34) | class Flow(Enum):
  class EditingEngine (line 43) | class EditingEngine:
    method __init__ (line 44) | def __init__(self,):
    method addEditingStep (line 48) | def addEditingStep(self, editingStep: EditingStep, args: Dict[str, any...
    method ingestFlow (line 80) | def ingestFlow(self, flow: Flow, args):
    method dumpEditingSchema (line 92) | def dumpEditingSchema(self):
    method renderVideo (line 95) | def renderVideo(self, outputPath, logger=None):
    method renderImage (line 98) | def renderImage(self, outputPath, logger=None):
    method generateAudio (line 101) | def generateAudio(self, outputPath, logger=None):

FILE: shortGPT/editing_framework/rendering_logger.py
  class MoviepyProgressLogger (line 4) | class MoviepyProgressLogger(ProgressBarLogger):
    method __init__ (line 6) | def __init__(self, callBackFunction = None):
    method bars_callback (line 11) | def bars_callback(self, bar, attr, value, old_value=None):
    method format_time (line 22) | def format_time(self, seconds):

FILE: shortGPT/editing_utils/captions.py
  function getSpeechBlocks (line 3) | def getSpeechBlocks(whispered, silence_time=0.8):
  function cleanWord (line 16) | def cleanWord(word):
  function interpolateTimeFromDict (line 19) | def interpolateTimeFromDict(word_position, d):
  function getTimestampMapping (line 25) | def getTimestampMapping(whisper_analysis):
  function splitWordsBySize (line 36) | def splitWordsBySize(words, maxCaptionSize):
  function getCaptionsWithTime (line 50) | def getCaptionsWithTime(transcriptions, maxCaptionSize=15, considerPunct...

FILE: shortGPT/editing_utils/editing_images.py
  function getImageUrlsTimed (line 6) | def getImageUrlsTimed(imageTextPairs):
  function searchImageUrlsFromQuery (line 11) | def searchImageUrlsFromQuery(query, top=3, expected_dim=[720,720], retri...

FILE: shortGPT/editing_utils/handle_videos.py
  function getYoutubeVideoLink (line 7) | def getYoutubeVideoLink(url):
  function extract_random_clip_from_video (line 27) | def extract_random_clip_from_video(video_url, video_duration, clip_durat...
  function get_aspect_ratio (line 60) | def get_aspect_ratio(video_file):

FILE: shortGPT/engine/abstract_content_engine.py
  class AbstractContentEngine (line 12) | class AbstractContentEngine(ABC):
    method __init__ (line 13) | def __init__(self, short_id: str, content_type: str, language: Languag...
    method __getattr__ (line 29) | def __getattr__(self, name):
    method __setattr__ (line 39) | def __setattr__(self, name, value):
    method prepareEditingPaths (line 48) | def prepareEditingPaths(self):
    method verifyParameters (line 53) | def verifyParameters(*args, **kargs):
    method isShortDone (line 60) | def isShortDone(self):
    method makeContent (line 63) | def makeContent(self):
    method get_video_output_path (line 77) | def get_video_output_path(self):
    method get_total_steps (line 80) | def get_total_steps(self):
    method set_logger (line 83) | def set_logger(self, logger):
    method initializeFFMPEG (line 86) | def initializeFFMPEG(self):

FILE: shortGPT/engine/content_short_engine.py
  class ContentShortEngine (line 20) | class ContentShortEngine(AbstractContentEngine):
    method __init__ (line 22) | def __init__(self, short_type: str, background_video_name: str, backgr...
    method _generateScript (line 49) | def _generateScript(self):
    method _generateTempAudio (line 52) | def _generateTempAudio(self):
    method _speedUpAudio (line 65) | def _speedUpAudio(self):
    method _timeCaptions (line 72) | def _timeCaptions(self):
    method _generateImageSearchTerms (line 78) | def _generateImageSearchTerms(self):
    method _generateImageUrls (line 84) | def _generateImageUrls(self):
    method _chooseBackgroundMusic (line 89) | def _chooseBackgroundMusic(self):
    method _chooseBackgroundVideo (line 92) | def _chooseBackgroundVideo(self):
    method _prepareBackgroundAssets (line 98) | def _prepareBackgroundAssets(self):
    method _prepareCustomAssets (line 112) | def _prepareCustomAssets(self):
    method _editAndRenderShort (line 116) | def _editAndRenderShort(self):
    method _addYoutubeMetadata (line 156) | def _addYoutubeMetadata(self):

FILE: shortGPT/engine/content_translation_engine.py
  class ContentTranslationEngine (line 23) | class ContentTranslationEngine(AbstractContentEngine):
    method __init__ (line 25) | def __init__(self, voiceModule: VoiceModule, src_url: str = "", target...
    method _transcribe_audio (line 42) | def _transcribe_audio(self):
    method _translate_content (line 58) | def _translate_content(self):
    method _generate_translated_audio (line 69) | def _generate_translated_audio(self):
    method _edit_and_render_video (line 83) | def _edit_and_render_video(self):
    method _add_metadata (line 121) | def _add_metadata(self):

FILE: shortGPT/engine/content_video_engine.py
  class ContentVideoEngine (line 19) | class ContentVideoEngine(AbstractContentEngine):
    method __init__ (line 21) | def __init__(self, voiceModule: VoiceModule, script: str, background_m...
    method _generateTempAudio (line 45) | def _generateTempAudio(self):
    method _speedUpAudio (line 58) | def _speedUpAudio(self):
    method _timeCaptions (line 68) | def _timeCaptions(self):
    method _generateVideoSearchTerms (line 77) | def _generateVideoSearchTerms(self):
    method _generateVideoUrls (line 82) | def _generateVideoUrls(self):
    method _chooseBackgroundMusic (line 97) | def _chooseBackgroundMusic(self):
    method _prepareBackgroundAssets (line 101) | def _prepareBackgroundAssets(self):
    method _prepareCustomAssets (line 108) | def _prepareCustomAssets(self):
    method _editAndRenderShort (line 112) | def _editAndRenderShort(self):
    method _addMetadata (line 144) | def _addMetadata(self):

FILE: shortGPT/engine/facts_short_engine.py
  class FactsShortEngine (line 7) | class FactsShortEngine(ContentShortEngine):
    method __init__ (line 9) | def __init__(self, voiceModule: VoiceModule, facts_type: str, backgrou...
    method _generateScript (line 16) | def _generateScript(self):

FILE: shortGPT/engine/multi_language_translation_engine.py
  class MultiLanguageTranslationEngine (line 22) | class MultiLanguageTranslationEngine(AbstractContentEngine):
    method __init__ (line 24) | def __init__(self, voiceModule: VoiceModule, src_url: str = "", target...
    method _transcribe_audio (line 41) | def _transcribe_audio(self):
    method _translate_content (line 65) | def _translate_content(self):
    method _generate_translated_audio (line 76) | def _generate_translated_audio(self):
    method _edit_and_render_video (line 90) | def _edit_and_render_video(self):
    method _add_metadata (line 129) | def _add_metadata(self):

FILE: shortGPT/engine/reddit_short_engine.py
  class RedditShortEngine (line 10) | class RedditShortEngine(ContentShortEngine):
    method __init__ (line 12) | def __init__(self,voiceModule: VoiceModule, background_video_name: str...
    method __generateRandomStory (line 17) | def __generateRandomStory(self):
    method __getRealisticStory (line 22) | def __getRealisticStory(self, max_tries=3):
    method _generateScript (line 35) | def _generateScript(self):
    method _prepareCustomAssets (line 44) | def _prepareCustomAssets(self):
    method _editAndRenderShort (line 63) | def _editAndRenderShort(self):

FILE: shortGPT/gpt/facts_gpt.py
  function generateFacts (line 3) | def generateFacts(facts_type):
  function generateFactSubjects (line 9) | def generateFactSubjects(n):

FILE: shortGPT/gpt/gpt_chat_video.py
  function generateScript (line 3) | def generateScript(script_description, language):
  function correctScript (line 15) | def correctScript(script, correction):

FILE: shortGPT/gpt/gpt_editing.py
  function extractJsonFromString (line 3) | def extractJsonFromString(text):
  function getImageQueryPairs (line 12) | def getImageQueryPairs(captions, n=15, maxTime=2):
  function getVideoSearchQueriesTimed (line 53) | def getVideoSearchQueriesTimed(captions_timed):

FILE: shortGPT/gpt/gpt_translate.py
  function translateContent (line 3) | def translateContent(content, language):

FILE: shortGPT/gpt/gpt_utils.py
  function num_tokens_from_messages (line 13) | def num_tokens_from_messages(texts, model="gpt-4o-mini"):
  function extract_biggest_json (line 31) | def extract_biggest_json(string):
  function get_first_number (line 39) | def get_first_number(string):
  function load_yaml_file (line 48) | def load_yaml_file(file_path: str) -> dict:
  function load_json_file (line 53) | def load_json_file(file_path):
  function load_local_yaml_prompt (line 60) | def load_local_yaml_prompt(file_path):
  function open_file (line 67) | def open_file(filepath):
  function llm_completion (line 72) | def llm_completion(chat_prompt="", system="", temp=0.7, max_tokens=2000,...

FILE: shortGPT/gpt/gpt_voice.py
  function getGenderFromText (line 3) | def getGenderFromText(text):

FILE: shortGPT/gpt/gpt_yt.py
  function generate_title_description_dict (line 4) | def generate_title_description_dict(content):

FILE: shortGPT/gpt/reddit_gpt.py
  function generateRedditPostMetadata (line 4) | def generateRedditPostMetadata(title):
  function getInterestingRedditQuestion (line 15) | def getInterestingRedditQuestion():
  function createRedditScript (line 19) | def createRedditScript(question):
  function getRealisticness (line 26) | def getRealisticness(text):
  function getQuestionFromThread (line 39) | def getQuestionFromThread(text):
  function generateUsername (line 50) | def generateUsername():

FILE: shortGPT/tracking/api_tracking.py
  class APITracker (line 5) | class APITracker:
    method __init__ (line 7) | def __init__(self):
    method setDataManager (line 10) | def setDataManager(self, contentManager : ContentDataManager):
    method openAIWrapper (line 15) | def openAIWrapper(self, gptFunc):
    method elevenWrapper (line 28) | def elevenWrapper(self, audioFunc):
    method wrap_turbo (line 40) | def wrap_turbo(self):
    method wrap_eleven (line 47) | def wrap_eleven(self):
    method initiateAPITracking (line 55) | def initiateAPITracking(self):

FILE: shortGPT/utils/cli.py
  class CLI (line 4) | class CLI:
    method display_header (line 7) | def display_header():
    method display_help (line 23) | def display_help():
    method display_requirements_check (line 31) | def display_requirements_check():
    class bcolors (line 52) | class bcolors:
    method display_error (line 64) | def display_error(error_message, stack_trace):
    method get_console_green_text (line 72) | def get_console_green_text(text):
    method get_console_red_text (line 77) | def get_console_red_text(text):
    method get_console_yellow_text (line 82) | def get_console_yellow_text(text):
    method get_console_blue_text (line 87) | def get_console_blue_text(text):
    method get_console_bold_text (line 91) | def get_console_bold_text(text):
    method get_console_underline_text (line 95) | def get_console_underline_text(text):
    method get_console_cyan_text (line 99) | def get_console_cyan_text(text):
    method get_console_header_text (line 103) | def get_console_header_text(text):
    method get_console_text (line 107) | def get_console_text(text, color):
    method display_blue_text (line 111) | def display_blue_text(text):
    method display_green_text (line 115) | def display_green_text(text):
    method display_red_text (line 119) | def display_red_text(text):
    method display_yellow_text (line 123) | def display_yellow_text(text):
    method display_bold_text (line 127) | def display_bold_text(text):
    method display_underline_text (line 131) | def display_underline_text(text):
    method display_cyan_text (line 135) | def display_cyan_text(text):
    method display_header_text (line 139) | def display_header_text(text):

FILE: shortGPT/utils/requirements.py
  class Requirements (line 5) | class Requirements:
    method __init__ (line 8) | def __init__(self):
    method get_list_requirements (line 12) | def get_list_requirements(self):
    method get_os_name (line 33) | def get_os_name(self):
    method get_os_version (line 37) | def get_os_version(self):
    method get_python_version (line 41) | def get_python_version(self):
    method is_all_requirements_installed (line 45) | def is_all_requirements_installed(self):
    method is_requirement_installed (line 53) | def is_requirement_installed(self, package_name):
    method get_version (line 62) | def get_version(self, package_name):
    method get_all_requirements_versions (line 70) | def get_all_requirements_versions(self):
    method get_all_requirements_not_installed (line 78) | def get_all_requirements_not_installed(self):
Condensed preview — 152 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (436K chars).
[
  {
    "path": ".database/template_asset_db.json",
    "chars": 1649,
    "preview": "{\n    \"asset_collection\": {\n        \"1\": {\n            \"_id\": \"local_assets\",\n            \"white_reddit_template\": {\n   "
  },
  {
    "path": ".github/CHANGE_LOG.md",
    "chars": 548,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## [Unreleased]\n\n<!--\nNotes for any u"
  },
  {
    "path": ".github/CODEOWNERS",
    "chars": 282,
    "preview": "# These owners will be the default owners for everything in\n# the repo. Unless a later match takes precedence,\n# @USER w"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "chars": 5198,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 909,
    "preview": "🌟💻📚\n\n## Contributing\n\nThere are many exciting ways to contribute to ShortGPT, our AI automated content creation framewor"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 708,
    "preview": "# These are supported funding model platforms\n\ngithub: rayventura\npatreon: # Replace with a single Patreon username\nopen"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yaml",
    "chars": 2379,
    "preview": "name: 🐛 Bug Report\ndescription: File a bug report\ntitle: '🐛 [Bug]: '\nlabels: ['bug']\n\nbody:\n  - type: markdown\n    attri"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yaml",
    "chars": 1175,
    "preview": "name: ✨ Feature request\ndescription: Suggest an feature / idea for this project\ntitle: '✨ [Feature Request / Suggestion]"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.yaml",
    "chars": 473,
    "preview": "name: ❓ Question\ndescription: Ask a question about this project\ntitle: '❓ [Question]: '\nlabels: ['question']\nbody:\n  - t"
  },
  {
    "path": ".github/SECURITY.md",
    "chars": 1276,
    "preview": "# Security Policy\n\n## Supported Versions\n\n| Version | Supported          |\n| ------- | ------------------ |\n| 0.0.x   | "
  },
  {
    "path": ".github/config.yml",
    "chars": 769,
    "preview": "# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome\n\n# Comment to be posted to on f"
  },
  {
    "path": ".github/issue_label_bot.yaml",
    "chars": 102,
    "preview": "label-alias:\n    bug: 'Type: Bug'\n    feature_request: 'Type: Feature'\n    question: 'Type: Question'\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 1352,
    "preview": "## Proposed changes\n\nDescribe the big picture of your changes here to communicate to the maintainers why we should accep"
  },
  {
    "path": ".github/settings.yml",
    "chars": 7023,
    "preview": "repository:\n  # See https://developer.github.com/v3/repos/#edit for all available settings.\n\n  # The name of the reposit"
  },
  {
    "path": ".github/workflows/generate_release-changelog.yaml",
    "chars": 912,
    "preview": "name: Create Release\n\non:\n  push:\n    tags:\n      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\njobs:\n  bui"
  },
  {
    "path": ".gitignore",
    "chars": 388,
    "preview": "!*.py\n!*.json\n!*.yaml\n!*.template\n*.pyc\n**/__pycache__/\ntest.py\npublic/*\n!public/white_reddit_template.png\n!public/subsc"
  },
  {
    "path": "CHANGES.txt",
    "chars": 1012,
    "preview": "# CHANGES\n\n## Version 0.1.31\n- Fixing issue in AssetDatabase, where it was copying unexisting asset template file\n## Ver"
  },
  {
    "path": "Dockerfile",
    "chars": 720,
    "preview": "# Use an official Python runtime as the parent image\nFROM python:3.10-slim-bullseye\nRUN apt-get update && apt-get instal"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2024 Ray Ventura\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "README-Docker.md",
    "chars": 516,
    "preview": "# To run ShortGPT docker:\n\n\nFirst make a .env file with the API keys like this:\n\n```bash\nGEMINI_API_KEY=put_your_gemini_"
  },
  {
    "path": "README.md",
    "chars": 7436,
    "preview": "# 🚀🎬 ShortGPT \n## AI video automation framework\n<p align=\"center\">\n  <a href=\"https://discord.gg/uERx39ru3R\">\n    <img s"
  },
  {
    "path": "docs/.gitignore",
    "chars": 233,
    "preview": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.lo"
  },
  {
    "path": "docs/README.md",
    "chars": 281,
    "preview": "# ShortGPT Documentation\n# Installation\n\n1. `yarn install` in the root of this repository (two level above this director"
  },
  {
    "path": "docs/babel.config.js",
    "chars": 89,
    "preview": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "docs/docs/api-key-manager.mdx",
    "chars": 1853,
    "preview": "---\ntitle: ApiKeyManager in ShortGPT\nsidebar_label: ApiKeyManager\n---\n\n# ApiKeyManager in ShortGPT\n\nApiKeyManager is a c"
  },
  {
    "path": "docs/docs/asset-database.mdx",
    "chars": 2403,
    "preview": "---\ntitle: AssetDatabase in ShortGPT\nsidebar_label: AssetDatabase\n---\n\n# AssetDatabase in ShortGPT\n\nThe `AssetDatabase` "
  },
  {
    "path": "docs/docs/content-translation-engine.mdx",
    "chars": 2935,
    "preview": "---\ntitle: ContentTranslationEngine\nsidebar_label: ContentTranslationEngine\n---\n\nThe `ContentTranslationEngine` in Short"
  },
  {
    "path": "docs/docs/content-video-engine.mdx",
    "chars": 4529,
    "preview": "---\ntitle: ContentVideoEngine\nsidebar_label: ContentVideoEngine\n---\n\nThe `ContentVideoEngine` in ShortGPT is a powerful "
  },
  {
    "path": "docs/docs/facts-short-engine.mdx",
    "chars": 4401,
    "preview": "---\ntitle: FactsShortEngine\nsidebar_label: FactsShortEngine\n---\n\nThe `FactsShortEngine` in ShortGPT is a content engine "
  },
  {
    "path": "docs/docs/getting-started.mdx",
    "chars": 2706,
    "preview": "---\ntitle: ShortGPT Hello World Example\nsidebar_label: ShortGPT Hello World Example\n---\n# ShortGPT Hello World Example\n\n"
  },
  {
    "path": "docs/docs/how-to-install.mdx",
    "chars": 2330,
    "preview": "---\ntitle: Step-by-Step Guide to Installing ShortGPT\nsidebar_label: Installation Guide\n---\nimport Tabs from '@theme/Tabs"
  },
  {
    "path": "docs/docusaurus.config.js",
    "chars": 3789,
    "preview": "/* eslint-disable @typescript-eslint/no-var-requires */\nconst darkCodeTheme = require('prism-react-renderer/themes/dracu"
  },
  {
    "path": "docs/package.json",
    "chars": 1417,
    "preview": "{\n  \"name\": \"shortgpt-documentation\",\n  \"version\": \"3.5.1\",\n  \"private\": true,\n  \"scripts\": {\n    \"build:clean\": \"rm -rf"
  },
  {
    "path": "docs/plugins/my-loaders/index.js",
    "chars": 373,
    "preview": "module.exports = function () {\n  return {\n    name: 'loaders',\n    configureWebpack() {\n      return {\n        module: {"
  },
  {
    "path": "docs/plugins/tailwind-loader/index.js",
    "chars": 474,
    "preview": "/* eslint-disable @typescript-eslint/no-var-requires */\nmodule.exports = function () {\n  return {\n    name: 'postcss-tai"
  },
  {
    "path": "docs/sidebars.js",
    "chars": 810,
    "preview": "/**\n * Creating a sidebar enables you to:\n * - create an ordered group of docs\n * - render a sidebar for each doc of tha"
  },
  {
    "path": "docs/src/components/Home.js",
    "chars": 16396,
    "preview": "import { Hero } from '@algolia/ui-library';\nimport { useColorMode } from '@docusaurus/theme-common';\nimport { useBaseUrl"
  },
  {
    "path": "docs/src/css/custom.css",
    "chars": 5237,
    "preview": "@import url(fragments.css);\n@import 'tailwindcss/tailwind.css';\n\n:root {\n  --ifm-font-size-base: 16px;\n  --ifm-code-font"
  },
  {
    "path": "docs/src/css/fragments.css",
    "chars": 34228,
    "preview": ":root {\n  --transparent: transparent;\n  --white: #fff;\n  --grey-900: #23263b;\n  --grey-800: #36395a;\n  --grey-700: #484c"
  },
  {
    "path": "docs/src/pages/index.js",
    "chars": 348,
    "preview": "import Layout from '@theme/Layout';\nimport React from 'react';\n\nimport Home from '../components/Home';\n\nfunction HomePag"
  },
  {
    "path": "docs/tailwind.config.js",
    "chars": 254,
    "preview": "module.exports = {\n  purge: ['./src/**/*.html', './src/**/*.js', './src/**/*.tsx'],\n  corePlugins: { preflight: false, c"
  },
  {
    "path": "gui/asset_components.py",
    "chars": 3501,
    "preview": "import os\nimport platform\nimport random\nimport subprocess\n\nimport gradio as gr\n\nfrom shortGPT.api_utils.eleven_api impor"
  },
  {
    "path": "gui/content_automation_ui.py",
    "chars": 1505,
    "preview": "import time\nimport gradio as gr\n\nfrom gui.ui_tab_short_automation import ShortAutomationUI\nfrom gui.ui_tab_video_automat"
  },
  {
    "path": "gui/gui_gradio.py",
    "chars": 1996,
    "preview": "import gradio as gr\n\nfrom gui.content_automation_ui import GradioContentAutomationUI\nfrom gui.ui_abstract_base import Ab"
  },
  {
    "path": "gui/ui_abstract_base.py",
    "chars": 568,
    "preview": "\nimport gradio as gr\n\n\nclass AbstractBaseUI:\n    '''Base class for the GUI. This class is responsible for creating the U"
  },
  {
    "path": "gui/ui_abstract_component.py",
    "chars": 88,
    "preview": "\n\nclass AbstractComponentUI:\n    def create_ui(self):\n        raise NotImplementedError\n"
  },
  {
    "path": "gui/ui_components_html.py",
    "chars": 3104,
    "preview": "class GradioComponentsHTML:\n\n    @staticmethod\n    def get_html_header() -> str:\n        '''Create HTML for the header''"
  },
  {
    "path": "gui/ui_tab_asset_library.py",
    "chars": 12229,
    "preview": "import os\nimport re\nimport shutil\n\nimport gradio as gr\n\nfrom gui.asset_components import AssetComponentsUtils\nfrom gui.u"
  },
  {
    "path": "gui/ui_tab_config.py",
    "chars": 5954,
    "preview": "import time\n\nimport gradio as gr\n\nfrom gui.asset_components import AssetComponentsUtils\nfrom gui.ui_abstract_component i"
  },
  {
    "path": "gui/ui_tab_short_automation.py",
    "chars": 10769,
    "preview": "import os\nimport time\nimport traceback\n\nimport gradio as gr\n\nfrom gui.asset_components import AssetComponentsUtils\nfrom "
  },
  {
    "path": "gui/ui_tab_video_automation.py",
    "chars": 12028,
    "preview": "import os\nimport traceback\nfrom enum import Enum\n\nimport gradio as gr\n\nfrom gui.asset_components import AssetComponentsU"
  },
  {
    "path": "gui/ui_tab_video_translation.py",
    "chars": 8740,
    "preview": "import os\nimport time\nimport traceback\n\nimport gradio as gr\n\nfrom gui.asset_components import AssetComponentsUtils\nfrom "
  },
  {
    "path": "installation-notes.md",
    "chars": 3667,
    "preview": "** Thanks for Son Tran for the fixes on the installation guide. Here are the recommanded steps for installing ShortGPT:\n"
  },
  {
    "path": "requirements.txt",
    "chars": 270,
    "preview": "python-dotenv\ngradio_client==1.5.4\ngradio==5.12.0\nopenai==1.37.0\nhttpx==0.27.2\ntiktoken\ntinydb\ntinymongo\nproglog\nyt-dlp>"
  },
  {
    "path": "runShortGPT.py",
    "chars": 81,
    "preview": "from gui.gui_gradio import ShortGptUI\n\napp = ShortGptUI(colab=False)\napp.launch()"
  },
  {
    "path": "runShortGPTColab.py",
    "chars": 81,
    "preview": "from gui.gui_gradio import ShortGptUI\n\napp = ShortGptUI(colab=True)\napp.launch()\n"
  },
  {
    "path": "setup.py",
    "chars": 1645,
    "preview": "from setuptools import setup, find_packages\nimport codecs\nimport os\n\nhere = os.path.abspath(os.path.dirname(__file__))\n\n"
  },
  {
    "path": "shortGPT/__init__.py",
    "chars": 916,
    "preview": "# import time\n# t1 = time.time()\n# from . import config\n# print(\"Took\", time.time() - t1, \"seconds to import config\")\n# "
  },
  {
    "path": "shortGPT/api_utils/README.md",
    "chars": 3713,
    "preview": "# Module: api_utils\n\nThe `api_utils` module provides utility functions for working with different APIs. It includes thre"
  },
  {
    "path": "shortGPT/api_utils/__init__.py",
    "chars": 48,
    "preview": "from . import image_api\nfrom . import eleven_api"
  },
  {
    "path": "shortGPT/api_utils/eleven_api.py",
    "chars": 2098,
    "preview": "import json\n\nimport requests\n\n\nclass ElevenLabsAPI:\n\n    def __init__(self, api_key):\n        self.api_key = api_key\n   "
  },
  {
    "path": "shortGPT/api_utils/image_api.py",
    "chars": 2601,
    "preview": "import json\nimport requests\nimport re\nimport urllib.parse\n\nfrom urllib3 import Retry\n\ndef _extractBingImages(html):\n    "
  },
  {
    "path": "shortGPT/api_utils/pexels_api.py",
    "chars": 2188,
    "preview": "import requests\n\nfrom shortGPT.config.api_db import ApiKeyManager\n\n\ndef search_videos(query_string, orientation_landscap"
  },
  {
    "path": "shortGPT/audio/README.md",
    "chars": 3528,
    "preview": "# Audio Module\n\nThe audio module provides a set of functions and classes for working with audio files and performing var"
  },
  {
    "path": "shortGPT/audio/__init__.py",
    "chars": 88,
    "preview": "from . import audio_utils\nfrom . import eleven_voice_module\nfrom . import audio_duration"
  },
  {
    "path": "shortGPT/audio/audio_duration.py",
    "chars": 2558,
    "preview": "import json\nimport subprocess\n\nimport yt_dlp\n\nfrom shortGPT.editing_utils.handle_videos import getYoutubeVideoLink\n\n\ndef"
  },
  {
    "path": "shortGPT/audio/audio_utils.py",
    "chars": 3645,
    "preview": "import os\nimport subprocess\nimport time\n\nimport yt_dlp\n\nfrom shortGPT.audio.audio_duration import get_asset_duration\n\nCO"
  },
  {
    "path": "shortGPT/audio/edge_voice_module.py",
    "chars": 1822,
    "preview": "import asyncio\nimport os\nfrom concurrent.futures import ThreadPoolExecutor\n\nimport edge_tts\n\nfrom shortGPT.audio.voice_m"
  },
  {
    "path": "shortGPT/audio/eleven_voice_module.py",
    "chars": 1467,
    "preview": "from shortGPT.api_utils.eleven_api import ElevenLabsAPI\nfrom shortGPT.audio.voice_module import VoiceModule\n\n\nclass Elev"
  },
  {
    "path": "shortGPT/audio/voice_module.py",
    "chars": 317,
    "preview": "from abc import ABC, abstractmethod\nclass VoiceModule(ABC):\n\n    def __init__(self):\n        pass\n    @abstractmethod   "
  },
  {
    "path": "shortGPT/config/README.md",
    "chars": 4585,
    "preview": "# Module: config\n\nThe `config` module contains various files and functions related to configuration settings and utiliti"
  },
  {
    "path": "shortGPT/config/__init__.py",
    "chars": 20,
    "preview": "from . import config"
  },
  {
    "path": "shortGPT/config/api_db.py",
    "chars": 1157,
    "preview": "import enum\nimport os\nfrom shortGPT.database.db_document import TinyMongoDocument\nfrom dotenv import load_dotenv\nload_do"
  },
  {
    "path": "shortGPT/config/asset_db.py",
    "chars": 11539,
    "preview": "import base64\nimport re\nimport shutil\nimport time\nfrom datetime import datetime\nfrom pathlib import Path\nimport enum\nimp"
  },
  {
    "path": "shortGPT/config/config.py",
    "chars": 2007,
    "preview": "import yaml\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nELEVEN_LABS_KEY = os.getenv('ELEVEN_LABS_API_KEY')\n"
  },
  {
    "path": "shortGPT/config/languages.py",
    "chars": 10954,
    "preview": "\nfrom enum import Enum\n\nclass Language(Enum):\n    ENGLISH = \"English\"\n    SPANISH = \"Spanish\"\n    FRENCH = \"French\"\n    "
  },
  {
    "path": "shortGPT/config/path_utils.py",
    "chars": 989,
    "preview": "import os\nimport platform\nimport sys\nimport subprocess\nimport subprocess\nimport tempfile\ndef search_program(program_name"
  },
  {
    "path": "shortGPT/database/README.md",
    "chars": 5225,
    "preview": "# Database Module Documentation\n\nThe `database` module provides classes for managing database documents and data in the "
  },
  {
    "path": "shortGPT/database/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "shortGPT/database/content_data_manager.py",
    "chars": 755,
    "preview": "from shortGPT.database.db_document import AbstractDatabaseDocument\n\n\nclass ContentDataManager():\n\n    def __init__(self,"
  },
  {
    "path": "shortGPT/database/content_database.py",
    "chars": 1140,
    "preview": "from uuid import uuid4\nfrom shortGPT.database.db_document import TINY_MONGO_DATABASE, TinyMongoDocument\n\nfrom shortGPT.d"
  },
  {
    "path": "shortGPT/database/db_document.py",
    "chars": 3795,
    "preview": "import threading\nfrom abc import ABC, abstractmethod\n\nimport tinydb\nimport tinymongo as tm\n\n\nclass AbstractDatabaseDocum"
  },
  {
    "path": "shortGPT/editing_framework/README.md",
    "chars": 6658,
    "preview": "# Editing Framework Module Documentation\n\nThe `editing_framework` module provides a set of classes and functions for edi"
  },
  {
    "path": "shortGPT/editing_framework/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "shortGPT/editing_framework/core_editing_engine.py",
    "chars": 10752,
    "preview": "from urllib.error import HTTPError\nfrom shortGPT.config.path_utils import get_program_path\nimport os\nfrom shortGPT.confi"
  },
  {
    "path": "shortGPT/editing_framework/editing_engine.py",
    "chars": 10933,
    "preview": "import json\nfrom typing import Any, Dict, List, Union\nfrom enum import Enum\nimport collections.abc\n\nfrom shortGPT.editin"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/add_background_video.json",
    "chars": 351,
    "preview": "{\n\t\"background_video\": {\n\t\t\"type\": \"video\",\n\t\t\"z\": 0,\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"url\"],\n            \"actions\": [\"se"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/add_background_voiceover.json",
    "chars": 271,
    "preview": "{\n\t\"background_voiceover\": {\n\t\t\"inputs\": {\n\t\t\t\"parameters\": [\"url\"],\n            \"actions\": [\"volume_percentage\"]\n\t\t},\n\t"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/add_voiceover.json",
    "chars": 166,
    "preview": "{\n\t\"voiceover\": {\n\t\t\"inputs\": {\n\t\t\t\"parameters\": [\n\t\t\t\t\"url\"\n\t\t\t]\n\t\t},\n\t\t\"type\": \"audio\",\n\t\t\"z\": -1,\n\t\t\"parameters\": {\n\t"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/background_music.json",
    "chars": 429,
    "preview": "{\n\t\"background_music\": {\n\t\t\"inputs\": {\n\t\t\t\"parameters\": [\"url\", \"volume_percentage\"],\n\t\t\t\"actions\":[\"loop_background_mus"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/crop_1920x1080_to_short.json",
    "chars": 514,
    "preview": "{\n\t\"background_video\": {\n\t\t\"type\": \"video\",\n\t\t\"z\": 0,\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"url\"]\n\t\t},\n\t\t\"parameters\": {\n\t\t\t\"u"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/extract_audio.json",
    "chars": 520,
    "preview": "{\n\t\"extract_audio\": {\n\t\t\"inputs\": {\n\t\t\t\"parameters\": [\"url\"],\n            \"actions\": [\"subclip\", \"set_time_start\", \"set_"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/insert_audio.json",
    "chars": 328,
    "preview": "{\n\t\"insert_audio\": {\n\t\t\"inputs\": {\n\t\t\t\"parameters\": [\"url\"],\n            \"actions\": [\"set_time_start\", \"set_time_end\"]\n\t"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/make_caption.json",
    "chars": 581,
    "preview": "{\n\t\"caption\": {\n\t\t\"type\": \"text\",\n\t\t\"z\": 4,\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"text\"],\n\t\t\t\"actions\": [\"set_time_start\", \"se"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/make_caption_arabic.json",
    "chars": 581,
    "preview": "{\n\t\"caption\": {\n\t\t\"type\": \"text\",\n\t\t\"z\": 4,\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"text\"],\n\t\t\t\"actions\": [\"set_time_start\", \"se"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/make_caption_arabic_landscape.json",
    "chars": 542,
    "preview": "{\n\t\"caption\": {\n\t\t\"type\": \"text\",\n\t\t\"z\": 4,\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"text\"],\n\t\t\t\"actions\": [\"set_time_start\", \"se"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/make_caption_landscape.json",
    "chars": 564,
    "preview": "{\n\t\"caption\": {\n\t\t\"type\": \"text\",\n\t\t\"z\": 4,\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"text\"],\n\t\t\t\"actions\": [\"set_time_start\", \"se"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/show_reddit_image.json",
    "chars": 374,
    "preview": "{\n\t\"reddit_image\": {\n\t\t\"type\": \"image\",\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"url\"]\n\t\t},\n\t\t\"z\": 5,\n\t\t\"parameters\": {\n\t\t\t\"url\":"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/show_top_image.json",
    "chars": 641,
    "preview": "{\n\t\"top_image_1\": {\n\t\t\"type\": \"image\",\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"url\"],\n\t\t\t\"actions\": [\"set_time_start\", \"set_time"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/show_watermark.json",
    "chars": 472,
    "preview": "{\n\t\"short_watermark\": {\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"text\"]\n\t\t},\n\t\t\"type\": \"text\",\n\t\t\"z\": 3,\n\t\t\"parameters\": {\n\t\t\t\"te"
  },
  {
    "path": "shortGPT/editing_framework/editing_steps/subscribe_animation.json",
    "chars": 566,
    "preview": "{\n\t\"subscribe_animation\": {\n\t\t\"type\": \"video\",\n\t\t\"z\": 6,\n\t\t\"inputs\":{\n\t\t\t\"parameters\": [\"url\"]\n\t\t},\n\t\t\"parameters\": {\n\t\t"
  },
  {
    "path": "shortGPT/editing_framework/flows/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "shortGPT/editing_framework/flows/build_reddit_image.json",
    "chars": 1958,
    "preview": "{\n\t\"inputs\":{\n\t\t\"username_text\": \"visual_assets/username_txt/parameters/text\",\n\t\t\"ncomments_text\": \"visual_assets/ncomme"
  },
  {
    "path": "shortGPT/editing_framework/rendering_logger.py",
    "chars": 1083,
    "preview": "from proglog import ProgressBarLogger\nimport time\n\nclass MoviepyProgressLogger(ProgressBarLogger):\n    \n    def __init__"
  },
  {
    "path": "shortGPT/editing_utils/README.md",
    "chars": 4385,
    "preview": "# Module: editing_utils\n\nThe `editing_utils` module provides utility functions for editing videos and images. It consist"
  },
  {
    "path": "shortGPT/editing_utils/__init__.py",
    "chars": 51,
    "preview": "from . import editing_images\nfrom . import captions"
  },
  {
    "path": "shortGPT/editing_utils/captions.py",
    "chars": 3846,
    "preview": "import re\n\ndef getSpeechBlocks(whispered, silence_time=0.8):\n    text_blocks, (st, et, txt) = [], (0,0,\"\")\n    for i, se"
  },
  {
    "path": "shortGPT/editing_utils/editing_images.py",
    "chars": 762,
    "preview": "from shortGPT.api_utils.image_api import getBingImages\nfrom tqdm import tqdm\nimport random\nimport math\n\ndef getImageUrls"
  },
  {
    "path": "shortGPT/editing_utils/handle_videos.py",
    "chars": 3276,
    "preview": "import os\nimport random\nimport yt_dlp\nimport subprocess\nimport json\n\ndef getYoutubeVideoLink(url):\n    format_filter = \""
  },
  {
    "path": "shortGPT/engine/README.md",
    "chars": 8338,
    "preview": "# **Module: engine**\n\nThis module contains the main engine classes for generating different types of short videos. There"
  },
  {
    "path": "shortGPT/engine/__init__.py",
    "chars": 71,
    "preview": "from . import abstract_content_engine\nfrom . import reddit_short_engine"
  },
  {
    "path": "shortGPT/engine/abstract_content_engine.py",
    "chars": 3777,
    "preview": "import os\nfrom abc import ABC\n\nfrom shortGPT.audio.voice_module import VoiceModule\nfrom shortGPT.config.languages import"
  },
  {
    "path": "shortGPT/engine/content_short_engine.py",
    "chars": 8500,
    "preview": "import datetime\nimport os\nimport re\nimport shutil\nfrom abc import abstractmethod\n\nfrom shortGPT.audio import audio_utils"
  },
  {
    "path": "shortGPT/engine/content_translation_engine.py",
    "chars": 7766,
    "preview": "import datetime\nimport os\nimport re\nimport shutil\n\nfrom tqdm import tqdm\n\nfrom shortGPT.audio.audio_duration import get_"
  },
  {
    "path": "shortGPT/engine/content_video_engine.py",
    "chars": 7771,
    "preview": "import datetime\nimport os\nimport re\nimport shutil\n\nfrom shortGPT.api_utils.pexels_api import getBestVideo\nfrom shortGPT."
  },
  {
    "path": "shortGPT/engine/facts_short_engine.py",
    "chars": 1002,
    "preview": "from shortGPT.audio.voice_module import VoiceModule\nfrom shortGPT.gpt import facts_gpt\nfrom shortGPT.config.languages im"
  },
  {
    "path": "shortGPT/engine/multi_language_translation_engine.py",
    "chars": 8210,
    "preview": "import datetime\nimport os\nimport re\nimport shutil\n\nfrom tqdm import tqdm\n\nfrom shortGPT.audio.audio_duration import get_"
  },
  {
    "path": "shortGPT/engine/reddit_short_engine.py",
    "chars": 5792,
    "preview": "from shortGPT.audio.voice_module import VoiceModule\nfrom shortGPT.config.asset_db import AssetDatabase\nfrom shortGPT.con"
  },
  {
    "path": "shortGPT/gpt/README.md",
    "chars": 6876,
    "preview": "# Module: gpt\n\nThe `gpt` module provides various functions for working with the OpenAI GPT-3 API. This module consists o"
  },
  {
    "path": "shortGPT/gpt/__init__.py",
    "chars": 48,
    "preview": "from . import gpt_utils\nfrom . import reddit_gpt"
  },
  {
    "path": "shortGPT/gpt/facts_gpt.py",
    "chars": 1043,
    "preview": "from shortGPT.gpt import gpt_utils\nimport json\ndef generateFacts(facts_type):\n    chat, system = gpt_utils.load_local_ya"
  },
  {
    "path": "shortGPT/gpt/gpt_chat_video.py",
    "chars": 1232,
    "preview": "from shortGPT.gpt import gpt_utils\nimport json\ndef generateScript(script_description, language):\n    out = {'script': ''"
  },
  {
    "path": "shortGPT/gpt/gpt_editing.py",
    "chars": 3622,
    "preview": "from shortGPT.gpt import gpt_utils\nimport json\ndef extractJsonFromString(text):\n    start = text.find('{') \n    end = te"
  },
  {
    "path": "shortGPT/gpt/gpt_translate.py",
    "chars": 498,
    "preview": "from shortGPT.gpt import gpt_utils\n\ndef translateContent(content, language):\n    chat, system = gpt_utils.load_local_yam"
  },
  {
    "path": "shortGPT/gpt/gpt_utils.py",
    "chars": 4051,
    "preview": "import json\nimport os\nimport re\nfrom time import sleep, time\n\nimport openai\nimport tiktoken\nimport yaml\n\nfrom shortGPT.c"
  },
  {
    "path": "shortGPT/gpt/gpt_voice.py",
    "chars": 372,
    "preview": "\nfrom shortGPT.gpt import gpt_utils\ndef getGenderFromText(text):\n    chat, system = gpt_utils.load_local_yaml_prompt('pr"
  },
  {
    "path": "shortGPT/gpt/gpt_yt.py",
    "chars": 777,
    "preview": "from shortGPT.gpt import gpt_utils\nimport json\n\ndef generate_title_description_dict(content):\n    out = {\"title\": \"\", \"d"
  },
  {
    "path": "shortGPT/gpt/reddit_gpt.py",
    "chars": 2285,
    "preview": "from shortGPT.gpt import gpt_utils\nimport random\nimport json\ndef generateRedditPostMetadata(title):\n    name = generateU"
  },
  {
    "path": "shortGPT/prompt_templates/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "shortGPT/prompt_templates/chat_video_edit_script.yaml",
    "chars": 956,
    "preview": "system_prompt: |\n  You are an expert video script writer / editor. You ONLY write text that is read. You only write the "
  },
  {
    "path": "shortGPT/prompt_templates/chat_video_script.yaml",
    "chars": 904,
    "preview": "system_prompt: |\n  You are an expert video writer. You ONLY produce text that is read. You only produce the script. that"
  },
  {
    "path": "shortGPT/prompt_templates/editing_generate_images.yaml",
    "chars": 2426,
    "preview": "system_prompt: |\n  You are an AI specialized in generating precise image search queries for video editing. You must outp"
  },
  {
    "path": "shortGPT/prompt_templates/editing_generate_videos.yaml",
    "chars": 1773,
    "preview": "system_prompt: |\n  You are an AI specialized in generating precise video search queries for video editing. You must outp"
  },
  {
    "path": "shortGPT/prompt_templates/facts_generator.yaml",
    "chars": 1594,
    "preview": "system_prompt: >\n  You are an expert content writer of a YouTube shorts channel. You specialize in `facts` shorts.\n  You"
  },
  {
    "path": "shortGPT/prompt_templates/facts_subjects_generation.yaml",
    "chars": 335,
    "preview": "system_prompt: >\n\nchat_prompt: >\n  For a series of <<N>> youtube video about top 10 facts on a certain subject,\n  pick a"
  },
  {
    "path": "shortGPT/prompt_templates/reddit_extract_question.yaml",
    "chars": 1875,
    "preview": "system_prompt: |\n  From the transcript of a reddit ask, tell me the question in the title. The transcript always answers"
  },
  {
    "path": "shortGPT/prompt_templates/reddit_filter_realistic.yaml",
    "chars": 734,
    "preview": "system_prompt: |\n  You are the judge of the story. Your goal will be to judge if it can possibly happen. \n  If it's poss"
  },
  {
    "path": "shortGPT/prompt_templates/reddit_generate_question.yaml",
    "chars": 1621,
    "preview": "system_prompt: |\n  You will write an interesting reddit ask thread question.\n\n  Instructions for the question:\n  The que"
  },
  {
    "path": "shortGPT/prompt_templates/reddit_generate_script.yaml",
    "chars": 1587,
    "preview": "system_prompt: |\n  Instructions for the new story:\n  You are a YouTube shorts content creator who makes extremely good Y"
  },
  {
    "path": "shortGPT/prompt_templates/reddit_story_filter.yaml",
    "chars": 1135,
    "preview": "system_prompt: >\n  You're a judge of the realisticness of a story for a youtube short. \n  You must put yourself in the s"
  },
  {
    "path": "shortGPT/prompt_templates/reddit_username.yaml",
    "chars": 239,
    "preview": "system_prompt: >\n  \nchat_prompt: >\n  Generate a random Reddit name with one or two numbers inside the name. Only generat"
  },
  {
    "path": "shortGPT/prompt_templates/translate_content.yaml",
    "chars": 219,
    "preview": "system_prompt: >\n  You're an expert content translator to <<LANGUAGE>>.\n  The user will give you any text in any languag"
  },
  {
    "path": "shortGPT/prompt_templates/voice_identify_gender.yaml",
    "chars": 343,
    "preview": "system_prompt: |\n  I will give you a narrated transcript and you must identify if it's most probably a male or female. \n"
  },
  {
    "path": "shortGPT/prompt_templates/yt_title_description.yaml",
    "chars": 803,
    "preview": "system_prompt: >\n  You are a youtube shorts title and description expert writer.\n  The user will give you the transcript"
  },
  {
    "path": "shortGPT/tracking/README.md",
    "chars": 2046,
    "preview": "# Module: Tracking\n\n## Goal\nThe `tracking` module is responsible for tracking and analyzing the usage and cost of variou"
  },
  {
    "path": "shortGPT/tracking/__init__.py",
    "chars": 26,
    "preview": "from . import api_tracking"
  },
  {
    "path": "shortGPT/tracking/api_tracking.py",
    "chars": 1903,
    "preview": "from shortGPT.gpt import gpt_utils\nfrom shortGPT.database.content_data_manager import ContentDataManager\nimport json\n\ncl"
  },
  {
    "path": "shortGPT/tracking/cost_analytics.py",
    "chars": 1645,
    "preview": "import numpy as np\nfrom shortGPT.database.content_database import ContentDatabase\ndb = ContentDatabase()\nall = []\n# Calc"
  },
  {
    "path": "shortGPT/utils/cli.py",
    "chars": 4940,
    "preview": "from shortGPT.utils.requirements import Requirements\n\n\nclass CLI:\n\n    @staticmethod\n    def display_header():\n        '"
  },
  {
    "path": "shortGPT/utils/requirements.py",
    "chars": 4619,
    "preview": "import os\nimport platform\n\n\nclass Requirements:\n    '''Manage requirements for the project'''\n\n    def __init__(self):\n "
  },
  {
    "path": "videos/.gitignore",
    "chars": 80,
    "preview": "# Ignore everything in this directory\n*\n# Except this file\n!.gitignore\n!archive/"
  }
]

About this extraction

This page contains the full source code of the RayVentura/ShortGPT GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 152 files (399.2 KB), approximately 105.8k tokens, and a symbol index with 343 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!