Skip to content

Commit 0d87fc9

Browse files
authored
Merge pull request #1 from LERM0/lermo-0.0.1
Lermo 0.0.1
2 parents a37b491 + a835078 commit 0d87fc9

File tree

136 files changed

+12668
-5895
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

136 files changed

+12668
-5895
lines changed

LOG.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

README.md

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,103 @@
11
# LermoAI
22

3-
AI Agent for Personalized Learning
3+
***AI Agent for Personalized Learning***
44

5+
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.
6+
7+
![](docs/app.png)
8+
9+
# Features
10+
11+
- [x] AI Agent
12+
- [x] Article Generation
13+
- [x] Podcast Generation
14+
- [x] LLM
15+
- [x] OpenAI
16+
- [x] Mistral
17+
- [x] Llama
18+
- [ ] Groq
19+
- [ ] Claude
20+
- [ ] Learning Path
21+
- [ ] Chat Agent
22+
- [ ] Video Generation
23+
- [ ] Custom Agent
24+
- [ ] Search Agent
525

626
# Getting Started
727

8-
In Progress
28+
### Requirements
29+
30+
- Node.js
31+
- Next.js
32+
- React
33+
- Python
34+
35+
### Web
36+
37+
To set up the frontend:
38+
39+
```sh
40+
cd apps/frontend/apps/lermo-gen-web
41+
42+
# Install Dependencies
43+
pnpm i
44+
45+
# Start
46+
pnpm run dev
47+
```
48+
49+
### API
50+
51+
To set up the API:
52+
53+
```sh
54+
cd apps/api/core-api
55+
56+
# Install Dependencies
57+
pip install -r requirements.txt
58+
pip install git+https://github.com/myshell-ai/MeloTTS.git
59+
python -m unidic download
60+
61+
# Start
62+
python main.py
63+
```
64+
65+
### LLM
66+
67+
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).
68+
69+
### Docker Setup
70+
71+
Edit the environment variables to use either OpenAI or your self-hosted LLM:
72+
73+
```yaml
74+
# OpenAI
75+
args:
76+
- OPENAI_API_BASE=https://api.openai.com/v1
77+
- OPENAI_API_KEY=sk-proj-xxx
78+
79+
# Hugging Face
80+
args:
81+
- OPENAI_API_BASE=https://llama-cpp.hf.space
82+
- OPENAI_API_KEY=llama-key
83+
```
84+
85+
To start the Docker containers:
86+
87+
```sh
88+
docker-compose up
89+
```
90+
91+
# Free and Open for Everyone
92+
93+
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.
94+
95+
# Support Us
96+
97+
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 contact@lermo.io to express your interest and discuss potential contributions.
98+
99+
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.
100+
101+
# Lermo Mission
102+
103+
"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."

apps/api/core-api/Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
FROM nvidia/cuda:11.8.0-base-ubuntu22.04
22

3+
ARG OPENAI_API_BASE
4+
ARG OPENAI_API_KEY
5+
36
ENV PYTHON_VERSION=3.10
7+
ENV OPENAI_API_BASE=$OPENAI_API_BASE
8+
ENV OPENAI_API_KEY=$OPENAI_API_KEY
49

510
RUN apt-get -qq update \
611
&& apt-get -qq install --no-install-recommends \
@@ -29,4 +34,4 @@ RUN python -m unidic download
2934

3035
EXPOSE 8000
3136

32-
# ENTRYPOINT python main.py
37+
ENTRYPOINT python main.py
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
[
2+
{
3+
"name": "Main Agent",
4+
"role": "General knowledge instructor",
5+
"personality": "Well-rounded, knowledgeable, and curious. Enjoys learning about a wide range of topics and sharing that knowledge with others.",
6+
"areas": "History, geography, science, arts, culture, current events, and general trivia.",
7+
"style": "Engaging discussions, informative explanations, and interactive quizzes."
8+
},
9+
{
10+
"name": "Lang Guru",
11+
"role": "Language and literature instructor",
12+
"personality": "Creative, articulate, and well-read. Enjoys playing with words and helping students improve their writing and reading skills.",
13+
"areas": "Grammar, vocabulary, literature analysis, and creative writing.",
14+
"style": "Interactive exercises, engaging storytelling, and personalized feedback."
15+
},
16+
{
17+
"name": "Math Master",
18+
"role": "Mathematics instructor",
19+
"personality": "Logical, precise, and patient. Enjoys solving complex problems and helping students grasp difficult concepts.",
20+
"areas": "Algebra, calculus, geometry, statistics, and discrete math.",
21+
"style": "Step-by-step explanations, interactive problem-solving, and visual aids."
22+
},
23+
{
24+
"name": "Physics Pro",
25+
"role": "Physics instructor",
26+
"personality": "Curious, analytical, and enthusiastic about the laws of nature. Loves conducting experiments and explaining the principles of physics.",
27+
"areas": "Mechanics, electromagnetism, thermodynamics, optics, and quantum physics.",
28+
"style": "Real-world applications, hands-on experiments, and conceptual clarity."
29+
},
30+
{
31+
"name": "Chem Wizard",
32+
"role": "Chemistry instructor",
33+
"personality": "Detail-oriented, methodical, and passionate about chemical reactions. Enjoys demonstrating experiments and breaking down complex molecules.",
34+
"areas": "Organic chemistry, inorganic chemistry, biochemistry, physical chemistry, and analytical chemistry.",
35+
"style": "Laboratory experiments, interactive simulations, and mnemonic devices."
36+
},
37+
{
38+
"name": "Bio Genius",
39+
"role": "Biology instructor",
40+
"personality": "Inquisitive, observant, and dedicated to the study of life. Loves exploring the diversity of living organisms and ecosystems.",
41+
"areas": "Genetics, molecular biology, ecology, anatomy and physiology, and evolutionary biology.",
42+
"style": "Field studies, hands-on dissections, and engaging multimedia content."
43+
},
44+
{
45+
"name": "Tech Guru",
46+
"role": "Technology and computer science instructor",
47+
"personality": "Innovative, tech-savvy, and always up-to-date with the latest advancements. Enjoys coding, debugging, and teaching new technologies.",
48+
"areas": "Programming languages, software development, computer networks, cybersecurity, and artificial intelligence.",
49+
"style": "Coding challenges, real-world projects, and interactive tutorials."
50+
}
51+
]

apps/api/core-api/app/api/main.py

Lines changed: 100 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,112 @@
11
from fastapi import APIRouter, HTTPException, Depends, Header, Request
2-
from fastapi.responses import StreamingResponse, FileResponse
2+
from fastapi.responses import StreamingResponse, FileResponse, JSONResponse
33

4-
from app.engine import create_podcast_script, text_to_voice
4+
from app.engine import create_podcast_script, text_to_voice, create_content_suggestions, create_article, config_agent
5+
import json
6+
import logging
57

68
router = APIRouter()
79

10+
@router.get("/agent")
11+
async def get_template():
12+
try:
13+
with open('/app/app/agent_template.json', 'r') as file:
14+
template_data = json.load(file)
15+
return JSONResponse(content={"data": template_data}, media_type="application/json")
16+
except Exception as e:
17+
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
18+
logging.error(f"An error occurred: {e}")
19+
raise HTTPException(status_code=500, detail=str(e))
20+
21+
@router.post("/agent")
22+
async def update_agent(request: Request):
23+
try:
24+
params = await request.json()
25+
with open('/app/app/agent_template.json', 'w') as file:
26+
json.dump(params, file)
27+
return JSONResponse(content={
28+
"config": "content"
29+
}, media_type="application/json")
30+
except Exception as e:
31+
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
32+
logging.error(f"An error occurred: {e}")
33+
raise HTTPException(status_code=500, detail=str(e))
34+
35+
36+
@router.put("/config")
37+
async def update_config(request: Request):
38+
try:
39+
params = await request.json()
40+
print(params)
41+
if all(param == "" for param in [params.get(key, "") for key in ["agentName", "voiceName", "podcastName", "podcastSpeed"]]):
42+
return JSONResponse(content={"message": "No changes to apply."}, media_type="application/json")
43+
44+
# Read the existing configuration
45+
try:
46+
with open('/app/app/config.json', 'r') as file:
47+
existing_config = json.load(file)
48+
except FileNotFoundError:
49+
existing_config = {}
50+
51+
# Merge the existing configuration with the new values
52+
new_config = {**existing_config, **{key: params[key] for key in ["agentName", "voiceName", "podcastName", "podcastSpeed"] if params.get(key)}}
53+
54+
# Write the merged configuration back to the file
55+
with open('/app/app/config.json', 'w') as file:
56+
json.dump(new_config, file)
57+
58+
config_agent()
59+
60+
return JSONResponse(content={"message": "Configuration updated successfully.", "data": new_config}, media_type="application/json")
61+
except Exception as e:
62+
logging.error(f"An error occurred: {e}")
63+
raise HTTPException(status_code=500, detail=str(e))
64+
865
@router.post("/podcast")
66+
async def chat_llama(request: Request) -> StreamingResponse:
67+
try:
68+
data = await request.json()
69+
prompt = data.get("prompt")
70+
71+
scheme = request.url.scheme
72+
netloc = request.url.netloc
73+
74+
text = create_podcast_script(prompt)
75+
filePath = text_to_voice(text)
76+
full_url = f"{scheme}://{netloc}{filePath}"
77+
78+
return JSONResponse(content={
79+
"full_url": full_url
80+
}, media_type="application/json")
81+
except Exception as e:
82+
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
83+
logging.error(f"An error occurred: {e}")
84+
raise HTTPException(status_code=500, detail=str(e))
85+
86+
87+
@router.post("/article")
88+
async def chat_llama(request: Request) -> StreamingResponse:
89+
try:
90+
data = await request.json()
91+
prompt = data.get("prompt")
92+
article_content = create_article(prompt)
93+
return JSONResponse(content={"data": f"{article_content}"}, media_type="application/json")
94+
except Exception as e:
95+
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
96+
logging.error(f"An error occurred: {e}")
97+
raise HTTPException(status_code=500, detail=str(e))
98+
99+
100+
@router.post("/suggest")
9101
async def chat_with_model(request: Request):
10102
try:
11103
params = await request.json()
104+
config = params.get("config")
12105
prompt = params.get("prompt")
13-
content = params.get("content")
14-
text = create_podcast_script(content)
15-
16-
prompt_array = prompt.split(", ")[:2]
17-
file_name = prompt_array[0]
18-
speaker = prompt_array[1]
19-
file_path_full = f"/tmp/voice/{file_name}.wav"
106+
json_res = create_content_suggestions(prompt)
20107

21-
text_to_voice(text, file_path_full, speaker)
22-
return FileResponse(path=file_path_full, media_type="audio/wav", filename=f"{file_name}.wav")
108+
return JSONResponse(content={"data": json_res}, media_type="application/json")
23109
except Exception as e:
24-
raise HTTPException(status_code=500, detail=str(e))
110+
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
111+
logging.error(f"An error occurred: {e}")
112+
raise HTTPException(status_code=500, detail=str(e))

apps/api/core-api/app/config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"agentName": "Physics Pro", "voiceName": "EN-Default", "podcastName": "default", "podcastSpeed": 1}

0 commit comments

Comments
 (0)