Auto-update: Thu Aug 8 17:24:51 PDT 2024

This commit is contained in:
sanj 2024-08-08 17:24:51 -07:00
parent 75ef6577d1
commit bc94adb1da
8 changed files with 21 additions and 35 deletions

View file

@ -78,10 +78,6 @@ DAY_SHORT_FMT = os.getenv("DAY_SHORT_FMT")
# Large language model # Large language model
LLM_URL = os.getenv("LLM_URL", "http://localhost:11434") LLM_URL = os.getenv("LLM_URL", "http://localhost:11434")
LLM_SYS_MSG = os.getenv("SYSTEM_MSG", "You are a helpful AI assistant.") LLM_SYS_MSG = os.getenv("SYSTEM_MSG", "You are a helpful AI assistant.")
DEFAULT_LLM = os.getenv("DEFAULT_LLM", "llama3")
DEFAULT_VISION = os.getenv("DEFAULT_VISION", "llava")
DEFAULT_VOICE = os.getenv("DEFAULT_VOICE", "Luna")
DEFAULT_11L_VOICE = os.getenv("DEFAULT_11L_VOICE", "Victoria")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
# Summarization # Summarization
@ -118,8 +114,6 @@ TTS_DIR = DATA_DIR / "tts"
os.makedirs(TTS_DIR, exist_ok=True) os.makedirs(TTS_DIR, exist_ok=True)
VOICE_DIR = TTS_DIR / 'voices' VOICE_DIR = TTS_DIR / 'voices'
os.makedirs(VOICE_DIR, exist_ok=True) os.makedirs(VOICE_DIR, exist_ok=True)
PODCAST_DIR = os.getenv("PODCAST_DIR", TTS_DIR / "sideloads")
os.makedirs(PODCAST_DIR, exist_ok=True)
TTS_OUTPUT_DIR = TTS_DIR / 'outputs' TTS_OUTPUT_DIR = TTS_DIR / 'outputs'
os.makedirs(TTS_OUTPUT_DIR, exist_ok=True) os.makedirs(TTS_OUTPUT_DIR, exist_ok=True)
TTS_SEGMENTS_DIR = TTS_DIR / 'segments' TTS_SEGMENTS_DIR = TTS_DIR / 'segments'

View file

@ -323,8 +323,6 @@ MS365_REDIRECT_PATH=¿SECRET? # <--- e.g. http://localhost:4444/MS365/oauth
#─── via comfyui (stable diffusion): ─────── S̝͖̦͓̪̻ O̡͖̘̫͇̟ H̢͔͔̫͉͜ O̢̢͉̞͍̘ T̟͍͍̪̦̞ R I G H T N O W #─── via comfyui (stable diffusion): ─────── S̝͖̦͓̪̻ O̡͖̘̫͇̟ H̢͔͔̫͉͜ O̢̢͉̞͍̘ T̟͍͍̪̦̞ R I G H T N O W
LLM_URL=http://localhost:11434 LLM_URL=http://localhost:11434
SYSTEM_MSG=You are a helpful AI assistant. SYSTEM_MSG=You are a helpful AI assistant.
DEFAULT_LLM=dolphin-mistral
DEFAULT_VISION=llava-llama3
OPENAI_API_KEY=¿SECRET? # <--- not presently implemented for anything OPENAI_API_KEY=¿SECRET? # <--- not presently implemented for anything
SUMMARY_MODEL='command-r:latest' SUMMARY_MODEL='command-r:latest'
SUMMARY_CHUNK_SIZE=16384 SUMMARY_CHUNK_SIZE=16384
@ -335,7 +333,6 @@ SUMMARY_MIN_LENGTH=64
SUMMARY_TOKEN_LIMIT=16384 SUMMARY_TOKEN_LIMIT=16384
SUMMARY_INSTRUCT='You are an AI assistant that provides accurate summaries of text -- nothing more and nothing less. You must not include ANY extraneous text other than the sumary. Do not include comments apart from the summary, do not preface the summary, and do not provide any form of postscript. Do not add paragraph breaks. Do not add any kind of formatting. Your response should begin with, consist of, and end with an accurate plaintext summary.' SUMMARY_INSTRUCT='You are an AI assistant that provides accurate summaries of text -- nothing more and nothing less. You must not include ANY extraneous text other than the sumary. Do not include comments apart from the summary, do not preface the summary, and do not provide any form of postscript. Do not add paragraph breaks. Do not add any kind of formatting. Your response should begin with, consist of, and end with an accurate plaintext summary.'
SUMMARY_INSTRUCT_TTS='You are an AI assistant that summarizes emails -- nothing more and nothing less. You must not include ANY extraneous text other than the sumary. Do not include comments apart from the summary, do not preface the summary, and do not provide any form of postscript. Do not add paragraph breaks. Do not add any kind of formatting. Your response should begin with, consist of, and end with an accurate plaintext summary. Your response will undergo Text-To-Speech conversion and added to Sanjays private podcast. Providing adequate context (Sanjay did not send this question to you, he will only hear your response) but aiming for conciseness and precision, and bearing in mind the Text-To-Speech conversion (avoiding acronyms and formalities), summarize the following.' SUMMARY_INSTRUCT_TTS='You are an AI assistant that summarizes emails -- nothing more and nothing less. You must not include ANY extraneous text other than the sumary. Do not include comments apart from the summary, do not preface the summary, and do not provide any form of postscript. Do not add paragraph breaks. Do not add any kind of formatting. Your response should begin with, consist of, and end with an accurate plaintext summary. Your response will undergo Text-To-Speech conversion and added to Sanjays private podcast. Providing adequate context (Sanjay did not send this question to you, he will only hear your response) but aiming for conciseness and precision, and bearing in mind the Text-To-Speech conversion (avoiding acronyms and formalities), summarize the following.'
DEFAULT_VOICE=joanne
WHISPER_CPP_DIR='whisper.cpp' WHISPER_CPP_DIR='whisper.cpp'
WHISPER_CPP_MODELS=tiny,base,base-en,small,medium,medium-en,large-v3 WHISPER_CPP_MODELS=tiny,base,base-en,small,medium,medium-en,large-v3
WEBCLIPPER_TTS=elevenlabs WEBCLIPPER_TTS=elevenlabs
@ -351,9 +348,6 @@ DAY_SHORT_FMT="%Y-%m-%d"
# designed for use with `ollama`, but most of the functionality should be equal with # designed for use with `ollama`, but most of the functionality should be equal with
# LM Studio, LocalAI, ect... # LM Studio, LocalAI, ect...
# #
# DEFAULT_LLM is self-explanatory; DEFAULT_VISION is used for image recognition within
# a multimodal chat context, such as on the ig module for generating intelligible
# comments to Instagram posts, or more realistic captions for img-generated images.
# #
# Note it's possible to specify a separate model for general purposes and for # Note it's possible to specify a separate model for general purposes and for
# summarization tasks. The other SUMMARY_ variables call for some explanation, # summarization tasks. The other SUMMARY_ variables call for some explanation,
@ -391,8 +385,6 @@ DAY_SHORT_FMT="%Y-%m-%d"
# tts output was requested; tends to yield "cleaner" audio # tts output was requested; tends to yield "cleaner" audio
# with less numbers (page numbers, citations) and other # with less numbers (page numbers, citations) and other
# information extraneous to spoken contexts. # information extraneous to spoken contexts.
#
# DEFAULT_VOICE: used for all tts tasks when a specific voice is not requested.
# #
# ────────── # ──────────
# #

View file

@ -30,7 +30,7 @@ from urllib3.util.retry import Retry
from datetime import datetime as dt_datetime from datetime import datetime as dt_datetime
from better_profanity import profanity from better_profanity import profanity
from sijapi.utilities import html_to_markdown, sanitize_filename, assemble_journal_path, assemble_archive_path, contains_profanity, is_ad_or_tracker, initialize_adblock_rules, contains_blacklisted_word from sijapi.utilities import html_to_markdown, sanitize_filename, assemble_journal_path, assemble_archive_path, contains_profanity, is_ad_or_tracker, initialize_adblock_rules, contains_blacklisted_word
from sijapi import L, API, Archivist, BLOCKLISTS_DIR, OBSIDIAN_VAULT_DIR, OBSIDIAN_RESOURCES_DIR, DEFAULT_11L_VOICE, DEFAULT_VOICE from sijapi import L, API, Archivist, BLOCKLISTS_DIR, OBSIDIAN_VAULT_DIR, OBSIDIAN_RESOURCES_DIR
archivist = APIRouter() archivist = APIRouter()

View file

@ -22,7 +22,7 @@ import ssl
import yaml import yaml
from typing import List, Dict, Optional, Set from typing import List, Dict, Optional, Set
from datetime import datetime as dt_datetime from datetime import datetime as dt_datetime
from sijapi import L, PODCAST_DIR, DEFAULT_VOICE, EMAIL_CONFIG, EMAIL_LOGS from sijapi import L, Dir, EMAIL_CONFIG, EMAIL_LOGS
from sijapi.routers import gis, img, tts, llm from sijapi.routers import gis, img, tts, llm
from sijapi.utilities import clean_text, assemble_journal_path, extract_text, prefix_lines from sijapi.utilities import clean_text, assemble_journal_path, extract_text, prefix_lines
from sijapi.classes import EmailAccount, IMAPConfig, SMTPConfig, IncomingEmail, EmailContact, AutoResponder from sijapi.classes import EmailAccount, IMAPConfig, SMTPConfig, IncomingEmail, EmailContact, AutoResponder
@ -205,7 +205,7 @@ async def summarize_single_email(this_email: IncomingEmail, podcast: bool = Fals
attachment_texts = await extract_attachments(this_email.attachments) attachment_texts = await extract_attachments(this_email.attachments)
email_content += "\n—--\n" + "\n—--\n".join([f"Attachment: {text}" for text in attachment_texts]) email_content += "\n—--\n" + "\n—--\n".join([f"Attachment: {text}" for text in attachment_texts])
summary = await llm.summarize_text(email_content) summary = await llm.summarize_text(email_content)
await tts.local_tts(text_content = summary, speed = 1.1, voice = DEFAULT_VOICE, podcast = podcast, output_path = tts_path) await tts.local_tts(text_content = summary, speed = 1.1, voice = Tts.xtts.default, podcast = podcast, output_path = tts_path)
md_summary = f'```ad.summary\n' md_summary = f'```ad.summary\n'
md_summary += f'title: {this_email.subject}\n' md_summary += f'title: {this_email.subject}\n'
md_summary += f'{summary}\n' md_summary += f'{summary}\n'

View file

@ -26,7 +26,7 @@ import tempfile
import shutil import shutil
import html2text import html2text
import markdown import markdown
from sijapi import L, LLM_SYS_MSG, DEFAULT_LLM, DEFAULT_VISION, REQUESTS_DIR, OBSIDIAN_CHROMADB_COLLECTION, OBSIDIAN_VAULT_DIR, DOC_DIR, OPENAI_API_KEY, DEFAULT_VOICE, SUMMARY_INSTRUCT, SUMMARY_CHUNK_SIZE, SUMMARY_TPW, SUMMARY_CHUNK_OVERLAP, SUMMARY_LENGTH_RATIO, SUMMARY_TOKEN_LIMIT, SUMMARY_MIN_LENGTH, SUMMARY_MODEL from sijapi import L, LLM_SYS_MSG, REQUESTS_DIR, OBSIDIAN_CHROMADB_COLLECTION, OBSIDIAN_VAULT_DIR, DOC_DIR, OPENAI_API_KEY, SUMMARY_INSTRUCT, SUMMARY_CHUNK_SIZE, SUMMARY_TPW, SUMMARY_CHUNK_OVERLAP, SUMMARY_LENGTH_RATIO, SUMMARY_TOKEN_LIMIT, SUMMARY_MIN_LENGTH, SUMMARY_MODEL
from sijapi.utilities import convert_to_unix_time, sanitize_filename, ocr_pdf, clean_text, should_use_ocr, extract_text_from_pdf, extract_text_from_docx, read_text_file, str_to_bool, get_extension from sijapi.utilities import convert_to_unix_time, sanitize_filename, ocr_pdf, clean_text, should_use_ocr, extract_text_from_pdf, extract_text_from_docx, read_text_file, str_to_bool, get_extension
from sijapi.routers import tts from sijapi.routers import tts
from sijapi.routers.asr import transcribe_audio from sijapi.routers.asr import transcribe_audio
@ -87,7 +87,7 @@ async def generate_response(prompt: str):
return {"response": output['response']} return {"response": output['response']}
async def query_ollama(usr: str, sys: str = LLM_SYS_MSG, model: str = DEFAULT_LLM, max_tokens: int = 200): async def query_ollama(usr: str, sys: str = LLM_SYS_MSG, model: str = Llm.chat.model, max_tokens: int = 200):
messages = [{"role": "system", "content": sys}, messages = [{"role": "system", "content": sys},
{"role": "user", "content": usr}] {"role": "user", "content": usr}]
LLM = Ollama() LLM = Ollama()
@ -105,7 +105,7 @@ async def query_ollama(usr: str, sys: str = LLM_SYS_MSG, model: str = DEFAULT_LL
async def query_ollama_multishot( async def query_ollama_multishot(
message_list: List[str], message_list: List[str],
sys: str = LLM_SYS_MSG, sys: str = LLM_SYS_MSG,
model: str = DEFAULT_LLM, model: str = Llm.chat.model,
max_tokens: int = 200 max_tokens: int = 200
): ):
if len(message_list) % 2 == 0: if len(message_list) % 2 == 0:
@ -231,9 +231,9 @@ async def stream_messages_with_vision(message: dict, model: str, num_predict: in
def get_appropriate_model(requested_model): def get_appropriate_model(requested_model):
if requested_model == "gpt-4-vision-preview": if requested_model == "gpt-4-vision-preview":
return DEFAULT_VISION return Llm.vision.model
elif not is_model_available(requested_model): elif not is_model_available(requested_model):
return DEFAULT_LLM return Llm.chat.model
else: else:
return requested_model return requested_model
@ -314,7 +314,7 @@ async def chat_completions_options(request: Request):
], ],
"created": int(time.time()), "created": int(time.time()),
"id": str(uuid.uuid4()), "id": str(uuid.uuid4()),
"model": DEFAULT_LLM, "model": Llm.chat.model,
"object": "chat.completion.chunk", "object": "chat.completion.chunk",
}, },
status_code=200, status_code=200,
@ -533,7 +533,7 @@ async def summarize_tts_endpoint(
instruction: str = Form(SUMMARY_INSTRUCT), instruction: str = Form(SUMMARY_INSTRUCT),
file: Optional[UploadFile] = File(None), file: Optional[UploadFile] = File(None),
text: Optional[str] = Form(None), text: Optional[str] = Form(None),
voice: Optional[str] = Form(DEFAULT_VOICE), voice: Optional[str] = Form(None),
speed: Optional[float] = Form(1.2), speed: Optional[float] = Form(1.2),
podcast: Union[bool, str] = Form(False) podcast: Union[bool, str] = Form(False)
): ):
@ -577,7 +577,7 @@ async def summarize_tts_endpoint(
async def summarize_tts( async def summarize_tts(
text: str, text: str,
instruction: str = SUMMARY_INSTRUCT, instruction: str = SUMMARY_INSTRUCT,
voice: Optional[str] = DEFAULT_VOICE, voice: Optional[str] = None,
speed: float = 1.1, speed: float = 1.1,
podcast: bool = False, podcast: bool = False,
LLM: Ollama = None LLM: Ollama = None

View file

@ -18,7 +18,7 @@ from markdownify import markdownify as md
from better_profanity import profanity from better_profanity import profanity
from fastapi import APIRouter, BackgroundTasks, UploadFile, Form, HTTPException, Query, Path as FastAPIPath from fastapi import APIRouter, BackgroundTasks, UploadFile, Form, HTTPException, Query, Path as FastAPIPath
from pathlib import Path from pathlib import Path
from sijapi import L, News, Archivist, OBSIDIAN_VAULT_DIR, OBSIDIAN_RESOURCES_DIR, DEFAULT_11L_VOICE, DEFAULT_VOICE from sijapi import L, News, Archivist, OBSIDIAN_VAULT_DIR, OBSIDIAN_RESOURCES_DIR
from sijapi.utilities import html_to_markdown, download_file, sanitize_filename, assemble_journal_path, assemble_archive_path, contains_profanity, is_ad_or_tracker from sijapi.utilities import html_to_markdown, download_file, sanitize_filename, assemble_journal_path, assemble_archive_path, contains_profanity, is_ad_or_tracker
from sijapi.routers import gis, llm, tts, note from sijapi.routers import gis, llm, tts, note
@ -37,7 +37,7 @@ async def clip_post(
url: str = Form(...), url: str = Form(...),
title: Optional[str] = Form(None), title: Optional[str] = Form(None),
tts: str = Form('summary'), tts: str = Form('summary'),
voice: str = Form(DEFAULT_VOICE), voice: str = Form(None),
): ):
result = await process_and_save_article(bg_tasks, url, title, tts, voice) result = await process_and_save_article(bg_tasks, url, title, tts, voice)
return {"message": "Clip saved successfully", "result": result} return {"message": "Clip saved successfully", "result": result}
@ -46,7 +46,7 @@ async def clip_post(
async def clip_get( async def clip_get(
bg_tasks: BackgroundTasks, bg_tasks: BackgroundTasks,
url: str, url: str,
voice: str = Query(DEFAULT_VOICE) voice: str = Query(None)
): ):
result = await process_and_save_article(bg_tasks, url, None, tts, voice) result = await process_and_save_article(bg_tasks, url, None, tts, voice)
return {"message": "Clip saved successfully", "result": result} return {"message": "Clip saved successfully", "result": result}
@ -124,7 +124,7 @@ async def process_news_site(site, bg_tasks: BackgroundTasks):
earliest_date, earliest_date,
bg_tasks, bg_tasks,
tts_mode=site.tts if hasattr(site, 'tts') else "off", tts_mode=site.tts if hasattr(site, 'tts') else "off",
voice=site.voice if hasattr(site, 'voice') else DEFAULT_11L_VOICE voice=site.voice if hasattr(site, 'voice') else Tts.elevenlabs.default
)) ))
tasks.append(task) tasks.append(task)
@ -136,7 +136,7 @@ async def process_news_site(site, bg_tasks: BackgroundTasks):
err(f"Error processing {site.name}: {str(e)}") err(f"Error processing {site.name}: {str(e)}")
async def download_and_save_article(article, site_name, earliest_date, bg_tasks: BackgroundTasks, tts_mode: str = "off", voice: str = DEFAULT_11L_VOICE): async def download_and_save_article(article, site_name, earliest_date, bg_tasks: BackgroundTasks, tts_mode: str = "off", voice: str = Tts.elevenlabs.default):
try: try:
url = article.url url = article.url
parsed_article = await fetch_and_parse_article(url) parsed_article = await fetch_and_parse_article(url)
@ -156,7 +156,7 @@ async def process_and_save_article(
url: str, url: str,
title: Optional[str] = None, title: Optional[str] = None,
tts_mode: str = "summary", tts_mode: str = "summary",
voice: str = DEFAULT_VOICE, voice: str = Tts.elevenlabs.default,
site_name: Optional[str] = None site_name: Optional[str] = None
) -> str: ) -> str:

View file

@ -17,7 +17,7 @@ from dateutil.parser import parse as dateutil_parse
from fastapi import HTTPException, status from fastapi import HTTPException, status
from pathlib import Path from pathlib import Path
from fastapi import APIRouter, Query, HTTPException from fastapi import APIRouter, Query, HTTPException
from sijapi import API, L, OBSIDIAN_VAULT_DIR, OBSIDIAN_RESOURCES_DIR, OBSIDIAN_BANNER_SCENE, DEFAULT_11L_VOICE, DEFAULT_VOICE, GEO from sijapi import API, L, OBSIDIAN_VAULT_DIR, OBSIDIAN_RESOURCES_DIR, OBSIDIAN_BANNER_SCENE, GEO
from sijapi.routers import asr, cal, gis, img, llm, serve, timing, tts, weather from sijapi.routers import asr, cal, gis, img, llm, serve, timing, tts, weather
from sijapi.utilities import assemble_journal_path, convert_to_12_hour_format, sanitize_filename, convert_degrees_to_cardinal, check_file_name, HOURLY_COLUMNS_MAPPING from sijapi.utilities import assemble_journal_path, convert_to_12_hour_format, sanitize_filename, convert_degrees_to_cardinal, check_file_name, HOURLY_COLUMNS_MAPPING
from sijapi.classes import Location from sijapi.classes import Location
@ -122,7 +122,7 @@ async def process_document(
document: File, document: File,
title: Optional[str] = None, title: Optional[str] = None,
tts_mode: str = "summary", tts_mode: str = "summary",
voice: str = DEFAULT_VOICE voice: str = None,
): ):
timestamp = dt_datetime.now().strftime('%b %d, %Y at %H:%M') timestamp = dt_datetime.now().strftime('%b %d, %Y at %H:%M')

View file

@ -488,10 +488,10 @@ def copy_to_podcast_dir(file_path):
# Extract the file name from the file path # Extract the file name from the file path
file_name = Path(file_path).name file_name = Path(file_path).name
# Construct the destination path in the PODCAST_DIR # Construct the destination path in the podcast folder
destination_path = Path(Dir.PODCAST) / file_name destination_path = Path(Dir.PODCAST) / file_name
# Copy the file to the PODCAST_DIR # Copy the file to the podcast folder
shutil.copy(file_path, destination_path) shutil.copy(file_path, destination_path)
print(f"File copied successfully to {destination_path}") print(f"File copied successfully to {destination_path}")