Spaces:
Running
Running
Merge pull request #96 from rsrini7/openrouter-integration
Browse filesadded openrouter api and loaded the api key if exist in .env file
- .env.example +6 -0
- .gitignore +1 -0
- .idea/.gitignore +0 -3
- .idea/inspectionProfiles/Project_Default.xml +0 -14
- .idea/inspectionProfiles/profiles_settings.xml +0 -6
- .idea/misc.xml +0 -7
- .idea/modules.xml +0 -8
- .idea/slide-deck-ai.iml +0 -10
- .idea/vcs.xml +0 -6
- README.md +2 -0
- app.py +18 -5
- global_config.py +27 -5
- helpers/llm_helper.py +18 -1
.env.example
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Example .env file for SlideDeck AI
|
| 2 |
+
# Add your API keys and configuration values here
|
| 3 |
+
|
| 4 |
+
# OpenRouter API key (if using OpenRouter as a provider)
|
| 5 |
+
|
| 6 |
+
OPENROUTER_API_KEY=your-openrouter-api-key
|
.gitignore
CHANGED
|
@@ -144,3 +144,4 @@ dmypy.json
|
|
| 144 |
# Cython debug symbols
|
| 145 |
cython_debug/
|
| 146 |
|
|
|
|
|
|
| 144 |
# Cython debug symbols
|
| 145 |
cython_debug/
|
| 146 |
|
| 147 |
+
.idea
|
.idea/.gitignore
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
# Default ignored files
|
| 2 |
-
/shelf/
|
| 3 |
-
/workspace.xml
|
|
|
|
|
|
|
|
|
|
|
|
.idea/inspectionProfiles/Project_Default.xml
DELETED
|
@@ -1,14 +0,0 @@
|
|
| 1 |
-
<component name="InspectionProjectProfileManager">
|
| 2 |
-
<profile version="1.0">
|
| 3 |
-
<option name="myName" value="Project Default" />
|
| 4 |
-
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
| 5 |
-
<option name="ignoredPackages">
|
| 6 |
-
<value>
|
| 7 |
-
<list size="1">
|
| 8 |
-
<item index="0" class="java.lang.String" itemvalue="numpy" />
|
| 9 |
-
</list>
|
| 10 |
-
</value>
|
| 11 |
-
</option>
|
| 12 |
-
</inspection_tool>
|
| 13 |
-
</profile>
|
| 14 |
-
</component>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.idea/inspectionProfiles/profiles_settings.xml
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
<component name="InspectionProjectProfileManager">
|
| 2 |
-
<settings>
|
| 3 |
-
<option name="USE_PROJECT_PROFILE" value="false" />
|
| 4 |
-
<version value="1.0" />
|
| 5 |
-
</settings>
|
| 6 |
-
</component>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.idea/misc.xml
DELETED
|
@@ -1,7 +0,0 @@
|
|
| 1 |
-
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
-
<project version="4">
|
| 3 |
-
<component name="Black">
|
| 4 |
-
<option name="sdkName" value="Python 3.10 (slide-deck-ai)" />
|
| 5 |
-
</component>
|
| 6 |
-
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (slide-deck-ai)" project-jdk-type="Python SDK" />
|
| 7 |
-
</project>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
-
<project version="4">
|
| 3 |
-
<component name="ProjectModuleManager">
|
| 4 |
-
<modules>
|
| 5 |
-
<module fileurl="file://$PROJECT_DIR$/.idea/slide-deck-ai.iml" filepath="$PROJECT_DIR$/.idea/slide-deck-ai.iml" />
|
| 6 |
-
</modules>
|
| 7 |
-
</component>
|
| 8 |
-
</project>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.idea/slide-deck-ai.iml
DELETED
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
-
<module type="PYTHON_MODULE" version="4">
|
| 3 |
-
<component name="NewModuleRootManager">
|
| 4 |
-
<content url="file://$MODULE_DIR$">
|
| 5 |
-
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
| 6 |
-
</content>
|
| 7 |
-
<orderEntry type="inheritedJdk" />
|
| 8 |
-
<orderEntry type="sourceFolder" forTests="false" />
|
| 9 |
-
</component>
|
| 10 |
-
</module>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.idea/vcs.xml
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
-
<project version="4">
|
| 3 |
-
<component name="VcsDirectoryMappings">
|
| 4 |
-
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
| 5 |
-
</component>
|
| 6 |
-
</project>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -54,6 +54,8 @@ The supported LLMs offer different styles of content generation. Use one of the
|
|
| 54 |
| Gemini 2.0 Flash Lite | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Fastest, longer content |
|
| 55 |
| GPT | Azure OpenAI (`az`) | Mandatory; [get here](https://ai.azure.com/resource/playground) NOTE: You need to have your subscription/billing set up | Faster, longer content |
|
| 56 |
| Command R+ | Cohere (`co`) | Mandatory; [get here](https://dashboard.cohere.com/api-keys) | Shorter, simpler content |
|
|
|
|
|
|
|
| 57 |
| Llama 3.3 70B Instruct Turbo | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Detailed, slower |
|
| 58 |
| Llama 3.1 8B Instruct Turbo 128K | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Shorter |
|
| 59 |
|
|
|
|
| 54 |
| Gemini 2.0 Flash Lite | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Fastest, longer content |
|
| 55 |
| GPT | Azure OpenAI (`az`) | Mandatory; [get here](https://ai.azure.com/resource/playground) NOTE: You need to have your subscription/billing set up | Faster, longer content |
|
| 56 |
| Command R+ | Cohere (`co`) | Mandatory; [get here](https://dashboard.cohere.com/api-keys) | Shorter, simpler content |
|
| 57 |
+
| Gemini-2.0-flash-001 | OpenRouter (`or`) | Mandatory; [get here](https://openrouter.ai/settings/keys) | Faster, longer content |
|
| 58 |
+
| GPT-3.5 Turbo | OpenRouter (`or`) | Mandatory; [get here](https://openrouter.ai/settings/keys) | Faster, longer content |
|
| 59 |
| Llama 3.3 70B Instruct Turbo | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Detailed, slower |
|
| 60 |
| Llama 3.1 8B Instruct Turbo 128K | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Shorter |
|
| 61 |
|
app.py
CHANGED
|
@@ -25,10 +25,8 @@ import helpers.file_manager as filem
|
|
| 25 |
from global_config import GlobalConfig
|
| 26 |
from helpers import llm_helper, pptx_helper, text_helper
|
| 27 |
|
| 28 |
-
|
| 29 |
load_dotenv()
|
| 30 |
|
| 31 |
-
|
| 32 |
RUN_IN_OFFLINE_MODE = os.getenv('RUN_IN_OFFLINE_MODE', 'False').lower() == 'true'
|
| 33 |
|
| 34 |
|
|
@@ -182,14 +180,24 @@ with st.sidebar:
|
|
| 182 |
on_change=reset_api_key
|
| 183 |
).split(' ')[0]
|
| 184 |
|
| 185 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
api_key_token = st.text_input(
|
| 187 |
label=(
|
| 188 |
'3: Paste your API key/access token:\n\n'
|
| 189 |
'*Mandatory* for all providers.'
|
| 190 |
),
|
|
|
|
| 191 |
type='password',
|
| 192 |
-
|
| 193 |
)
|
| 194 |
|
| 195 |
# Additional configs for Azure OpenAI
|
|
@@ -349,7 +357,11 @@ def set_up_chat_ui():
|
|
| 349 |
if isinstance(chunk, str):
|
| 350 |
response += chunk
|
| 351 |
else:
|
| 352 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
|
| 354 |
# Update the progress bar with an approx progress percentage
|
| 355 |
progress_bar.progress(
|
|
@@ -581,3 +593,4 @@ def main():
|
|
| 581 |
|
| 582 |
if __name__ == '__main__':
|
| 583 |
main()
|
|
|
|
|
|
| 25 |
from global_config import GlobalConfig
|
| 26 |
from helpers import llm_helper, pptx_helper, text_helper
|
| 27 |
|
|
|
|
| 28 |
load_dotenv()
|
| 29 |
|
|
|
|
| 30 |
RUN_IN_OFFLINE_MODE = os.getenv('RUN_IN_OFFLINE_MODE', 'False').lower() == 'true'
|
| 31 |
|
| 32 |
|
|
|
|
| 180 |
on_change=reset_api_key
|
| 181 |
).split(' ')[0]
|
| 182 |
|
| 183 |
+
# --- Automatically fetch API key from .env if available ---
|
| 184 |
+
provider_match = GlobalConfig.PROVIDER_REGEX.match(llm_provider_to_use)
|
| 185 |
+
selected_provider = provider_match.group(1) if provider_match else llm_provider_to_use
|
| 186 |
+
env_key_name = GlobalConfig.PROVIDER_ENV_KEYS.get(selected_provider)
|
| 187 |
+
default_api_key = os.getenv(env_key_name, "") if env_key_name else ""
|
| 188 |
+
|
| 189 |
+
# Always sync session state to env value if needed (auto-fill on provider change)
|
| 190 |
+
if default_api_key and st.session_state.get('api_key_input', None) != default_api_key:
|
| 191 |
+
st.session_state['api_key_input'] = default_api_key
|
| 192 |
+
|
| 193 |
api_key_token = st.text_input(
|
| 194 |
label=(
|
| 195 |
'3: Paste your API key/access token:\n\n'
|
| 196 |
'*Mandatory* for all providers.'
|
| 197 |
),
|
| 198 |
+
key='api_key_input',
|
| 199 |
type='password',
|
| 200 |
+
disabled=bool(default_api_key),
|
| 201 |
)
|
| 202 |
|
| 203 |
# Additional configs for Azure OpenAI
|
|
|
|
| 357 |
if isinstance(chunk, str):
|
| 358 |
response += chunk
|
| 359 |
else:
|
| 360 |
+
content = getattr(chunk, 'content', None)
|
| 361 |
+
if content is not None:
|
| 362 |
+
response += content
|
| 363 |
+
else:
|
| 364 |
+
response += str(chunk)
|
| 365 |
|
| 366 |
# Update the progress bar with an approx progress percentage
|
| 367 |
progress_bar.progress(
|
|
|
|
| 593 |
|
| 594 |
if __name__ == '__main__':
|
| 595 |
main()
|
| 596 |
+
|
global_config.py
CHANGED
|
@@ -3,6 +3,7 @@ A set of configurations used by the app.
|
|
| 3 |
"""
|
| 4 |
import logging
|
| 5 |
import os
|
|
|
|
| 6 |
|
| 7 |
from dataclasses import dataclass
|
| 8 |
from dotenv import load_dotenv
|
|
@@ -20,9 +21,10 @@ class GlobalConfig:
|
|
| 20 |
PROVIDER_COHERE = 'co'
|
| 21 |
PROVIDER_GOOGLE_GEMINI = 'gg'
|
| 22 |
PROVIDER_HUGGING_FACE = 'hf'
|
|
|
|
| 23 |
PROVIDER_OLLAMA = 'ol'
|
|
|
|
| 24 |
PROVIDER_TOGETHER_AI = 'to'
|
| 25 |
-
PROVIDER_AZURE_OPENAI = 'az'
|
| 26 |
VALID_PROVIDERS = {
|
| 27 |
PROVIDER_COHERE,
|
| 28 |
PROVIDER_GOOGLE_GEMINI,
|
|
@@ -30,7 +32,17 @@ class GlobalConfig:
|
|
| 30 |
PROVIDER_OLLAMA,
|
| 31 |
PROVIDER_TOGETHER_AI,
|
| 32 |
PROVIDER_AZURE_OPENAI,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
}
|
|
|
|
| 34 |
VALID_MODELS = {
|
| 35 |
'[az]azure/open-ai': {
|
| 36 |
'description': 'faster, detailed',
|
|
@@ -62,6 +74,16 @@ class GlobalConfig:
|
|
| 62 |
'max_new_tokens': 8192,
|
| 63 |
'paid': False,
|
| 64 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
'[to]meta-llama/Llama-3.3-70B-Instruct-Turbo': {
|
| 66 |
'description': 'detailed, slower',
|
| 67 |
'max_new_tokens': 4096,
|
|
@@ -71,7 +93,7 @@ class GlobalConfig:
|
|
| 71 |
'description': 'shorter, faster',
|
| 72 |
'max_new_tokens': 4096,
|
| 73 |
'paid': True,
|
| 74 |
-
}
|
| 75 |
}
|
| 76 |
LLM_PROVIDER_HELP = (
|
| 77 |
'LLM provider codes:\n\n'
|
|
@@ -79,14 +101,14 @@ class GlobalConfig:
|
|
| 79 |
'- **[co]**: Cohere\n'
|
| 80 |
'- **[gg]**: Google Gemini API\n'
|
| 81 |
'- **[hf]**: Hugging Face Inference API\n'
|
| 82 |
-
'- **[
|
|
|
|
| 83 |
'[Find out more](https://github.com/barun-saha/slide-deck-ai?tab=readme-ov-file#summary-of-the-llms)'
|
| 84 |
)
|
| 85 |
DEFAULT_MODEL_INDEX = int(os.environ.get('DEFAULT_MODEL_INDEX', '4'))
|
| 86 |
LLM_MODEL_TEMPERATURE = 0.2
|
| 87 |
-
LLM_MODEL_MIN_OUTPUT_LENGTH = 100
|
| 88 |
-
LLM_MODEL_MAX_INPUT_LENGTH = 400 # characters
|
| 89 |
MAX_PAGE_COUNT = 50
|
|
|
|
| 90 |
|
| 91 |
LOG_LEVEL = 'DEBUG'
|
| 92 |
COUNT_TOKENS = False
|
|
|
|
| 3 |
"""
|
| 4 |
import logging
|
| 5 |
import os
|
| 6 |
+
import re
|
| 7 |
|
| 8 |
from dataclasses import dataclass
|
| 9 |
from dotenv import load_dotenv
|
|
|
|
| 21 |
PROVIDER_COHERE = 'co'
|
| 22 |
PROVIDER_GOOGLE_GEMINI = 'gg'
|
| 23 |
PROVIDER_HUGGING_FACE = 'hf'
|
| 24 |
+
PROVIDER_AZURE_OPENAI = 'az'
|
| 25 |
PROVIDER_OLLAMA = 'ol'
|
| 26 |
+
PROVIDER_OPENROUTER = 'or'
|
| 27 |
PROVIDER_TOGETHER_AI = 'to'
|
|
|
|
| 28 |
VALID_PROVIDERS = {
|
| 29 |
PROVIDER_COHERE,
|
| 30 |
PROVIDER_GOOGLE_GEMINI,
|
|
|
|
| 32 |
PROVIDER_OLLAMA,
|
| 33 |
PROVIDER_TOGETHER_AI,
|
| 34 |
PROVIDER_AZURE_OPENAI,
|
| 35 |
+
PROVIDER_OPENROUTER,
|
| 36 |
+
}
|
| 37 |
+
PROVIDER_ENV_KEYS = {
|
| 38 |
+
PROVIDER_COHERE: "COHERE_API_KEY",
|
| 39 |
+
PROVIDER_GOOGLE_GEMINI: "GOOGLE_API_KEY",
|
| 40 |
+
PROVIDER_HUGGING_FACE: "HUGGINGFACEHUB_API_TOKEN",
|
| 41 |
+
PROVIDER_AZURE_OPENAI: "AZURE_OPENAI_API_KEY",
|
| 42 |
+
PROVIDER_OPENROUTER: "OPENROUTER_API_KEY",
|
| 43 |
+
PROVIDER_TOGETHER_AI: "TOGETHER_API_KEY",
|
| 44 |
}
|
| 45 |
+
PROVIDER_REGEX = re.compile(r'\[(.*?)\]')
|
| 46 |
VALID_MODELS = {
|
| 47 |
'[az]azure/open-ai': {
|
| 48 |
'description': 'faster, detailed',
|
|
|
|
| 74 |
'max_new_tokens': 8192,
|
| 75 |
'paid': False,
|
| 76 |
},
|
| 77 |
+
'[or]google/gemini-2.0-flash-001': {
|
| 78 |
+
'description': 'Google Gemini-2.0-flash-001 (via OpenRouter)',
|
| 79 |
+
'max_new_tokens': 8192,
|
| 80 |
+
'paid': True,
|
| 81 |
+
},
|
| 82 |
+
'[or]openai/gpt-3.5-turbo': {
|
| 83 |
+
'description': 'OpenAI GPT-3.5 Turbo (via OpenRouter)',
|
| 84 |
+
'max_new_tokens': 4096,
|
| 85 |
+
'paid': True,
|
| 86 |
+
},
|
| 87 |
'[to]meta-llama/Llama-3.3-70B-Instruct-Turbo': {
|
| 88 |
'description': 'detailed, slower',
|
| 89 |
'max_new_tokens': 4096,
|
|
|
|
| 93 |
'description': 'shorter, faster',
|
| 94 |
'max_new_tokens': 4096,
|
| 95 |
'paid': True,
|
| 96 |
+
}
|
| 97 |
}
|
| 98 |
LLM_PROVIDER_HELP = (
|
| 99 |
'LLM provider codes:\n\n'
|
|
|
|
| 101 |
'- **[co]**: Cohere\n'
|
| 102 |
'- **[gg]**: Google Gemini API\n'
|
| 103 |
'- **[hf]**: Hugging Face Inference API\n'
|
| 104 |
+
'- **[or]**: OpenRouter\n\n'
|
| 105 |
+
'- **[to]**: Together AI\n'
|
| 106 |
'[Find out more](https://github.com/barun-saha/slide-deck-ai?tab=readme-ov-file#summary-of-the-llms)'
|
| 107 |
)
|
| 108 |
DEFAULT_MODEL_INDEX = int(os.environ.get('DEFAULT_MODEL_INDEX', '4'))
|
| 109 |
LLM_MODEL_TEMPERATURE = 0.2
|
|
|
|
|
|
|
| 110 |
MAX_PAGE_COUNT = 50
|
| 111 |
+
LLM_MODEL_MAX_INPUT_LENGTH = 1000 # characters
|
| 112 |
|
| 113 |
LOG_LEVEL = 'DEBUG'
|
| 114 |
COUNT_TOKENS = False
|
helpers/llm_helper.py
CHANGED
|
@@ -11,7 +11,7 @@ import requests
|
|
| 11 |
from requests.adapters import HTTPAdapter
|
| 12 |
from urllib3.util import Retry
|
| 13 |
from langchain_core.language_models import BaseLLM, BaseChatModel
|
| 14 |
-
|
| 15 |
|
| 16 |
sys.path.append('..')
|
| 17 |
|
|
@@ -23,6 +23,7 @@ OLLAMA_MODEL_REGEX = re.compile(r'[a-zA-Z0-9._:-]+$')
|
|
| 23 |
# 94 characters long, only containing alphanumeric characters, hyphens, and underscores
|
| 24 |
API_KEY_REGEX = re.compile(r'^[a-zA-Z0-9_-]{6,94}$')
|
| 25 |
REQUEST_TIMEOUT = 35
|
|
|
|
| 26 |
|
| 27 |
|
| 28 |
logger = logging.getLogger(__name__)
|
|
@@ -188,6 +189,22 @@ def get_langchain_llm(
|
|
| 188 |
api_key=api_key,
|
| 189 |
)
|
| 190 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
if provider == GlobalConfig.PROVIDER_COHERE:
|
| 192 |
from langchain_cohere.llms import Cohere
|
| 193 |
|
|
|
|
| 11 |
from requests.adapters import HTTPAdapter
|
| 12 |
from urllib3.util import Retry
|
| 13 |
from langchain_core.language_models import BaseLLM, BaseChatModel
|
| 14 |
+
import os
|
| 15 |
|
| 16 |
sys.path.append('..')
|
| 17 |
|
|
|
|
| 23 |
# 94 characters long, only containing alphanumeric characters, hyphens, and underscores
|
| 24 |
API_KEY_REGEX = re.compile(r'^[a-zA-Z0-9_-]{6,94}$')
|
| 25 |
REQUEST_TIMEOUT = 35
|
| 26 |
+
OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1'
|
| 27 |
|
| 28 |
|
| 29 |
logger = logging.getLogger(__name__)
|
|
|
|
| 189 |
api_key=api_key,
|
| 190 |
)
|
| 191 |
|
| 192 |
+
if provider == GlobalConfig.PROVIDER_OPENROUTER:
|
| 193 |
+
# Use langchain-openai's ChatOpenAI for OpenRouter
|
| 194 |
+
from langchain_openai import ChatOpenAI
|
| 195 |
+
|
| 196 |
+
logger.debug('Getting LLM via OpenRouter: %s', model)
|
| 197 |
+
openrouter_api_key = api_key
|
| 198 |
+
|
| 199 |
+
return ChatOpenAI(
|
| 200 |
+
base_url=OPENROUTER_BASE_URL,
|
| 201 |
+
openai_api_key=openrouter_api_key,
|
| 202 |
+
model_name=model,
|
| 203 |
+
temperature=GlobalConfig.LLM_MODEL_TEMPERATURE,
|
| 204 |
+
max_tokens=max_new_tokens,
|
| 205 |
+
streaming=True,
|
| 206 |
+
)
|
| 207 |
+
|
| 208 |
if provider == GlobalConfig.PROVIDER_COHERE:
|
| 209 |
from langchain_cohere.llms import Cohere
|
| 210 |
|