-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from LERM0/lermo-0.0.1
Lermo 0.0.1
- Loading branch information
Showing
136 changed files
with
12,668 additions
and
5,895 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,103 @@ | ||
# LermoAI | ||
|
||
AI Agent for Personalized Learning | ||
***AI Agent for Personalized Learning*** | ||
|
||
LermoAI is an open-source project that aims to revolutionize the way you learn. By generating personalized content tailored to your preferences, LermoAI ensures that your learning experience is both efficient and enjoyable. Whether you prefer reading articles, listening to podcasts, or watching videos, LermoAI creates custom learning materials just for you. Choose your AI agent and embark on a learning journey that's perfectly suited to your needs. | ||
|
||
![](docs/app.png) | ||
|
||
# Features | ||
|
||
- [x] AI Agent | ||
- [x] Article Generation | ||
- [x] Podcast Generation | ||
- [x] LLM | ||
- [x] OpenAI | ||
- [x] Mistral | ||
- [x] Llama | ||
- [ ] Groq | ||
- [ ] Claude | ||
- [ ] Learning Path | ||
- [ ] Chat Agent | ||
- [ ] Video Generation | ||
- [ ] Custom Agent | ||
- [ ] Search Agent | ||
|
||
# Getting Started | ||
|
||
In Progress | ||
### Requirements | ||
|
||
- Node.js | ||
- Next.js | ||
- React | ||
- Python | ||
|
||
### Web | ||
|
||
To set up the frontend: | ||
|
||
```sh | ||
cd apps/frontend/apps/lermo-gen-web | ||
|
||
# Install Dependencies | ||
pnpm i | ||
|
||
# Start | ||
pnpm run dev | ||
``` | ||
|
||
### API | ||
|
||
To set up the API: | ||
|
||
```sh | ||
cd apps/api/core-api | ||
|
||
# Install Dependencies | ||
pip install -r requirements.txt | ||
pip install git+https://github.com/myshell-ai/MeloTTS.git | ||
python -m unidic download | ||
|
||
# Start | ||
python main.py | ||
``` | ||
|
||
### LLM | ||
|
||
LermoAI supports both OpenAI and self-hosted LLMs such as Llama and Mistral. For more details, refer to the [LLM README](apps/llm/README.md). | ||
|
||
### Docker Setup | ||
|
||
Edit the environment variables to use either OpenAI or your self-hosted LLM: | ||
|
||
```yaml | ||
# OpenAI | ||
args: | ||
- OPENAI_API_BASE=https://api.openai.com/v1 | ||
- OPENAI_API_KEY=sk-proj-xxx | ||
|
||
# Hugging Face | ||
args: | ||
- OPENAI_API_BASE=https://llama-cpp.hf.space | ||
- OPENAI_API_KEY=llama-key | ||
``` | ||
To start the Docker containers: | ||
```sh | ||
docker-compose up | ||
``` | ||
|
||
# Free and Open for Everyone | ||
|
||
At Lermo, we believe in making education accessible to all. That's why it is completely free and open for everyone to use. We aim to democratize education and provide equal opportunities for all learners. | ||
|
||
# Support Us | ||
|
||
Contributor: We are currently building a small group of contributors for this project as it is still in its initial stages. We welcome individuals who are interested in joining our team and contribute to the development and improvement of this project. Please reach out to us at [email protected] to express your interest and discuss potential contributions. | ||
|
||
Sponsorship: We are planning to utilize platforms such as Github Sponsors, Patreon, and buymeacoffee to gather financial support for this project. Your sponsorship will greatly assist us in furthering our mission of changing the education system. Stay tuned for more information on how you can sponsor and support our project through these platforms. | ||
|
||
# Lermo Mission | ||
|
||
"Picture a groundbreaking education system that transcends barriers, offering boundless access to knowledge for all. It embodies inclusivity and equality, empowering learners worldwide to embrace their potential and pursue dreams without constraints. In this educational utopia, knowledge fuels curiosity, ignites intellect, and fosters a love for learning, shaping a brighter, enlightened future for humanity. Let's dare to envision and strive for an education system that belongs to everyone—a beacon of hope and empowerment, inspiring generations to flourish and make a positive impact." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
[ | ||
{ | ||
"name": "Main Agent", | ||
"role": "General knowledge instructor", | ||
"personality": "Well-rounded, knowledgeable, and curious. Enjoys learning about a wide range of topics and sharing that knowledge with others.", | ||
"areas": "History, geography, science, arts, culture, current events, and general trivia.", | ||
"style": "Engaging discussions, informative explanations, and interactive quizzes." | ||
}, | ||
{ | ||
"name": "Lang Guru", | ||
"role": "Language and literature instructor", | ||
"personality": "Creative, articulate, and well-read. Enjoys playing with words and helping students improve their writing and reading skills.", | ||
"areas": "Grammar, vocabulary, literature analysis, and creative writing.", | ||
"style": "Interactive exercises, engaging storytelling, and personalized feedback." | ||
}, | ||
{ | ||
"name": "Math Master", | ||
"role": "Mathematics instructor", | ||
"personality": "Logical, precise, and patient. Enjoys solving complex problems and helping students grasp difficult concepts.", | ||
"areas": "Algebra, calculus, geometry, statistics, and discrete math.", | ||
"style": "Step-by-step explanations, interactive problem-solving, and visual aids." | ||
}, | ||
{ | ||
"name": "Physics Pro", | ||
"role": "Physics instructor", | ||
"personality": "Curious, analytical, and enthusiastic about the laws of nature. Loves conducting experiments and explaining the principles of physics.", | ||
"areas": "Mechanics, electromagnetism, thermodynamics, optics, and quantum physics.", | ||
"style": "Real-world applications, hands-on experiments, and conceptual clarity." | ||
}, | ||
{ | ||
"name": "Chem Wizard", | ||
"role": "Chemistry instructor", | ||
"personality": "Detail-oriented, methodical, and passionate about chemical reactions. Enjoys demonstrating experiments and breaking down complex molecules.", | ||
"areas": "Organic chemistry, inorganic chemistry, biochemistry, physical chemistry, and analytical chemistry.", | ||
"style": "Laboratory experiments, interactive simulations, and mnemonic devices." | ||
}, | ||
{ | ||
"name": "Bio Genius", | ||
"role": "Biology instructor", | ||
"personality": "Inquisitive, observant, and dedicated to the study of life. Loves exploring the diversity of living organisms and ecosystems.", | ||
"areas": "Genetics, molecular biology, ecology, anatomy and physiology, and evolutionary biology.", | ||
"style": "Field studies, hands-on dissections, and engaging multimedia content." | ||
}, | ||
{ | ||
"name": "Tech Guru", | ||
"role": "Technology and computer science instructor", | ||
"personality": "Innovative, tech-savvy, and always up-to-date with the latest advancements. Enjoys coding, debugging, and teaching new technologies.", | ||
"areas": "Programming languages, software development, computer networks, cybersecurity, and artificial intelligence.", | ||
"style": "Coding challenges, real-world projects, and interactive tutorials." | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,112 @@ | ||
from fastapi import APIRouter, HTTPException, Depends, Header, Request | ||
from fastapi.responses import StreamingResponse, FileResponse | ||
from fastapi.responses import StreamingResponse, FileResponse, JSONResponse | ||
|
||
from app.engine import create_podcast_script, text_to_voice | ||
from app.engine import create_podcast_script, text_to_voice, create_content_suggestions, create_article, config_agent | ||
import json | ||
import logging | ||
|
||
router = APIRouter() | ||
|
||
@router.get("/agent") | ||
async def get_template(): | ||
try: | ||
with open('/app/app/agent_template.json', 'r') as file: | ||
template_data = json.load(file) | ||
return JSONResponse(content={"data": template_data}, media_type="application/json") | ||
except Exception as e: | ||
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s') | ||
logging.error(f"An error occurred: {e}") | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
@router.post("/agent") | ||
async def update_agent(request: Request): | ||
try: | ||
params = await request.json() | ||
with open('/app/app/agent_template.json', 'w') as file: | ||
json.dump(params, file) | ||
return JSONResponse(content={ | ||
"config": "content" | ||
}, media_type="application/json") | ||
except Exception as e: | ||
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s') | ||
logging.error(f"An error occurred: {e}") | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
|
||
@router.put("/config") | ||
async def update_config(request: Request): | ||
try: | ||
params = await request.json() | ||
print(params) | ||
if all(param == "" for param in [params.get(key, "") for key in ["agentName", "voiceName", "podcastName", "podcastSpeed"]]): | ||
return JSONResponse(content={"message": "No changes to apply."}, media_type="application/json") | ||
|
||
# Read the existing configuration | ||
try: | ||
with open('/app/app/config.json', 'r') as file: | ||
existing_config = json.load(file) | ||
except FileNotFoundError: | ||
existing_config = {} | ||
|
||
# Merge the existing configuration with the new values | ||
new_config = {**existing_config, **{key: params[key] for key in ["agentName", "voiceName", "podcastName", "podcastSpeed"] if params.get(key)}} | ||
|
||
# Write the merged configuration back to the file | ||
with open('/app/app/config.json', 'w') as file: | ||
json.dump(new_config, file) | ||
|
||
config_agent() | ||
|
||
return JSONResponse(content={"message": "Configuration updated successfully.", "data": new_config}, media_type="application/json") | ||
except Exception as e: | ||
logging.error(f"An error occurred: {e}") | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
@router.post("/podcast") | ||
async def chat_llama(request: Request) -> StreamingResponse: | ||
try: | ||
data = await request.json() | ||
prompt = data.get("prompt") | ||
|
||
scheme = request.url.scheme | ||
netloc = request.url.netloc | ||
|
||
text = create_podcast_script(prompt) | ||
filePath = text_to_voice(text) | ||
full_url = f"{scheme}://{netloc}{filePath}" | ||
|
||
return JSONResponse(content={ | ||
"full_url": full_url | ||
}, media_type="application/json") | ||
except Exception as e: | ||
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s') | ||
logging.error(f"An error occurred: {e}") | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
|
||
@router.post("/article") | ||
async def chat_llama(request: Request) -> StreamingResponse: | ||
try: | ||
data = await request.json() | ||
prompt = data.get("prompt") | ||
article_content = create_article(prompt) | ||
return JSONResponse(content={"data": f"{article_content}"}, media_type="application/json") | ||
except Exception as e: | ||
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s') | ||
logging.error(f"An error occurred: {e}") | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
|
||
@router.post("/suggest") | ||
async def chat_with_model(request: Request): | ||
try: | ||
params = await request.json() | ||
config = params.get("config") | ||
prompt = params.get("prompt") | ||
content = params.get("content") | ||
text = create_podcast_script(content) | ||
|
||
prompt_array = prompt.split(", ")[:2] | ||
file_name = prompt_array[0] | ||
speaker = prompt_array[1] | ||
file_path_full = f"/tmp/voice/{file_name}.wav" | ||
json_res = create_content_suggestions(prompt) | ||
|
||
text_to_voice(text, file_path_full, speaker) | ||
return FileResponse(path=file_path_full, media_type="audio/wav", filename=f"{file_name}.wav") | ||
return JSONResponse(content={"data": json_res}, media_type="application/json") | ||
except Exception as e: | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s') | ||
logging.error(f"An error occurred: {e}") | ||
raise HTTPException(status_code=500, detail=str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"agentName": "Physics Pro", "voiceName": "EN-Default", "podcastName": "default", "podcastSpeed": 1} |
Oops, something went wrong.