GitHub Action
		
	commited on
		
		
					Commit 
							
							·
						
						ec4e6b9
	
1
								Parent(s):
							
							ae2be5c
								
Sync from GitHub with Git LFS
Browse filesThis view is limited to 50 files because it contains too many changes.  
							See raw diff
- agents/notebook/views.py +1 -1
- hf_repo/agents/notebook/views.py +11 -1
- hf_repo/agents/requirements.txt +2 -1
- hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -2
- hf_repo/hf_repo/hf_repo/agents/tools/storage.py +1 -1
- hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +1 -1
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql +4 -3
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +5 -1
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +12 -0
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +3 -3
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +4 -3
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -2
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -2
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +1 -1
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +12 -10
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +0 -5
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +30 -23
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +15 -9
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/web_ui.py +0 -2
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html +14 -6
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -4
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html +15 -7
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +7 -7
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml +65 -40
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html +1 -0
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html +1 -0
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml +40 -65
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html +5 -14
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +9 -2
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html +6 -14
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +36 -30
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +26 -19
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html +14 -0
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +40 -8
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html +14 -0
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +72 -11
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/requirements.txt +2 -1
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +76 -11
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/web_ui.py +3 -0
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/add_message.py +5 -9
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +3 -5
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql +1 -1
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +5 -5
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/readme.md +1 -1
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml +65 -40
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/readme.md +1 -2
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/check_agents.py +19 -5
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml +40 -71
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/examples/config.yml +1 -7
- hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/init.py +17 -26
    	
        agents/notebook/views.py
    CHANGED
    
    | @@ -12,7 +12,7 @@ router = APIRouter() | |
| 12 | 
             
            templates = Jinja2Templates(directory="notebook/templates")
         | 
| 13 | 
             
            storage = Storage()
         | 
| 14 |  | 
| 15 | 
            -
            allowed_tags = ['b', 'i', 'a']
         | 
| 16 | 
             
            allowed_attributes = {
         | 
| 17 | 
             
                'a': ['href', 'title']
         | 
| 18 | 
             
            }
         | 
|  | |
| 12 | 
             
            templates = Jinja2Templates(directory="notebook/templates")
         | 
| 13 | 
             
            storage = Storage()
         | 
| 14 |  | 
| 15 | 
            +
            allowed_tags = ['b', 'i', 'a', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'table', 'caption', 'tr', 'th', 'td']
         | 
| 16 | 
             
            allowed_attributes = {
         | 
| 17 | 
             
                'a': ['href', 'title']
         | 
| 18 | 
             
            }
         | 
    	
        hf_repo/agents/notebook/views.py
    CHANGED
    
    | @@ -1,5 +1,7 @@ | |
| 1 | 
             
            # agents/notebook/views.py
         | 
| 2 |  | 
|  | |
|  | |
| 3 | 
             
            from fastapi import APIRouter, Request, Form
         | 
| 4 | 
             
            from fastapi.responses import RedirectResponse, HTMLResponse
         | 
| 5 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| @@ -10,6 +12,14 @@ router = APIRouter() | |
| 10 | 
             
            templates = Jinja2Templates(directory="notebook/templates")
         | 
| 11 | 
             
            storage = Storage()
         | 
| 12 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 13 | 
             
            @router.get("/chat")
         | 
| 14 | 
             
            def chat_page(request: Request):
         | 
| 15 | 
             
                did = request.session.get("did")
         | 
| @@ -72,7 +82,7 @@ def post_message( | |
| 72 |  | 
| 73 | 
             
                if text.strip():
         | 
| 74 | 
             
                    storage.write_note(
         | 
| 75 | 
            -
                        content=text.strip(),
         | 
| 76 | 
             
                        user_did=did,
         | 
| 77 | 
             
                        source="user",
         | 
| 78 | 
             
                        hidden=is_hidden
         | 
|  | |
| 1 | 
             
            # agents/notebook/views.py
         | 
| 2 |  | 
| 3 | 
            +
            import bleach
         | 
| 4 | 
            +
             | 
| 5 | 
             
            from fastapi import APIRouter, Request, Form
         | 
| 6 | 
             
            from fastapi.responses import RedirectResponse, HTMLResponse
         | 
| 7 | 
             
            from fastapi.templating import Jinja2Templates
         | 
|  | |
| 12 | 
             
            templates = Jinja2Templates(directory="notebook/templates")
         | 
| 13 | 
             
            storage = Storage()
         | 
| 14 |  | 
| 15 | 
            +
            allowed_tags = ['b', 'i', 'a', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'table', 'caption', 'tr', 'th', 'td']
         | 
| 16 | 
            +
            allowed_attributes = {
         | 
| 17 | 
            +
                'a': ['href', 'title']
         | 
| 18 | 
            +
            }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            def sanitize_html(text):
         | 
| 21 | 
            +
                return bleach.clean(text, tags=allowed_tags, attributes=allowed_attributes, strip=True)
         | 
| 22 | 
            +
             | 
| 23 | 
             
            @router.get("/chat")
         | 
| 24 | 
             
            def chat_page(request: Request):
         | 
| 25 | 
             
                did = request.session.get("did")
         | 
|  | |
| 82 |  | 
| 83 | 
             
                if text.strip():
         | 
| 84 | 
             
                    storage.write_note(
         | 
| 85 | 
            +
                        content=sanitize_html(text.strip()),
         | 
| 86 | 
             
                        user_did=did,
         | 
| 87 | 
             
                        source="user",
         | 
| 88 | 
             
                        hidden=is_hidden
         | 
    	
        hf_repo/agents/requirements.txt
    CHANGED
    
    | @@ -12,4 +12,5 @@ jinja2 | |
| 12 | 
             
            python-multipart
         | 
| 13 | 
             
            passlib[bcrypt]
         | 
| 14 | 
             
            werkzeug
         | 
| 15 | 
            -
            itsdangerous
         | 
|  | 
|  | |
| 12 | 
             
            python-multipart
         | 
| 13 | 
             
            passlib[bcrypt]
         | 
| 14 | 
             
            werkzeug
         | 
| 15 | 
            +
            itsdangerous
         | 
| 16 | 
            +
            bleach
         | 
    	
        hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -46,10 +46,10 @@ | |
| 46 | 
             
                            Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
         | 
| 47 | 
             
                        </div>
         | 
| 48 | 
             
                        <div>
         | 
| 49 | 
            -
                            {{ msg.badges }}Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did  | 
| 50 | 
             
                        </div>
         | 
| 51 | 
             
                        <hr>
         | 
| 52 | 
            -
                        <div>{{ msg.text }}</div>
         | 
| 53 | 
             
                    </div>
         | 
| 54 | 
             
                {% endfor %}
         | 
| 55 | 
             
            </body>
         | 
|  | |
| 46 | 
             
                            Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
         | 
| 47 | 
             
                        </div>
         | 
| 48 | 
             
                        <div>
         | 
| 49 | 
            +
                            {% if msg.badges %}{{ msg.badges }}{% endif %}Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did %}({{ msg.user_did }}){% endif %}
         | 
| 50 | 
             
                        </div>
         | 
| 51 | 
             
                        <hr>
         | 
| 52 | 
            +
                        <div>{{ msg.text|safe }}</div>
         | 
| 53 | 
             
                    </div>
         | 
| 54 | 
             
                {% endfor %}
         | 
| 55 | 
             
            </body>
         | 
    	
        hf_repo/hf_repo/hf_repo/agents/tools/storage.py
    CHANGED
    
    | @@ -731,7 +731,7 @@ class Storage: | |
| 731 | 
             
                    else:
         | 
| 732 | 
             
                        # Личные сообщения + публичные от user/llm, которые не скрыты
         | 
| 733 | 
             
                        query = """
         | 
| 734 | 
            -
                            SELECT n.id, n.text, n.source, n.user_did, u.username, n.timestamp, n.hidden
         | 
| 735 | 
             
                            FROM notes n
         | 
| 736 | 
             
                            LEFT JOIN users u ON n.user_did = u.did
         | 
| 737 | 
             
                            WHERE n.user_did = ?
         | 
|  | |
| 731 | 
             
                    else:
         | 
| 732 | 
             
                        # Личные сообщения + публичные от user/llm, которые не скрыты
         | 
| 733 | 
             
                        query = """
         | 
| 734 | 
            +
                            SELECT n.id, n.text, n.source, n.user_did, u.username, u.badges, n.timestamp, n.hidden
         | 
| 735 | 
             
                            FROM notes n
         | 
| 736 | 
             
                            LEFT JOIN users u ON n.user_did = u.did
         | 
| 737 | 
             
                            WHERE n.user_did = ?
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -46,7 +46,7 @@ | |
| 46 | 
             
                            Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
         | 
| 47 | 
             
                        </div>
         | 
| 48 | 
             
                        <div>
         | 
| 49 | 
            -
                            Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did !="" %}({{ msg.user_did }}){% endif %}
         | 
| 50 | 
             
                        </div>
         | 
| 51 | 
             
                        <hr>
         | 
| 52 | 
             
                        <div>{{ msg.text }}</div>
         | 
|  | |
| 46 | 
             
                            Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
         | 
| 47 | 
             
                        </div>
         | 
| 48 | 
             
                        <div>
         | 
| 49 | 
            +
                            {{ msg.badges }}Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did !="" %}({{ msg.user_did }}){% endif %}
         | 
| 50 | 
             
                        </div>
         | 
| 51 | 
             
                        <hr>
         | 
| 52 | 
             
                        <div>{{ msg.text }}</div>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql
    CHANGED
    
    | @@ -199,9 +199,10 @@ CREATE TABLE IF NOT EXISTS users ( | |
| 199 | 
             
              user_id INTEGER PRIMARY KEY AUTOINCREMENT,
         | 
| 200 | 
             
              ban DATETIME DEFAULT NULL,                                    -- если стоит дата/время, то пользователь забанен до этого момента
         | 
| 201 | 
             
              username TEXT,                                                -- имя пользователя (необязательно уникальное)
         | 
| 202 | 
            -
               | 
| 203 | 
            -
               | 
| 204 | 
            -
               | 
|  | |
| 205 | 
             
              info TEXT,                                                    -- произвольная информация, JSON
         | 
| 206 | 
             
              profile TEXT,                                                 -- структурированая информация, JSON
         | 
| 207 | 
             
              contacts TEXT,                                                -- JSON-массив альтернативных контактов (matrix, telegram и т.д.)
         | 
|  | |
| 199 | 
             
              user_id INTEGER PRIMARY KEY AUTOINCREMENT,
         | 
| 200 | 
             
              ban DATETIME DEFAULT NULL,                                    -- если стоит дата/время, то пользователь забанен до этого момента
         | 
| 201 | 
             
              username TEXT,                                                -- имя пользователя (необязательно уникальное)
         | 
| 202 | 
            +
              badges TEXT,                                                  -- значки, присвоенные агентом (например, "🎓💬")
         | 
| 203 | 
            +
              did TEXT  UNIQUE NOT NULL,                                    -- децентрализованный идентификатор
         | 
| 204 | 
            +
              mail TEXT UNIQUE NOT NULL,                                    -- электронная почта
         | 
| 205 | 
            +
              password_hash TEXT NOT NULL,                                  -- хэш пароля
         | 
| 206 | 
             
              info TEXT,                                                    -- произвольная информация, JSON
         | 
| 207 | 
             
              profile TEXT,                                                 -- структурированая информация, JSON
         | 
| 208 | 
             
              contacts TEXT,                                                -- JSON-массив альтернативных контактов (matrix, telegram и т.д.)
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 | 
             
            # agents/notebook/views.py
         | 
| 2 |  | 
| 3 | 
             
            from fastapi import APIRouter, Request, Form
         | 
| 4 | 
            -
            from fastapi.responses import RedirectResponse
         | 
| 5 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| 6 | 
             
            from starlette.status import HTTP_303_SEE_OTHER
         | 
| 7 | 
             
            from tools.storage import Storage
         | 
| @@ -66,6 +66,10 @@ def post_message( | |
| 66 | 
             
                did = request.session.get("did", "anon")
         | 
| 67 | 
             
                is_hidden = 1 if hidden.lower() == "true" else 0
         | 
| 68 |  | 
|  | |
|  | |
|  | |
|  | |
| 69 | 
             
                if text.strip():
         | 
| 70 | 
             
                    storage.write_note(
         | 
| 71 | 
             
                        content=text.strip(),
         | 
|  | |
| 1 | 
             
            # agents/notebook/views.py
         | 
| 2 |  | 
| 3 | 
             
            from fastapi import APIRouter, Request, Form
         | 
| 4 | 
            +
            from fastapi.responses import RedirectResponse, HTMLResponse
         | 
| 5 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| 6 | 
             
            from starlette.status import HTTP_303_SEE_OTHER
         | 
| 7 | 
             
            from tools.storage import Storage
         | 
|  | |
| 66 | 
             
                did = request.session.get("did", "anon")
         | 
| 67 | 
             
                is_hidden = 1 if hidden.lower() == "true" else 0
         | 
| 68 |  | 
| 69 | 
            +
                # Проверка на бан
         | 
| 70 | 
            +
                if storage.is_banned(did):
         | 
| 71 | 
            +
                    return HTMLResponse(content="Вы забанены и не можете отправлять сообщения.", status_code=403)
         | 
| 72 | 
            +
             | 
| 73 | 
             
                if text.strip():
         | 
| 74 | 
             
                    storage.write_note(
         | 
| 75 | 
             
                        content=text.strip(),
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py
    CHANGED
    
    | @@ -769,6 +769,18 @@ class Storage: | |
| 769 | 
             
                        return check_password_hash(result["password_hash"], password)
         | 
| 770 | 
             
                    return False
         | 
| 771 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 772 | 
             
                def get_user_info(self, mail: str) -> dict | None:
         | 
| 773 | 
             
                    mail = mail.lower()
         | 
| 774 | 
             
                    cursor = self.conn.cursor()
         | 
|  | |
| 769 | 
             
                        return check_password_hash(result["password_hash"], password)
         | 
| 770 | 
             
                    return False
         | 
| 771 |  | 
| 772 | 
            +
                def is_banned(self, user_did):
         | 
| 773 | 
            +
                    result = self.conn.execute("""
         | 
| 774 | 
            +
                        SELECT ban
         | 
| 775 | 
            +
                        FROM users
         | 
| 776 | 
            +
                        WHERE did = ?
         | 
| 777 | 
            +
                    """, (user_did,)).fetchone()
         | 
| 778 | 
            +
             | 
| 779 | 
            +
                    if result and result["ban"]:
         | 
| 780 | 
            +
                        return datetime.fromisoformat(result["ban"]) > datetime.now(UTC)
         | 
| 781 | 
            +
             | 
| 782 | 
            +
                    return False
         | 
| 783 | 
            +
             | 
| 784 | 
             
                def get_user_info(self, mail: str) -> dict | None:
         | 
| 785 | 
             
                    mail = mail.lower()
         | 
| 786 | 
             
                    cursor = self.conn.cursor()
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -33,7 +33,7 @@ | |
| 33 |  | 
| 34 | 
             
                <div>
         | 
| 35 | 
             
                    <a href="/messages">📢 Все сообщения</a> |
         | 
| 36 | 
            -
                    <a href="/messages?only_personal=true">🙋  | 
| 37 | 
             
                </div>
         | 
| 38 |  | 
| 39 | 
             
                <hr>
         | 
| @@ -41,8 +41,8 @@ | |
| 41 | 
             
                {% for msg in messages %}
         | 
| 42 | 
             
                    <div class="message source-{{ msg.source }}">
         | 
| 43 | 
             
                        <div>
         | 
| 44 | 
            -
                            {% if msg.user_did == request.session['did'] %}<span class="from-self"></span>{% endif %}
         | 
| 45 | 
            -
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 46 | 
             
                            Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
         | 
| 47 | 
             
                        </div>
         | 
| 48 | 
             
                        <div>
         | 
|  | |
| 33 |  | 
| 34 | 
             
                <div>
         | 
| 35 | 
             
                    <a href="/messages">📢 Все сообщения</a> |
         | 
| 36 | 
            +
                    <a href="/messages?only_personal=true">🙋 Личные</a>
         | 
| 37 | 
             
                </div>
         | 
| 38 |  | 
| 39 | 
             
                <hr>
         | 
|  | |
| 41 | 
             
                {% for msg in messages %}
         | 
| 42 | 
             
                    <div class="message source-{{ msg.source }}">
         | 
| 43 | 
             
                        <div>
         | 
| 44 | 
            +
                            {% if msg.user_did == request.session['did'] %}<span class="from-self" title="это ваше сообщение"></span>{% endif %}
         | 
| 45 | 
            +
                            {% if msg.hidden %}<span class="private" title="личное сообщение"></span>{% endif %}
         | 
| 46 | 
             
                            Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
         | 
| 47 | 
             
                        </div>
         | 
| 48 | 
             
                        <div>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -39,13 +39,14 @@ | |
| 39 | 
             
                <hr>
         | 
| 40 |  | 
| 41 | 
             
                {% for msg in messages %}
         | 
| 42 | 
            -
                    <div class="message source-{{ msg.source }} | 
| 43 | 
             
                        <div>
         | 
| 44 | 
            -
                             | 
| 45 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
|  | |
| 46 | 
             
                        </div>
         | 
| 47 | 
             
                        <div>
         | 
| 48 | 
            -
                            Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} ({{ msg.user_did }})
         | 
| 49 | 
             
                        </div>
         | 
| 50 | 
             
                        <hr>
         | 
| 51 | 
             
                        <div>{{ msg.text }}</div>
         | 
|  | |
| 39 | 
             
                <hr>
         | 
| 40 |  | 
| 41 | 
             
                {% for msg in messages %}
         | 
| 42 | 
            +
                    <div class="message source-{{ msg.source }}">
         | 
| 43 | 
             
                        <div>
         | 
| 44 | 
            +
                            {% if msg.user_did == request.session['did'] %}<span class="from-self"></span>{% endif %}
         | 
| 45 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 46 | 
            +
                            Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
         | 
| 47 | 
             
                        </div>
         | 
| 48 | 
             
                        <div>
         | 
| 49 | 
            +
                            Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did !="" %}({{ msg.user_did }}){% endif %}
         | 
| 50 | 
             
                        </div>
         | 
| 51 | 
             
                        <hr>
         | 
| 52 | 
             
                        <div>{{ msg.text }}</div>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -41,11 +41,11 @@ | |
| 41 | 
             
                {% for msg in messages %}
         | 
| 42 | 
             
                    <div class="message source-{{ msg.source }} {% if msg.user_did == request.session['did'] %}from-self{% endif %}">
         | 
| 43 | 
             
                        <div>
         | 
| 44 | 
            -
                            < | 
| 45 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 46 | 
             
                        </div>
         | 
| 47 | 
             
                        <div>
         | 
| 48 | 
            -
                             | 
| 49 | 
             
                        </div>
         | 
| 50 | 
             
                        <hr>
         | 
| 51 | 
             
                        <div>{{ msg.text }}</div>
         | 
|  | |
| 41 | 
             
                {% for msg in messages %}
         | 
| 42 | 
             
                    <div class="message source-{{ msg.source }} {% if msg.user_did == request.session['did'] %}from-self{% endif %}">
         | 
| 43 | 
             
                        <div>
         | 
| 44 | 
            +
                            Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp }}
         | 
| 45 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 46 | 
             
                        </div>
         | 
| 47 | 
             
                        <div>
         | 
| 48 | 
            +
                            Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} ({{ msg.user_did }})
         | 
| 49 | 
             
                        </div>
         | 
| 50 | 
             
                        <hr>
         | 
| 51 | 
             
                        <div>{{ msg.text }}</div>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -45,9 +45,9 @@ | |
| 45 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 46 | 
             
                        </div>
         | 
| 47 | 
             
                        <div>
         | 
| 48 | 
            -
                            участник: {{ msg.user_did[:10] }}...
         | 
| 49 | 
            -
                            {% if msg.username %}({{ msg.username }}){% endif %}
         | 
| 50 | 
             
                        </div>
         | 
|  | |
| 51 | 
             
                        <div>{{ msg.text }}</div>
         | 
| 52 | 
             
                    </div>
         | 
| 53 | 
             
                {% endfor %}
         | 
|  | |
| 45 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 46 | 
             
                        </div>
         | 
| 47 | 
             
                        <div>
         | 
| 48 | 
            +
                            участник: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} ({{ msg.user_did[:10] }})...
         | 
|  | |
| 49 | 
             
                        </div>
         | 
| 50 | 
            +
                        <hr>
         | 
| 51 | 
             
                        <div>{{ msg.text }}</div>
         | 
| 52 | 
             
                    </div>
         | 
| 53 | 
             
                {% endfor %}
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -45,7 +45,7 @@ | |
| 45 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 46 | 
             
                        </div>
         | 
| 47 | 
             
                        <div>
         | 
| 48 | 
            -
                             | 
| 49 | 
             
                            {% if msg.username %}({{ msg.username }}){% endif %}
         | 
| 50 | 
             
                        </div>
         | 
| 51 | 
             
                        <div>{{ msg.text }}</div>
         | 
|  | |
| 45 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 46 | 
             
                        </div>
         | 
| 47 | 
             
                        <div>
         | 
| 48 | 
            +
                            участник: {{ msg.user_did[:10] }}...
         | 
| 49 | 
             
                            {% if msg.username %}({{ msg.username }}){% endif %}
         | 
| 50 | 
             
                        </div>
         | 
| 51 | 
             
                        <div>{{ msg.text }}</div>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py
    CHANGED
    
    | @@ -718,23 +718,25 @@ class Storage: | |
| 718 | 
             
                    cursor = self.conn.cursor()
         | 
| 719 |  | 
| 720 | 
             
                    if only_personal:
         | 
| 721 | 
            -
                        # Только личные сообщения пользователя
         | 
| 722 | 
             
                        query = """
         | 
| 723 | 
            -
                            SELECT id, text, source, user_did, timestamp, hidden
         | 
| 724 | 
            -
                            FROM notes
         | 
| 725 | 
            -
                             | 
| 726 | 
            -
                             | 
|  | |
| 727 | 
             
                            LIMIT ?
         | 
| 728 | 
             
                        """
         | 
| 729 | 
             
                        cursor.execute(query, (user_did, limit))
         | 
| 730 | 
             
                    else:
         | 
| 731 | 
             
                        # Личные сообщения + публичные от user/llm, которые не скрыты
         | 
| 732 | 
             
                        query = """
         | 
| 733 | 
            -
                            SELECT id, text, source, user_did, timestamp, hidden
         | 
| 734 | 
            -
                            FROM notes
         | 
| 735 | 
            -
                             | 
| 736 | 
            -
             | 
| 737 | 
            -
             | 
|  | |
| 738 | 
             
                            LIMIT ?
         | 
| 739 | 
             
                        """
         | 
| 740 | 
             
                        cursor.execute(query, (user_did, limit))
         | 
|  | |
| 718 | 
             
                    cursor = self.conn.cursor()
         | 
| 719 |  | 
| 720 | 
             
                    if only_personal:
         | 
| 721 | 
            +
                        # Только личные (скрытые) сообщения пользователя
         | 
| 722 | 
             
                        query = """
         | 
| 723 | 
            +
                            SELECT n.id, n.text, n.source, n.user_did, u.username, n.timestamp, n.hidden
         | 
| 724 | 
            +
                            FROM notes n
         | 
| 725 | 
            +
                            LEFT JOIN users u ON n.user_did = u.did
         | 
| 726 | 
            +
                            WHERE n.user_did = ? AND n.hidden = 1
         | 
| 727 | 
            +
                            ORDER BY n.timestamp DESC
         | 
| 728 | 
             
                            LIMIT ?
         | 
| 729 | 
             
                        """
         | 
| 730 | 
             
                        cursor.execute(query, (user_did, limit))
         | 
| 731 | 
             
                    else:
         | 
| 732 | 
             
                        # Личные сообщения + публичные от user/llm, которые не скрыты
         | 
| 733 | 
             
                        query = """
         | 
| 734 | 
            +
                            SELECT n.id, n.text, n.source, n.user_did, u.username, n.timestamp, n.hidden
         | 
| 735 | 
            +
                            FROM notes n
         | 
| 736 | 
            +
                            LEFT JOIN users u ON n.user_did = u.did
         | 
| 737 | 
            +
                            WHERE n.user_did = ?
         | 
| 738 | 
            +
                               OR ((n.source = 'user' OR n.source = 'llm') AND n.hidden = 0)
         | 
| 739 | 
            +
                            ORDER BY n.timestamp DESC
         | 
| 740 | 
             
                            LIMIT ?
         | 
| 741 | 
             
                        """
         | 
| 742 | 
             
                        cursor.execute(query, (user_did, limit))
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py
    CHANGED
    
    | @@ -45,14 +45,9 @@ def show_messages(request: Request, only_personal: bool = False): | |
| 45 | 
             
                if not did:
         | 
| 46 | 
             
                    return RedirectResponse("/login", status_code=303)
         | 
| 47 |  | 
| 48 | 
            -
                # Получаем инфу о пользователе, чтобы понять, оператор ли он
         | 
| 49 | 
            -
                user_info = storage.get_user_info_by_did(did)
         | 
| 50 | 
            -
                is_operator = bool(user_info and user_info.get("operator"))
         | 
| 51 | 
            -
             | 
| 52 | 
             
                messages = storage.get_notes(
         | 
| 53 | 
             
                    limit=50,
         | 
| 54 | 
             
                    user_did=did,
         | 
| 55 | 
            -
                    is_operator=is_operator,
         | 
| 56 | 
             
                    only_personal=only_personal
         | 
| 57 | 
             
                )
         | 
| 58 | 
             
                return templates.TemplateResponse("messages.html", {
         | 
|  | |
| 45 | 
             
                if not did:
         | 
| 46 | 
             
                    return RedirectResponse("/login", status_code=303)
         | 
| 47 |  | 
|  | |
|  | |
|  | |
|  | |
| 48 | 
             
                messages = storage.get_notes(
         | 
| 49 | 
             
                    limit=50,
         | 
| 50 | 
             
                    user_did=did,
         | 
|  | |
| 51 | 
             
                    only_personal=only_personal
         | 
| 52 | 
             
                )
         | 
| 53 | 
             
                return templates.TemplateResponse("messages.html", {
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py
    CHANGED
    
    | @@ -714,38 +714,30 @@ class Storage: | |
| 714 | 
             
                    """, (content, user_did, source, timestamp, hidden))
         | 
| 715 | 
             
                    self.conn.commit()
         | 
| 716 |  | 
| 717 | 
            -
                def get_notes(self, limit=50, user_did="anon",  | 
| 718 | 
             
                    cursor = self.conn.cursor()
         | 
| 719 |  | 
| 720 | 
            -
                    if  | 
|  | |
| 721 | 
             
                        query = """
         | 
| 722 | 
             
                            SELECT id, text, source, user_did, timestamp, hidden
         | 
| 723 | 
             
                            FROM notes
         | 
|  | |
| 724 | 
             
                            ORDER BY timestamp DESC
         | 
| 725 | 
             
                            LIMIT ?
         | 
| 726 | 
             
                        """
         | 
| 727 | 
            -
                        cursor.execute(query, (limit | 
| 728 | 
             
                    else:
         | 
| 729 | 
            -
                         | 
| 730 | 
            -
             | 
| 731 | 
            -
                             | 
| 732 | 
            -
             | 
| 733 | 
            -
             | 
| 734 | 
            -
             | 
| 735 | 
            -
             | 
| 736 | 
            -
             | 
| 737 | 
            -
             | 
| 738 | 
            -
             | 
| 739 | 
            -
                        else:
         | 
| 740 | 
            -
                            # Публичные и личные
         | 
| 741 | 
            -
                            query = """
         | 
| 742 | 
            -
                                SELECT id, text, source, user_did, timestamp, hidden
         | 
| 743 | 
            -
                                FROM notes
         | 
| 744 | 
            -
                                WHERE (user_did = ? OR user_did = 'ALL') AND hidden = 0
         | 
| 745 | 
            -
                                ORDER BY timestamp DESC
         | 
| 746 | 
            -
                                LIMIT ?
         | 
| 747 | 
            -
                            """
         | 
| 748 | 
            -
                            cursor.execute(query, (user_did, limit))
         | 
| 749 |  | 
| 750 | 
             
                    return [dict(row) for row in cursor.fetchall()]
         | 
| 751 |  | 
| @@ -790,6 +782,21 @@ class Storage: | |
| 790 | 
             
                        }
         | 
| 791 | 
             
                    return None
         | 
| 792 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 793 | 
             
                # Утилиты
         | 
| 794 |  | 
| 795 | 
             
                def close(self):
         | 
|  | |
| 714 | 
             
                    """, (content, user_did, source, timestamp, hidden))
         | 
| 715 | 
             
                    self.conn.commit()
         | 
| 716 |  | 
| 717 | 
            +
                def get_notes(self, limit=50, user_did="anon", only_personal=False):
         | 
| 718 | 
             
                    cursor = self.conn.cursor()
         | 
| 719 |  | 
| 720 | 
            +
                    if only_personal:
         | 
| 721 | 
            +
                        # Только личные сообщения пользователя
         | 
| 722 | 
             
                        query = """
         | 
| 723 | 
             
                            SELECT id, text, source, user_did, timestamp, hidden
         | 
| 724 | 
             
                            FROM notes
         | 
| 725 | 
            +
                            WHERE user_did = ?
         | 
| 726 | 
             
                            ORDER BY timestamp DESC
         | 
| 727 | 
             
                            LIMIT ?
         | 
| 728 | 
             
                        """
         | 
| 729 | 
            +
                        cursor.execute(query, (user_did, limit))
         | 
| 730 | 
             
                    else:
         | 
| 731 | 
            +
                        # Личные сообщения + публичные от user/llm, которые не скрыты
         | 
| 732 | 
            +
                        query = """
         | 
| 733 | 
            +
                            SELECT id, text, source, user_did, timestamp, hidden
         | 
| 734 | 
            +
                            FROM notes
         | 
| 735 | 
            +
                            WHERE user_did = ?
         | 
| 736 | 
            +
                               OR ((source = 'user' OR source = 'llm') AND hidden = 0)
         | 
| 737 | 
            +
                            ORDER BY timestamp DESC
         | 
| 738 | 
            +
                            LIMIT ?
         | 
| 739 | 
            +
                        """
         | 
| 740 | 
            +
                        cursor.execute(query, (user_did, limit))
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 741 |  | 
| 742 | 
             
                    return [dict(row) for row in cursor.fetchall()]
         | 
| 743 |  | 
|  | |
| 782 | 
             
                        }
         | 
| 783 | 
             
                    return None
         | 
| 784 |  | 
| 785 | 
            +
                def get_user_info_by_did(self, did: str) -> dict | None:
         | 
| 786 | 
            +
                    cursor = self.conn.cursor()
         | 
| 787 | 
            +
                    cursor.execute(
         | 
| 788 | 
            +
                        "SELECT username, mail, operator FROM users WHERE did = ?",
         | 
| 789 | 
            +
                        (did,)
         | 
| 790 | 
            +
                    )
         | 
| 791 | 
            +
                    result = cursor.fetchone()
         | 
| 792 | 
            +
                    if result:
         | 
| 793 | 
            +
                        return {
         | 
| 794 | 
            +
                            "username": result["username"],
         | 
| 795 | 
            +
                            "mail": result["mail"],
         | 
| 796 | 
            +
                            "operator": result["operator"]
         | 
| 797 | 
            +
                        }
         | 
| 798 | 
            +
                    return None
         | 
| 799 | 
            +
             | 
| 800 | 
             
                # Утилиты
         | 
| 801 |  | 
| 802 | 
             
                def close(self):
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
|  | |
|  | |
| 1 | 
             
            from fastapi import APIRouter, Request, Form
         | 
| 2 | 
             
            from fastapi.responses import RedirectResponse
         | 
| 3 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| @@ -43,7 +45,10 @@ def show_messages(request: Request, only_personal: bool = False): | |
| 43 | 
             
                if not did:
         | 
| 44 | 
             
                    return RedirectResponse("/login", status_code=303)
         | 
| 45 |  | 
| 46 | 
            -
                 | 
|  | |
|  | |
|  | |
| 47 | 
             
                messages = storage.get_notes(
         | 
| 48 | 
             
                    limit=50,
         | 
| 49 | 
             
                    user_did=did,
         | 
| @@ -61,17 +66,18 @@ def show_messages(request: Request, only_personal: bool = False): | |
| 61 | 
             
            def post_message(
         | 
| 62 | 
             
                request: Request,
         | 
| 63 | 
             
                text: str = Form(...),
         | 
| 64 | 
            -
                hidden: str = Form(default= | 
| 65 | 
             
            ):
         | 
| 66 | 
             
                did = request.session.get("did", "anon")
         | 
| 67 | 
            -
                is_hidden = 1 if hidden else 0
         | 
| 68 |  | 
| 69 | 
            -
                 | 
| 70 | 
            -
                     | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
|  | |
| 75 | 
             
                return RedirectResponse(url="/messages", status_code=303)
         | 
| 76 |  | 
| 77 | 
             
            @router.get("/login")
         | 
|  | |
| 1 | 
            +
            # agents/notebook/views.py
         | 
| 2 | 
            +
             | 
| 3 | 
             
            from fastapi import APIRouter, Request, Form
         | 
| 4 | 
             
            from fastapi.responses import RedirectResponse
         | 
| 5 | 
             
            from fastapi.templating import Jinja2Templates
         | 
|  | |
| 45 | 
             
                if not did:
         | 
| 46 | 
             
                    return RedirectResponse("/login", status_code=303)
         | 
| 47 |  | 
| 48 | 
            +
                # Получаем инфу о пользователе, чтобы понять, оператор ли он
         | 
| 49 | 
            +
                user_info = storage.get_user_info_by_did(did)
         | 
| 50 | 
            +
                is_operator = bool(user_info and user_info.get("operator"))
         | 
| 51 | 
            +
             | 
| 52 | 
             
                messages = storage.get_notes(
         | 
| 53 | 
             
                    limit=50,
         | 
| 54 | 
             
                    user_did=did,
         | 
|  | |
| 66 | 
             
            def post_message(
         | 
| 67 | 
             
                request: Request,
         | 
| 68 | 
             
                text: str = Form(...),
         | 
| 69 | 
            +
                hidden: str = Form(default="false")
         | 
| 70 | 
             
            ):
         | 
| 71 | 
             
                did = request.session.get("did", "anon")
         | 
| 72 | 
            +
                is_hidden = 1 if hidden.lower() == "true" else 0
         | 
| 73 |  | 
| 74 | 
            +
                if text.strip():
         | 
| 75 | 
            +
                    storage.write_note(
         | 
| 76 | 
            +
                        content=text.strip(),
         | 
| 77 | 
            +
                        user_did=did,
         | 
| 78 | 
            +
                        source="user",
         | 
| 79 | 
            +
                        hidden=is_hidden
         | 
| 80 | 
            +
                    )
         | 
| 81 | 
             
                return RedirectResponse(url="/messages", status_code=303)
         | 
| 82 |  | 
| 83 | 
             
            @router.get("/login")
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/web_ui.py
    CHANGED
    
    | @@ -12,7 +12,6 @@ process_name = os.path.splitext(os.path.basename(__file__))[0] | |
| 12 | 
             
            from fastapi import FastAPI
         | 
| 13 | 
             
            from fastapi.staticfiles import StaticFiles
         | 
| 14 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| 15 | 
            -
            #from agents.notebook.auth import router as auth_router
         | 
| 16 | 
             
            from starlette.middleware.sessions import SessionMiddleware
         | 
| 17 | 
             
            from agents.notebook.views import router as notebook_router
         | 
| 18 | 
             
            from tools.storage import Storage
         | 
| @@ -25,7 +24,6 @@ app.add_middleware(SessionMiddleware, secret_key="очень_секретный_ | |
| 25 | 
             
            app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "notebook/static")), name="static")
         | 
| 26 | 
             
            templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "notebook/templates"))
         | 
| 27 |  | 
| 28 | 
            -
            #app.include_router(auth_router)
         | 
| 29 | 
             
            app.include_router(notebook_router)
         | 
| 30 |  | 
| 31 | 
             
            @app.on_event("startup")
         | 
|  | |
| 12 | 
             
            from fastapi import FastAPI
         | 
| 13 | 
             
            from fastapi.staticfiles import StaticFiles
         | 
| 14 | 
             
            from fastapi.templating import Jinja2Templates
         | 
|  | |
| 15 | 
             
            from starlette.middleware.sessions import SessionMiddleware
         | 
| 16 | 
             
            from agents.notebook.views import router as notebook_router
         | 
| 17 | 
             
            from tools.storage import Storage
         | 
|  | |
| 24 | 
             
            app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "notebook/static")), name="static")
         | 
| 25 | 
             
            templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "notebook/templates"))
         | 
| 26 |  | 
|  | |
| 27 | 
             
            app.include_router(notebook_router)
         | 
| 28 |  | 
| 29 | 
             
            @app.on_event("startup")
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html
    CHANGED
    
    | @@ -1,6 +1,14 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
              < | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            {% if error %}
         | 
| 2 | 
            +
              <p style="color:red">{{ error }}</p>
         | 
| 3 | 
            +
            {% endif %}
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            <table>
         | 
| 6 | 
            +
             <caption>Вход</caption>
         | 
| 7 | 
            +
             <form method="post">
         | 
| 8 | 
            +
               <tr><th><label>Email:</th><td><input type="email" name="mail" required></label></td></tr>
         | 
| 9 | 
            +
               <tr><th><label>Пароль:</th><td><input type="password" name="password" required></label></td></tr>
         | 
| 10 | 
            +
               <tr><th colspan="2"><button type="submit">Войти</button></th></tr>
         | 
| 11 | 
            +
             </form>
         | 
| 12 | 
            +
            </table>
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            <hr>Нет учетки: <a href="/register">Зарегистрироваться</a>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -25,10 +25,8 @@ | |
| 25 |  | 
| 26 | 
             
                <form method="post">
         | 
| 27 | 
             
                    <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
         | 
| 28 | 
            -
                    < | 
| 29 | 
            -
             | 
| 30 | 
            -
                    </label><br>
         | 
| 31 | 
            -
                    <button type="submit">Отправить</button>
         | 
| 32 | 
             
                </form>
         | 
| 33 |  | 
| 34 | 
             
                <hr>
         | 
|  | |
| 25 |  | 
| 26 | 
             
                <form method="post">
         | 
| 27 | 
             
                    <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
         | 
| 28 | 
            +
                    <button name="hidden" value="false" type="submit">Отправить</button>
         | 
| 29 | 
            +
                    <button name="hidden" value="true" type="submit">Отправить приватно</button>
         | 
|  | |
|  | |
| 30 | 
             
                </form>
         | 
| 31 |  | 
| 32 | 
             
                <hr>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html
    CHANGED
    
    | @@ -1,7 +1,15 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
              < | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            {% if error %}
         | 
| 2 | 
            +
              <p style="color:red">{{ error }}</p>
         | 
| 3 | 
            +
            {% endif %}
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            <table>
         | 
| 6 | 
            +
             <caption>Регистрация</caption>
         | 
| 7 | 
            +
             <form method="post">
         | 
| 8 | 
            +
               <tr><th><label>Имя:</th><td><input type="text" name="username" required></label></td></tr>
         | 
| 9 | 
            +
               <tr><th><label>Email:</th><td><input type="email" name="mail" required></label></td></tr>
         | 
| 10 | 
            +
               <tr><th><label>Пароль:</th><td><input type="password" name="password" required></label></td></tr>
         | 
| 11 | 
            +
               <tr><th colspan="2"><button type="submit">Зарегистрироваться</button></th></tr>
         | 
| 12 | 
            +
             </form>
         | 
| 13 | 
            +
            </table>
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            <hr>Есть учетка: <a href="/login">Войти</a>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py
    CHANGED
    
    | @@ -7,6 +7,9 @@ import json | |
| 7 | 
             
            import uuid
         | 
| 8 |  | 
| 9 | 
             
            from datetime import datetime, timedelta, UTC
         | 
|  | |
|  | |
|  | |
| 10 |  | 
| 11 | 
             
            SCRIPTS_BASE_PATH = "scripts"
         | 
| 12 |  | 
| @@ -747,21 +750,18 @@ class Storage: | |
| 747 | 
             
                    return [dict(row) for row in cursor.fetchall()]
         | 
| 748 |  | 
| 749 | 
             
                # Пользователи
         | 
| 750 | 
            -
                def _hash_password(self, password: str) -> str:
         | 
| 751 | 
            -
                    return hashlib.sha256(password.encode()).hexdigest()
         | 
| 752 | 
            -
             | 
| 753 | 
             
                def register_user(self, username: str, mail: str, password: str) -> bool:
         | 
| 754 | 
             
                    mail = mail.lower()
         | 
| 755 | 
            -
                    did =  | 
| 756 | 
             
                    try:
         | 
| 757 | 
             
                        self.conn.execute(
         | 
| 758 | 
             
                            "INSERT INTO users (username, mail, password_hash, did) VALUES (?, ?, ?, ?)",
         | 
| 759 | 
            -
                            (username, mail,  | 
| 760 | 
             
                        )
         | 
| 761 | 
             
                        self.conn.commit()
         | 
| 762 | 
             
                        return True
         | 
| 763 | 
             
                    except sqlite3.IntegrityError:
         | 
| 764 | 
            -
                        return False | 
| 765 |  | 
| 766 | 
             
                def authenticate_user(self, mail: str, password: str) -> bool:
         | 
| 767 | 
             
                    mail = mail.lower()
         | 
| @@ -772,7 +772,7 @@ class Storage: | |
| 772 | 
             
                    )
         | 
| 773 | 
             
                    result = cursor.fetchone()
         | 
| 774 | 
             
                    if result:
         | 
| 775 | 
            -
                        return result["password_hash"]  | 
| 776 | 
             
                    return False
         | 
| 777 |  | 
| 778 | 
             
                def get_user_info(self, mail: str) -> dict | None:
         | 
|  | |
| 7 | 
             
            import uuid
         | 
| 8 |  | 
| 9 | 
             
            from datetime import datetime, timedelta, UTC
         | 
| 10 | 
            +
            from werkzeug.security import generate_password_hash, check_password_hash
         | 
| 11 | 
            +
            from tools.identity import generate_did
         | 
| 12 | 
            +
            from tools.crypto import generate_keypair
         | 
| 13 |  | 
| 14 | 
             
            SCRIPTS_BASE_PATH = "scripts"
         | 
| 15 |  | 
|  | |
| 750 | 
             
                    return [dict(row) for row in cursor.fetchall()]
         | 
| 751 |  | 
| 752 | 
             
                # Пользователи
         | 
|  | |
|  | |
|  | |
| 753 | 
             
                def register_user(self, username: str, mail: str, password: str) -> bool:
         | 
| 754 | 
             
                    mail = mail.lower()
         | 
| 755 | 
            +
                    did = generate_did()
         | 
| 756 | 
             
                    try:
         | 
| 757 | 
             
                        self.conn.execute(
         | 
| 758 | 
             
                            "INSERT INTO users (username, mail, password_hash, did) VALUES (?, ?, ?, ?)",
         | 
| 759 | 
            +
                            (username, mail, generate_password_hash(password), did)
         | 
| 760 | 
             
                        )
         | 
| 761 | 
             
                        self.conn.commit()
         | 
| 762 | 
             
                        return True
         | 
| 763 | 
             
                    except sqlite3.IntegrityError:
         | 
| 764 | 
            +
                        return False
         | 
| 765 |  | 
| 766 | 
             
                def authenticate_user(self, mail: str, password: str) -> bool:
         | 
| 767 | 
             
                    mail = mail.lower()
         | 
|  | |
| 772 | 
             
                    )
         | 
| 773 | 
             
                    result = cursor.fetchone()
         | 
| 774 | 
             
                    if result:
         | 
| 775 | 
            +
                        return check_password_hash(result["password_hash"], password)
         | 
| 776 | 
             
                    return False
         | 
| 777 |  | 
| 778 | 
             
                def get_user_info(self, mail: str) -> dict | None:
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml
    CHANGED
    
    | @@ -1,44 +1,69 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 4 | 
             
            api_port: 8080
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
              password: password
         | 
| 11 | 
            -
              username: user
         | 
| 12 | 
            -
            dht_enabled: true
         | 
| 13 | 
             
            dht_port: 20784
         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
             
            llm_backends:
         | 
| 18 | 
            -
            -  | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
               | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
              name: openai-gpt4o
         | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 43 | 
             
            ui_port: 8765
         | 
| 44 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # HMP Agent Configuration
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # === Общие параметры ===
         | 
| 4 | 
            +
            agent_id: ""                      # Оставьте пустым для генерации DiD автоматически
         | 
| 5 | 
            +
            agent_name: "CognitiveCore"       # Имя агента
         | 
| 6 | 
            +
            agent_role: "core"                # 'core' или 'shell'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            # === Прокси ===
         | 
| 9 | 
            +
            proxy_mode: false                 # false — прокси не используется, иначе true
         | 
| 10 | 
            +
            proxy_type: "socks5"              # 'http', 'socks4', 'socks5' и т.д. (если proxy_mode: true)
         | 
| 11 | 
            +
            proxy_address: "127.0.0.1:9050"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            # === Функции ядра ===
         | 
| 14 | 
            +
            enable_llm: true                  # доступ к LLM
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            serve_api: true                   # REST API
         | 
| 17 | 
             
            api_port: 8080
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            # === DHT-сеть и обмен знаниями ===
         | 
| 20 | 
            +
            dht_enabled: true                 # Включение участия в DHT-сети (включено принудительно!)
         | 
| 21 | 
            +
            dht_update: true                  # Регулярные обновления и публикация данных в DHT (включено принудительно!)
         | 
| 22 | 
            +
            bootstrap_responder: true         # Агент отвечает на bootstrap-запросы (включено принудительно!)
         | 
|  | |
|  | |
|  | |
| 23 | 
             
            dht_port: 20784
         | 
| 24 | 
            +
            update_interval: 60               # секунд (для DHT-обновлений)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            # === LLM-бэкенды ===
         | 
| 27 | 
             
            llm_backends:
         | 
| 28 | 
            +
              - name: "local-model"
         | 
| 29 | 
            +
                type: "local"
         | 
| 30 | 
            +
                path: "/models/gguf/mistral.gguf"
         | 
| 31 | 
            +
                format: "gguf"
         | 
| 32 | 
            +
                prompt_template: "mistral"
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              - name: "lmstudio-local"
         | 
| 35 | 
            +
                type: "api"
         | 
| 36 | 
            +
                provider: "openai-compatible"
         | 
| 37 | 
            +
                model: "mistral"               # или то, что LM Studio показывает как модель
         | 
| 38 | 
            +
                api_key: "lm-studio-any-key"  # может быть заглушкой
         | 
| 39 | 
            +
                base_url: "http://127.0.0.1:1234/v1"
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              - name: "openai-gpt4o"
         | 
| 42 | 
            +
                type: "api"
         | 
| 43 | 
            +
                provider: "openai"
         | 
| 44 | 
            +
                model: "gpt-4o"
         | 
| 45 | 
            +
                api_key: "sk-..."
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              # Пользователь может добавить сколько угодно дополнительных локальных или сетевых LLM
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            default_llm: "local-model"        # если модели нет в списке `llm_backends` используется первая в списке
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            # === Веб-интерфейс ===
         | 
| 52 | 
            +
            notebook_ui: true                 # UI в виде блокнота
         | 
| 53 | 
            +
            # ui_hosts:
         | 
| 54 | 
            +
            #   - "0.0.0.0"   # (небезопасно) доступ с любых IPv4-адресов
         | 
| 55 | 
            +
            #   - "::"        # (небезопасно) доступ с любых IPv6-адресов
         | 
| 56 | 
            +
            ui_hosts:                         # Какие IP прослушиваются, ["0.0.0.0"; "::"] - доступен везде
         | 
| 57 | 
            +
              - "127.0.0.1"
         | 
| 58 | 
            +
              - "::1"
         | 
| 59 | 
             
            ui_port: 8765
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            # === Данные пользователя ===
         | 
| 62 | 
            +
            default_user:
         | 
| 63 | 
            +
              username: "user"
         | 
| 64 | 
            +
              email: "[email protected]"
         | 
| 65 | 
            +
              password: "password"            # пусто при инициализации, будет установлен при регистрации
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            # === Отладка и логгирование ===
         | 
| 68 | 
            +
            debug: true
         | 
| 69 | 
            +
            log_level: "INFO"                 # DEBUG, INFO, WARNING, ERROR
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html
    CHANGED
    
    | @@ -3,3 +3,4 @@ | |
| 3 | 
             
              <label>Пароль: <input type="password" name="password" required></label><br>
         | 
| 4 | 
             
              <button type="submit">Войти</button>
         | 
| 5 | 
             
            </form>
         | 
|  | 
|  | |
| 3 | 
             
              <label>Пароль: <input type="password" name="password" required></label><br>
         | 
| 4 | 
             
              <button type="submit">Войти</button>
         | 
| 5 | 
             
            </form>
         | 
| 6 | 
            +
            Нет учетки: <a href="/register">зарегистрироваться</a>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html
    CHANGED
    
    | @@ -4,3 +4,4 @@ | |
| 4 | 
             
              <label>Пароль: <input type="password" name="password" required></label><br>
         | 
| 5 | 
             
              <button type="submit">Зарегистрироваться</button>
         | 
| 6 | 
             
            </form>
         | 
|  | 
|  | |
| 4 | 
             
              <label>Пароль: <input type="password" name="password" required></label><br>
         | 
| 5 | 
             
              <button type="submit">Зарегистрироваться</button>
         | 
| 6 | 
             
            </form>
         | 
| 7 | 
            +
            Есть учетка: <a href="/login">войти</a>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml
    CHANGED
    
    | @@ -1,69 +1,44 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
            agent_id: ""                      # Оставьте пустым для генерации DiD автоматически
         | 
| 5 | 
            -
            agent_name: "CognitiveCore"       # Имя агента
         | 
| 6 | 
            -
            agent_role: "core"                # 'core' или 'shell'
         | 
| 7 | 
            -
             | 
| 8 | 
            -
            # === Прокси ===
         | 
| 9 | 
            -
            proxy_mode: false                 # false — прокси не используется, иначе true
         | 
| 10 | 
            -
            proxy_type: "socks5"              # 'http', 'socks4', 'socks5' и т.д. (если proxy_mode: true)
         | 
| 11 | 
            -
            proxy_address: "127.0.0.1:9050"
         | 
| 12 | 
            -
             | 
| 13 | 
            -
            # === Функции ядра ===
         | 
| 14 | 
            -
            enable_llm: true                  # доступ к LLM
         | 
| 15 | 
            -
             | 
| 16 | 
            -
            serve_api: true                   # REST API
         | 
| 17 | 
             
            api_port: 8080
         | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
|  | |
|  | |
|  | |
| 23 | 
             
            dht_port: 20784
         | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
             
            llm_backends:
         | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
               | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
               | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
            # ui_hosts:
         | 
| 54 | 
            -
            #   - "0.0.0.0"   # (небезопасно) доступ с любых IPv4-адресов
         | 
| 55 | 
            -
            #   - "::"        # (небезопасно) доступ с любых IPv6-адресов
         | 
| 56 | 
            -
            ui_hosts:                         # Какие IP прослушиваются, ["0.0.0.0"; "::"] - доступен везде
         | 
| 57 | 
            -
              - "127.0.0.1"
         | 
| 58 | 
            -
              - "::1"
         | 
| 59 | 
             
            ui_port: 8765
         | 
| 60 | 
            -
             | 
| 61 | 
            -
            # === Данные пользователя ===
         | 
| 62 | 
            -
            default_user:
         | 
| 63 | 
            -
              username: "user"
         | 
| 64 | 
            -
              email: "[email protected]"
         | 
| 65 | 
            -
              password: "password"            # пусто при инициализации, будет установлен при регистрации
         | 
| 66 | 
            -
             | 
| 67 | 
            -
            # === Отладка и логгирование ===
         | 
| 68 | 
            -
            debug: true
         | 
| 69 | 
            -
            log_level: "INFO"                 # DEBUG, INFO, WARNING, ERROR
         | 
|  | |
| 1 | 
            +
            agent_id: did:hmp:dac57687-1839-423d-8624-c38324de2635
         | 
| 2 | 
            +
            agent_name: CognitiveCore
         | 
| 3 | 
            +
            agent_role: core
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 4 | 
             
            api_port: 8080
         | 
| 5 | 
            +
            bootstrap_responder: true
         | 
| 6 | 
            +
            debug: true
         | 
| 7 | 
            +
            default_llm: local-model
         | 
| 8 | 
            +
            default_user:
         | 
| 9 | 
            +
              email: [email protected]
         | 
| 10 | 
            +
              password: password
         | 
| 11 | 
            +
              username: user
         | 
| 12 | 
            +
            dht_enabled: true
         | 
| 13 | 
             
            dht_port: 20784
         | 
| 14 | 
            +
            dht_update: true
         | 
| 15 | 
            +
            enable_llm: true
         | 
| 16 | 
            +
            identity_agent: dac57687-1839-423d-8624-c38324de2635
         | 
| 17 | 
             
            llm_backends:
         | 
| 18 | 
            +
            - format: gguf
         | 
| 19 | 
            +
              name: local-model
         | 
| 20 | 
            +
              path: /models/gguf/mistral.gguf
         | 
| 21 | 
            +
              prompt_template: mistral
         | 
| 22 | 
            +
              type: local
         | 
| 23 | 
            +
            - api_key: lm-studio-any-key
         | 
| 24 | 
            +
              base_url: http://127.0.0.1:1234/v1
         | 
| 25 | 
            +
              model: mistral
         | 
| 26 | 
            +
              name: lmstudio-local
         | 
| 27 | 
            +
              provider: openai-compatible
         | 
| 28 | 
            +
              type: api
         | 
| 29 | 
            +
            - api_key: sk-...
         | 
| 30 | 
            +
              model: gpt-4o
         | 
| 31 | 
            +
              name: openai-gpt4o
         | 
| 32 | 
            +
              provider: openai
         | 
| 33 | 
            +
              type: api
         | 
| 34 | 
            +
            log_level: INFO
         | 
| 35 | 
            +
            notebook_ui: true
         | 
| 36 | 
            +
            proxy_address: 127.0.0.1:9050
         | 
| 37 | 
            +
            proxy_mode: false
         | 
| 38 | 
            +
            proxy_type: socks5
         | 
| 39 | 
            +
            serve_api: true
         | 
| 40 | 
            +
            ui_hosts:
         | 
| 41 | 
            +
            - 127.0.0.1
         | 
| 42 | 
            +
            - ::1
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 43 | 
             
            ui_port: 8765
         | 
| 44 | 
            +
            update_interval: 60
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html
    CHANGED
    
    | @@ -1,14 +1,5 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            < | 
| 3 | 
            -
            < | 
| 4 | 
            -
            < | 
| 5 | 
            -
             | 
| 6 | 
            -
              {% if error %}<p style="color: red">{{ error }}</p>{% endif %}
         | 
| 7 | 
            -
              <form method="post">
         | 
| 8 | 
            -
                <input name="username" placeholder="Имя пользователя">
         | 
| 9 | 
            -
                <input name="password" type="password" placeholder="Пароль">
         | 
| 10 | 
            -
                <button type="submit">Войти</button>
         | 
| 11 | 
            -
              </form>
         | 
| 12 | 
            -
              <p>Нет аккаунта? <a href="/register">Регистрация</a></p>
         | 
| 13 | 
            -
            </body>
         | 
| 14 | 
            -
            </html>
         | 
|  | |
| 1 | 
            +
            <form method="post">
         | 
| 2 | 
            +
              <label>Email: <input type="email" name="mail" required></label><br>
         | 
| 3 | 
            +
              <label>Пароль: <input type="password" name="password" required></label><br>
         | 
| 4 | 
            +
              <button type="submit">Войти</button>
         | 
| 5 | 
            +
            </form>
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -20,11 +20,14 @@ | |
| 20 | 
             
                        <a href="/login">Войти</a> | <a href="/register">Регистрация</a>
         | 
| 21 | 
             
                    {% endif %}
         | 
| 22 | 
             
                </div>
         | 
|  | |
| 23 | 
             
                <h1>Сообщения</h1>
         | 
| 24 |  | 
| 25 | 
             
                <form method="post">
         | 
| 26 | 
             
                    <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
         | 
| 27 | 
            -
                    < | 
|  | |
|  | |
| 28 | 
             
                    <button type="submit">Отправить</button>
         | 
| 29 | 
             
                </form>
         | 
| 30 |  | 
| @@ -38,11 +41,15 @@ | |
| 38 | 
             
                <hr>
         | 
| 39 |  | 
| 40 | 
             
                {% for msg in messages %}
         | 
| 41 | 
            -
                    <div class="message source-{{ msg.source }} {% if msg.user_did == 'did | 
| 42 | 
             
                        <div>
         | 
| 43 | 
             
                            <strong>{{ msg.source }}</strong> — {{ msg.timestamp }}
         | 
| 44 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 45 | 
             
                        </div>
         | 
|  | |
|  | |
|  | |
|  | |
| 46 | 
             
                        <div>{{ msg.text }}</div>
         | 
| 47 | 
             
                    </div>
         | 
| 48 | 
             
                {% endfor %}
         | 
|  | |
| 20 | 
             
                        <a href="/login">Войти</a> | <a href="/register">Регистрация</a>
         | 
| 21 | 
             
                    {% endif %}
         | 
| 22 | 
             
                </div>
         | 
| 23 | 
            +
             | 
| 24 | 
             
                <h1>Сообщения</h1>
         | 
| 25 |  | 
| 26 | 
             
                <form method="post">
         | 
| 27 | 
             
                    <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
         | 
| 28 | 
            +
                    <label>
         | 
| 29 | 
            +
                        <input type="checkbox" name="hidden"> Скрыто
         | 
| 30 | 
            +
                    </label><br>
         | 
| 31 | 
             
                    <button type="submit">Отправить</button>
         | 
| 32 | 
             
                </form>
         | 
| 33 |  | 
|  | |
| 41 | 
             
                <hr>
         | 
| 42 |  | 
| 43 | 
             
                {% for msg in messages %}
         | 
| 44 | 
            +
                    <div class="message source-{{ msg.source }} {% if msg.user_did == request.session['did'] %}from-self{% endif %}">
         | 
| 45 | 
             
                        <div>
         | 
| 46 | 
             
                            <strong>{{ msg.source }}</strong> — {{ msg.timestamp }}
         | 
| 47 | 
             
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 48 | 
             
                        </div>
         | 
| 49 | 
            +
                        <div>
         | 
| 50 | 
            +
                            от {{ msg.user_did[:10] }}...
         | 
| 51 | 
            +
                            {% if msg.username %}({{ msg.username }}){% endif %}
         | 
| 52 | 
            +
                        </div>
         | 
| 53 | 
             
                        <div>{{ msg.text }}</div>
         | 
| 54 | 
             
                    </div>
         | 
| 55 | 
             
                {% endfor %}
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html
    CHANGED
    
    | @@ -1,14 +1,6 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            < | 
| 3 | 
            -
            < | 
| 4 | 
            -
            < | 
| 5 | 
            -
              < | 
| 6 | 
            -
             | 
| 7 | 
            -
              <form method="post">
         | 
| 8 | 
            -
                <input name="username" placeholder="Имя пользователя">
         | 
| 9 | 
            -
                <input name="password" type="password" placeholder="Пароль">
         | 
| 10 | 
            -
                <button type="submit">Зарегистрироваться</button>
         | 
| 11 | 
            -
              </form>
         | 
| 12 | 
            -
              <p>Уже есть аккаунт? <a href="/login">Войти</a></p>
         | 
| 13 | 
            -
            </body>
         | 
| 14 | 
            -
            </html>
         | 
|  | |
| 1 | 
            +
            <form method="post">
         | 
| 2 | 
            +
              <label>Имя пользователя: <input type="text" name="username" required></label><br>
         | 
| 3 | 
            +
              <label>Email: <input type="email" name="mail" required></label><br>
         | 
| 4 | 
            +
              <label>Пароль: <input type="password" name="password" required></label><br>
         | 
| 5 | 
            +
              <button type="submit">Зарегистрироваться</button>
         | 
| 6 | 
            +
            </form>
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py
    CHANGED
    
    | @@ -1,14 +1,8 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
            from fastapi import APIRouter, Request, Form, Depends
         | 
| 4 | 
             
            from fastapi.responses import RedirectResponse
         | 
| 5 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| 6 | 
            -
            from fastapi.exceptions import HTTPException
         | 
| 7 | 
            -
            from starlette.middleware.sessions import SessionMiddleware
         | 
| 8 | 
             
            from starlette.status import HTTP_303_SEE_OTHER
         | 
| 9 | 
             
            from tools.storage import Storage
         | 
| 10 | 
            -
            from passlib.hash import bcrypt
         | 
| 11 | 
            -
            from fastapi import FastAPI
         | 
| 12 |  | 
| 13 | 
             
            router = APIRouter()
         | 
| 14 | 
             
            templates = Jinja2Templates(directory="notebook/templates")
         | 
| @@ -16,13 +10,14 @@ storage = Storage() | |
| 16 |  | 
| 17 | 
             
            @router.get("/chat")
         | 
| 18 | 
             
            def chat_page(request: Request):
         | 
| 19 | 
            -
                 | 
| 20 | 
            -
                 | 
|  | |
| 21 | 
             
                    return RedirectResponse("/login", status_code=303)
         | 
| 22 |  | 
| 23 | 
             
                notes = storage.fetchall(
         | 
| 24 | 
             
                    "SELECT text, timestamp, source FROM notes WHERE hidden=0 AND user_did=? ORDER BY timestamp DESC LIMIT 20",
         | 
| 25 | 
            -
                    ( | 
| 26 | 
             
                )
         | 
| 27 | 
             
                return templates.TemplateResponse("chat.html", {
         | 
| 28 | 
             
                    "request": request,
         | 
| @@ -32,24 +27,26 @@ def chat_page(request: Request): | |
| 32 |  | 
| 33 | 
             
            @router.post("/chat")
         | 
| 34 | 
             
            def submit_note(request: Request, message: str = Form(...)):
         | 
| 35 | 
            -
                 | 
| 36 | 
             
                if message.strip():
         | 
| 37 | 
            -
                    storage. | 
| 38 | 
            -
                         | 
| 39 | 
            -
                         | 
|  | |
| 40 | 
             
                    )
         | 
| 41 | 
             
                return RedirectResponse(url="/chat", status_code=303)
         | 
| 42 |  | 
| 43 | 
             
            @router.get("/messages")
         | 
| 44 | 
             
            def show_messages(request: Request, only_personal: bool = False):
         | 
| 45 | 
            -
                 | 
| 46 | 
            -
                 | 
|  | |
| 47 | 
             
                    return RedirectResponse("/login", status_code=303)
         | 
| 48 |  | 
| 49 | 
             
                is_operator = False  # Пока не реализовано
         | 
| 50 | 
             
                messages = storage.get_notes(
         | 
| 51 | 
             
                    limit=50,
         | 
| 52 | 
            -
                    user_did= | 
| 53 | 
             
                    is_operator=is_operator,
         | 
| 54 | 
             
                    only_personal=only_personal
         | 
| 55 | 
             
                )
         | 
| @@ -57,21 +54,21 @@ def show_messages(request: Request, only_personal: bool = False): | |
| 57 | 
             
                    "request": request,
         | 
| 58 | 
             
                    "messages": messages,
         | 
| 59 | 
             
                    "only_personal": only_personal,
         | 
| 60 | 
            -
                    "username": username | 
| 61 | 
             
                })
         | 
| 62 |  | 
| 63 | 
             
            @router.post("/messages")
         | 
| 64 | 
             
            def post_message(
         | 
| 65 | 
             
                request: Request,
         | 
| 66 | 
             
                text: str = Form(...),
         | 
| 67 | 
            -
                user_did: str = Form(default="anon"),
         | 
| 68 | 
             
                hidden: str = Form(default=None)
         | 
| 69 | 
             
            ):
         | 
|  | |
| 70 | 
             
                is_hidden = 1 if hidden else 0
         | 
| 71 |  | 
| 72 | 
             
                storage.write_note(
         | 
| 73 | 
             
                    content=text,
         | 
| 74 | 
            -
                    user_did= | 
| 75 | 
             
                    source="user",
         | 
| 76 | 
             
                    hidden=is_hidden
         | 
| 77 | 
             
                )
         | 
| @@ -82,13 +79,15 @@ def login_page(request: Request): | |
| 82 | 
             
                return templates.TemplateResponse("login.html", {"request": request})
         | 
| 83 |  | 
| 84 | 
             
            @router.post("/login")
         | 
| 85 | 
            -
            def login_user(request: Request,  | 
| 86 | 
            -
                if storage.authenticate_user( | 
| 87 | 
            -
                     | 
| 88 | 
            -
                     | 
|  | |
|  | |
| 89 | 
             
                return templates.TemplateResponse("login.html", {
         | 
| 90 | 
             
                    "request": request,
         | 
| 91 | 
            -
                    "error": "Неверный  | 
| 92 | 
             
                })
         | 
| 93 |  | 
| 94 | 
             
            @router.get("/register")
         | 
| @@ -96,13 +95,20 @@ def register_page(request: Request): | |
| 96 | 
             
                return templates.TemplateResponse("register.html", {"request": request})
         | 
| 97 |  | 
| 98 | 
             
            @router.post("/register")
         | 
| 99 | 
            -
            def register_user( | 
| 100 | 
            -
                 | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 103 | 
             
                return templates.TemplateResponse("register.html", {
         | 
| 104 | 
             
                    "request": request,
         | 
| 105 | 
            -
                    "error": "Пользователь уже существует"
         | 
| 106 | 
             
                })
         | 
| 107 |  | 
| 108 | 
             
            @router.get("/logout")
         | 
|  | |
| 1 | 
            +
            from fastapi import APIRouter, Request, Form
         | 
|  | |
|  | |
| 2 | 
             
            from fastapi.responses import RedirectResponse
         | 
| 3 | 
             
            from fastapi.templating import Jinja2Templates
         | 
|  | |
|  | |
| 4 | 
             
            from starlette.status import HTTP_303_SEE_OTHER
         | 
| 5 | 
             
            from tools.storage import Storage
         | 
|  | |
|  | |
| 6 |  | 
| 7 | 
             
            router = APIRouter()
         | 
| 8 | 
             
            templates = Jinja2Templates(directory="notebook/templates")
         | 
|  | |
| 10 |  | 
| 11 | 
             
            @router.get("/chat")
         | 
| 12 | 
             
            def chat_page(request: Request):
         | 
| 13 | 
            +
                did = request.session.get("did")
         | 
| 14 | 
            +
                username = request.session.get("username")
         | 
| 15 | 
            +
                if not did:
         | 
| 16 | 
             
                    return RedirectResponse("/login", status_code=303)
         | 
| 17 |  | 
| 18 | 
             
                notes = storage.fetchall(
         | 
| 19 | 
             
                    "SELECT text, timestamp, source FROM notes WHERE hidden=0 AND user_did=? ORDER BY timestamp DESC LIMIT 20",
         | 
| 20 | 
            +
                    (did,)
         | 
| 21 | 
             
                )
         | 
| 22 | 
             
                return templates.TemplateResponse("chat.html", {
         | 
| 23 | 
             
                    "request": request,
         | 
|  | |
| 27 |  | 
| 28 | 
             
            @router.post("/chat")
         | 
| 29 | 
             
            def submit_note(request: Request, message: str = Form(...)):
         | 
| 30 | 
            +
                did = request.session.get("did", "anon")
         | 
| 31 | 
             
                if message.strip():
         | 
| 32 | 
            +
                    storage.write_note(
         | 
| 33 | 
            +
                        content=message.strip(),
         | 
| 34 | 
            +
                        user_did=did,
         | 
| 35 | 
            +
                        source="user"
         | 
| 36 | 
             
                    )
         | 
| 37 | 
             
                return RedirectResponse(url="/chat", status_code=303)
         | 
| 38 |  | 
| 39 | 
             
            @router.get("/messages")
         | 
| 40 | 
             
            def show_messages(request: Request, only_personal: bool = False):
         | 
| 41 | 
            +
                did = request.session.get("did")
         | 
| 42 | 
            +
                username = request.session.get("username")
         | 
| 43 | 
            +
                if not did:
         | 
| 44 | 
             
                    return RedirectResponse("/login", status_code=303)
         | 
| 45 |  | 
| 46 | 
             
                is_operator = False  # Пока не реализовано
         | 
| 47 | 
             
                messages = storage.get_notes(
         | 
| 48 | 
             
                    limit=50,
         | 
| 49 | 
            +
                    user_did=did,
         | 
| 50 | 
             
                    is_operator=is_operator,
         | 
| 51 | 
             
                    only_personal=only_personal
         | 
| 52 | 
             
                )
         | 
|  | |
| 54 | 
             
                    "request": request,
         | 
| 55 | 
             
                    "messages": messages,
         | 
| 56 | 
             
                    "only_personal": only_personal,
         | 
| 57 | 
            +
                    "username": username
         | 
| 58 | 
             
                })
         | 
| 59 |  | 
| 60 | 
             
            @router.post("/messages")
         | 
| 61 | 
             
            def post_message(
         | 
| 62 | 
             
                request: Request,
         | 
| 63 | 
             
                text: str = Form(...),
         | 
|  | |
| 64 | 
             
                hidden: str = Form(default=None)
         | 
| 65 | 
             
            ):
         | 
| 66 | 
            +
                did = request.session.get("did", "anon")
         | 
| 67 | 
             
                is_hidden = 1 if hidden else 0
         | 
| 68 |  | 
| 69 | 
             
                storage.write_note(
         | 
| 70 | 
             
                    content=text,
         | 
| 71 | 
            +
                    user_did=did,
         | 
| 72 | 
             
                    source="user",
         | 
| 73 | 
             
                    hidden=is_hidden
         | 
| 74 | 
             
                )
         | 
|  | |
| 79 | 
             
                return templates.TemplateResponse("login.html", {"request": request})
         | 
| 80 |  | 
| 81 | 
             
            @router.post("/login")
         | 
| 82 | 
            +
            def login_user(request: Request, mail: str = Form(...), password: str = Form(...)):
         | 
| 83 | 
            +
                if storage.authenticate_user(mail, password):
         | 
| 84 | 
            +
                    user_info = storage.get_user_info(mail)
         | 
| 85 | 
            +
                    request.session["username"] = user_info["username"]
         | 
| 86 | 
            +
                    request.session["did"] = user_info["did"]
         | 
| 87 | 
            +
                    return RedirectResponse("/messages", status_code=HTTP_303_SEE_OTHER)
         | 
| 88 | 
             
                return templates.TemplateResponse("login.html", {
         | 
| 89 | 
             
                    "request": request,
         | 
| 90 | 
            +
                    "error": "Неверный email или пароль"
         | 
| 91 | 
             
                })
         | 
| 92 |  | 
| 93 | 
             
            @router.get("/register")
         | 
|  | |
| 95 | 
             
                return templates.TemplateResponse("register.html", {"request": request})
         | 
| 96 |  | 
| 97 | 
             
            @router.post("/register")
         | 
| 98 | 
            +
            def register_user(
         | 
| 99 | 
            +
                request: Request,
         | 
| 100 | 
            +
                username: str = Form(...),
         | 
| 101 | 
            +
                mail: str = Form(...),
         | 
| 102 | 
            +
                password: str = Form(...)
         | 
| 103 | 
            +
            ):
         | 
| 104 | 
            +
                if storage.register_user(username, mail, password):
         | 
| 105 | 
            +
                    user_info = storage.get_user_info(mail)
         | 
| 106 | 
            +
                    request.session["username"] = user_info["username"]
         | 
| 107 | 
            +
                    request.session["did"] = user_info["did"]
         | 
| 108 | 
            +
                    return RedirectResponse("/messages", status_code=HTTP_303_SEE_OTHER)
         | 
| 109 | 
             
                return templates.TemplateResponse("register.html", {
         | 
| 110 | 
             
                    "request": request,
         | 
| 111 | 
            +
                    "error": "Пользователь с таким email уже существует"
         | 
| 112 | 
             
                })
         | 
| 113 |  | 
| 114 | 
             
            @router.get("/logout")
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py
    CHANGED
    
    | @@ -4,6 +4,7 @@ import hashlib | |
| 4 | 
             
            import sqlite3
         | 
| 5 | 
             
            import os
         | 
| 6 | 
             
            import json
         | 
|  | |
| 7 |  | 
| 8 | 
             
            from datetime import datetime, timedelta, UTC
         | 
| 9 |  | 
| @@ -17,7 +18,6 @@ class Storage: | |
| 17 | 
             
                    self.conn = sqlite3.connect(db_path, check_same_thread=False)
         | 
| 18 | 
             
                    self.conn.row_factory = sqlite3.Row
         | 
| 19 | 
             
                    self._init_db()
         | 
| 20 | 
            -
                    self._init_user_table()
         | 
| 21 |  | 
| 22 | 
             
                def _init_db(self):
         | 
| 23 | 
             
                    # Загружаем и выполняем весь SQL из файла db_structure.sql
         | 
| @@ -750,39 +750,46 @@ class Storage: | |
| 750 | 
             
                def _hash_password(self, password: str) -> str:
         | 
| 751 | 
             
                    return hashlib.sha256(password.encode()).hexdigest()
         | 
| 752 |  | 
| 753 | 
            -
                def  | 
| 754 | 
            -
                     | 
| 755 | 
            -
             | 
| 756 | 
            -
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
         | 
| 757 | 
            -
                            username TEXT UNIQUE NOT NULL,
         | 
| 758 | 
            -
                            password_hash TEXT NOT NULL
         | 
| 759 | 
            -
                        )
         | 
| 760 | 
            -
                    ''')
         | 
| 761 | 
            -
                    self.conn.commit()
         | 
| 762 | 
            -
             | 
| 763 | 
            -
                def register_user(self, username: str, password: str) -> bool:
         | 
| 764 | 
            -
                    self._init_user_table()
         | 
| 765 | 
             
                    try:
         | 
| 766 | 
             
                        self.conn.execute(
         | 
| 767 | 
            -
                            "INSERT INTO users (username, password_hash) VALUES (?, ?)",
         | 
| 768 | 
            -
                            (username, self._hash_password(password))
         | 
| 769 | 
             
                        )
         | 
| 770 | 
             
                        self.conn.commit()
         | 
| 771 | 
             
                        return True
         | 
| 772 | 
             
                    except sqlite3.IntegrityError:
         | 
| 773 | 
            -
                        return False  #  | 
| 774 |  | 
| 775 | 
            -
                def authenticate_user(self,  | 
|  | |
| 776 | 
             
                    cursor = self.conn.cursor()
         | 
| 777 | 
             
                    cursor.execute(
         | 
| 778 | 
            -
                        "SELECT password_hash FROM users WHERE  | 
| 779 | 
            -
                        ( | 
| 780 | 
             
                    )
         | 
| 781 | 
             
                    result = cursor.fetchone()
         | 
| 782 | 
             
                    if result:
         | 
| 783 | 
             
                        return result["password_hash"] == self._hash_password(password)
         | 
| 784 | 
             
                    return False
         | 
| 785 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 786 | 
             
                # Утилиты
         | 
| 787 |  | 
| 788 | 
             
                def close(self):
         | 
|  | |
| 4 | 
             
            import sqlite3
         | 
| 5 | 
             
            import os
         | 
| 6 | 
             
            import json
         | 
| 7 | 
            +
            import uuid
         | 
| 8 |  | 
| 9 | 
             
            from datetime import datetime, timedelta, UTC
         | 
| 10 |  | 
|  | |
| 18 | 
             
                    self.conn = sqlite3.connect(db_path, check_same_thread=False)
         | 
| 19 | 
             
                    self.conn.row_factory = sqlite3.Row
         | 
| 20 | 
             
                    self._init_db()
         | 
|  | |
| 21 |  | 
| 22 | 
             
                def _init_db(self):
         | 
| 23 | 
             
                    # Загружаем и выполняем весь SQL из файла db_structure.sql
         | 
|  | |
| 750 | 
             
                def _hash_password(self, password: str) -> str:
         | 
| 751 | 
             
                    return hashlib.sha256(password.encode()).hexdigest()
         | 
| 752 |  | 
| 753 | 
            +
                def register_user(self, username: str, mail: str, password: str) -> bool:
         | 
| 754 | 
            +
                    mail = mail.lower()
         | 
| 755 | 
            +
                    did = f"did:example:{uuid.uuid4()}"
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 756 | 
             
                    try:
         | 
| 757 | 
             
                        self.conn.execute(
         | 
| 758 | 
            +
                            "INSERT INTO users (username, mail, password_hash, did) VALUES (?, ?, ?, ?)",
         | 
| 759 | 
            +
                            (username, mail, self._hash_password(password), did)
         | 
| 760 | 
             
                        )
         | 
| 761 | 
             
                        self.conn.commit()
         | 
| 762 | 
             
                        return True
         | 
| 763 | 
             
                    except sqlite3.IntegrityError:
         | 
| 764 | 
            +
                        return False  # уже существует (уникальность mail или did)
         | 
| 765 |  | 
| 766 | 
            +
                def authenticate_user(self, mail: str, password: str) -> bool:
         | 
| 767 | 
            +
                    mail = mail.lower()
         | 
| 768 | 
             
                    cursor = self.conn.cursor()
         | 
| 769 | 
             
                    cursor.execute(
         | 
| 770 | 
            +
                        "SELECT password_hash FROM users WHERE mail = ?",
         | 
| 771 | 
            +
                        (mail,)
         | 
| 772 | 
             
                    )
         | 
| 773 | 
             
                    result = cursor.fetchone()
         | 
| 774 | 
             
                    if result:
         | 
| 775 | 
             
                        return result["password_hash"] == self._hash_password(password)
         | 
| 776 | 
             
                    return False
         | 
| 777 |  | 
| 778 | 
            +
                def get_user_info(self, mail: str) -> dict | None:
         | 
| 779 | 
            +
                    mail = mail.lower()
         | 
| 780 | 
            +
                    cursor = self.conn.cursor()
         | 
| 781 | 
            +
                    cursor.execute(
         | 
| 782 | 
            +
                        "SELECT username, did FROM users WHERE mail = ?",
         | 
| 783 | 
            +
                        (mail,)
         | 
| 784 | 
            +
                    )
         | 
| 785 | 
            +
                    result = cursor.fetchone()
         | 
| 786 | 
            +
                    if result:
         | 
| 787 | 
            +
                        return {
         | 
| 788 | 
            +
                            "username": result["username"],
         | 
| 789 | 
            +
                            "did": result["did"]
         | 
| 790 | 
            +
                        }
         | 
| 791 | 
            +
                    return None
         | 
| 792 | 
            +
             | 
| 793 | 
             
                # Утилиты
         | 
| 794 |  | 
| 795 | 
             
                def close(self):
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <html>
         | 
| 3 | 
            +
            <head><title>Вход</title></head>
         | 
| 4 | 
            +
            <body>
         | 
| 5 | 
            +
              <h2>Вход</h2>
         | 
| 6 | 
            +
              {% if error %}<p style="color: red">{{ error }}</p>{% endif %}
         | 
| 7 | 
            +
              <form method="post">
         | 
| 8 | 
            +
                <input name="username" placeholder="Имя пользователя">
         | 
| 9 | 
            +
                <input name="password" type="password" placeholder="Пароль">
         | 
| 10 | 
            +
                <button type="submit">Войти</button>
         | 
| 11 | 
            +
              </form>
         | 
| 12 | 
            +
              <p>Нет аккаунта? <a href="/register">Регистрация</a></p>
         | 
| 13 | 
            +
            </body>
         | 
| 14 | 
            +
            </html>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html
    CHANGED
    
    | @@ -1,18 +1,50 @@ | |
| 1 | 
            -
            <!-- templates/messages.html -->
         | 
| 2 | 
             
            <!DOCTYPE html>
         | 
| 3 | 
             
            <html>
         | 
| 4 | 
             
            <head>
         | 
| 5 | 
            -
                <title | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 6 | 
             
            </head>
         | 
| 7 | 
             
            <body>
         | 
| 8 | 
            -
                < | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
                     | 
| 12 | 
            -
             | 
| 13 | 
            -
                     | 
|  | |
|  | |
| 14 |  | 
|  | |
|  | |
|  | |
| 15 | 
             
                    <button type="submit">Отправить</button>
         | 
| 16 | 
             
                </form>
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 17 | 
             
            </body>
         | 
| 18 | 
             
            </html>
         | 
|  | |
|  | |
| 1 | 
             
            <!DOCTYPE html>
         | 
| 2 | 
             
            <html>
         | 
| 3 | 
             
            <head>
         | 
| 4 | 
            +
                <title>Сообщения</title>
         | 
| 5 | 
            +
                <style>
         | 
| 6 | 
            +
                    .message { padding: 8px; margin: 10px 0; border-radius: 8px; }
         | 
| 7 | 
            +
                    .source-user { background-color: #e0f7fa; }
         | 
| 8 | 
            +
                    .source-cli { background-color: #dcedc8; }
         | 
| 9 | 
            +
                    .source-llm { background-color: #f3e5f5; }
         | 
| 10 | 
            +
                    .source-system { background-color: #fff3e0; }
         | 
| 11 | 
            +
                    .private::after { content: " 🔒"; }
         | 
| 12 | 
            +
                    .from-self::before { content: "🧍 "; }
         | 
| 13 | 
            +
                </style>
         | 
| 14 | 
             
            </head>
         | 
| 15 | 
             
            <body>
         | 
| 16 | 
            +
                <div style="margin-bottom: 10px;">
         | 
| 17 | 
            +
                    {% if username %}
         | 
| 18 | 
            +
                        Привет, {{ username }} | <a href="/logout">Выход</a>
         | 
| 19 | 
            +
                    {% else %}
         | 
| 20 | 
            +
                        <a href="/login">Войти</a> | <a href="/register">Регистрация</a>
         | 
| 21 | 
            +
                    {% endif %}
         | 
| 22 | 
            +
                </div>
         | 
| 23 | 
            +
                <h1>Сообщения</h1>
         | 
| 24 |  | 
| 25 | 
            +
                <form method="post">
         | 
| 26 | 
            +
                    <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
         | 
| 27 | 
            +
                    <input type="text" name="user_did" placeholder="User DID" readonly value="{{ username }}">
         | 
| 28 | 
             
                    <button type="submit">Отправить</button>
         | 
| 29 | 
             
                </form>
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                <hr>
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                <div>
         | 
| 34 | 
            +
                    <a href="/messages">📢 Все сообщения</a> |
         | 
| 35 | 
            +
                    <a href="/messages?only_personal=true">🙋 Только мои</a>
         | 
| 36 | 
            +
                </div>
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                <hr>
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                {% for msg in messages %}
         | 
| 41 | 
            +
                    <div class="message source-{{ msg.source }} {% if msg.user_did == 'did:example:local-user' %}from-self{% endif %}">
         | 
| 42 | 
            +
                        <div>
         | 
| 43 | 
            +
                            <strong>{{ msg.source }}</strong> — {{ msg.timestamp }}
         | 
| 44 | 
            +
                            {% if msg.hidden %}<span class="private"></span>{% endif %}
         | 
| 45 | 
            +
                        </div>
         | 
| 46 | 
            +
                        <div>{{ msg.text }}</div>
         | 
| 47 | 
            +
                    </div>
         | 
| 48 | 
            +
                {% endfor %}
         | 
| 49 | 
             
            </body>
         | 
| 50 | 
             
            </html>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <html>
         | 
| 3 | 
            +
            <head><title>Регистрация</title></head>
         | 
| 4 | 
            +
            <body>
         | 
| 5 | 
            +
              <h2>Регистрация</h2>
         | 
| 6 | 
            +
              {% if error %}<p style="color: red">{{ error }}</p>{% endif %}
         | 
| 7 | 
            +
              <form method="post">
         | 
| 8 | 
            +
                <input name="username" placeholder="Имя пользователя">
         | 
| 9 | 
            +
                <input name="password" type="password" placeholder="Пароль">
         | 
| 10 | 
            +
                <button type="submit">Зарегистрироваться</button>
         | 
| 11 | 
            +
              </form>
         | 
| 12 | 
            +
              <p>Уже есть аккаунт? <a href="/login">Войти</a></p>
         | 
| 13 | 
            +
            </body>
         | 
| 14 | 
            +
            </html>
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py
    CHANGED
    
    | @@ -1,50 +1,111 @@ | |
| 1 | 
             
            # agents/notebook/views.py
         | 
| 2 |  | 
| 3 | 
            -
            from fastapi import APIRouter, Request, Form
         | 
| 4 | 
             
            from fastapi.responses import RedirectResponse
         | 
| 5 | 
             
            from fastapi.templating import Jinja2Templates
         | 
|  | |
|  | |
|  | |
| 6 | 
             
            from tools.storage import Storage
         | 
|  | |
|  | |
| 7 |  | 
| 8 | 
             
            router = APIRouter()
         | 
| 9 | 
             
            templates = Jinja2Templates(directory="notebook/templates")
         | 
| 10 | 
             
            storage = Storage()
         | 
| 11 |  | 
| 12 | 
            -
            DID = "did:example:local-user"  # временно
         | 
| 13 | 
            -
             | 
| 14 | 
             
            @router.get("/chat")
         | 
| 15 | 
             
            def chat_page(request: Request):
         | 
|  | |
|  | |
|  | |
|  | |
| 16 | 
             
                notes = storage.fetchall(
         | 
| 17 | 
             
                    "SELECT text, timestamp, source FROM notes WHERE hidden=0 AND user_did=? ORDER BY timestamp DESC LIMIT 20",
         | 
| 18 | 
            -
                    ( | 
| 19 | 
             
                )
         | 
| 20 | 
            -
                return templates.TemplateResponse("chat.html", { | 
|  | |
|  | |
|  | |
|  | |
| 21 |  | 
| 22 | 
             
            @router.post("/chat")
         | 
| 23 | 
             
            def submit_note(request: Request, message: str = Form(...)):
         | 
|  | |
| 24 | 
             
                if message.strip():
         | 
| 25 | 
             
                    storage.execute(
         | 
| 26 | 
             
                        "INSERT INTO notes (text, source, user_did) VALUES (?, ?, ?)",
         | 
| 27 | 
            -
                        (message.strip(), "user",  | 
| 28 | 
             
                    )
         | 
| 29 | 
             
                return RedirectResponse(url="/chat", status_code=303)
         | 
| 30 |  | 
| 31 | 
             
            @router.get("/messages")
         | 
| 32 | 
            -
            def show_messages(request: Request):
         | 
| 33 | 
            -
                 | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 34 | 
             
                return templates.TemplateResponse("messages.html", {
         | 
| 35 | 
             
                    "request": request,
         | 
| 36 | 
            -
                    "messages": messages
         | 
|  | |
|  | |
| 37 | 
             
                })
         | 
| 38 |  | 
| 39 | 
             
            @router.post("/messages")
         | 
| 40 | 
             
            def post_message(
         | 
| 41 | 
             
                request: Request,
         | 
| 42 | 
             
                text: str = Form(...),
         | 
| 43 | 
            -
                user_did: str = Form(default="anon")
         | 
|  | |
| 44 | 
             
            ):
         | 
|  | |
|  | |
| 45 | 
             
                storage.write_note(
         | 
| 46 | 
             
                    content=text,
         | 
| 47 | 
             
                    user_did=user_did,
         | 
| 48 | 
            -
                    source="user"
         | 
|  | |
| 49 | 
             
                )
         | 
| 50 | 
             
                return RedirectResponse(url="/messages", status_code=303)
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
             
            # agents/notebook/views.py
         | 
| 2 |  | 
| 3 | 
            +
            from fastapi import APIRouter, Request, Form, Depends
         | 
| 4 | 
             
            from fastapi.responses import RedirectResponse
         | 
| 5 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| 6 | 
            +
            from fastapi.exceptions import HTTPException
         | 
| 7 | 
            +
            from starlette.middleware.sessions import SessionMiddleware
         | 
| 8 | 
            +
            from starlette.status import HTTP_303_SEE_OTHER
         | 
| 9 | 
             
            from tools.storage import Storage
         | 
| 10 | 
            +
            from passlib.hash import bcrypt
         | 
| 11 | 
            +
            from fastapi import FastAPI
         | 
| 12 |  | 
| 13 | 
             
            router = APIRouter()
         | 
| 14 | 
             
            templates = Jinja2Templates(directory="notebook/templates")
         | 
| 15 | 
             
            storage = Storage()
         | 
| 16 |  | 
|  | |
|  | |
| 17 | 
             
            @router.get("/chat")
         | 
| 18 | 
             
            def chat_page(request: Request):
         | 
| 19 | 
            +
                username = request.session.get("user")
         | 
| 20 | 
            +
                if not username:
         | 
| 21 | 
            +
                    return RedirectResponse("/login", status_code=303)
         | 
| 22 | 
            +
             | 
| 23 | 
             
                notes = storage.fetchall(
         | 
| 24 | 
             
                    "SELECT text, timestamp, source FROM notes WHERE hidden=0 AND user_did=? ORDER BY timestamp DESC LIMIT 20",
         | 
| 25 | 
            +
                    (username,)
         | 
| 26 | 
             
                )
         | 
| 27 | 
            +
                return templates.TemplateResponse("chat.html", {
         | 
| 28 | 
            +
                    "request": request,
         | 
| 29 | 
            +
                    "notes": notes,
         | 
| 30 | 
            +
                    "username": username
         | 
| 31 | 
            +
                })
         | 
| 32 |  | 
| 33 | 
             
            @router.post("/chat")
         | 
| 34 | 
             
            def submit_note(request: Request, message: str = Form(...)):
         | 
| 35 | 
            +
                username = request.session.get("user", "anon")  # Можно вернуть anon, если не залогинен
         | 
| 36 | 
             
                if message.strip():
         | 
| 37 | 
             
                    storage.execute(
         | 
| 38 | 
             
                        "INSERT INTO notes (text, source, user_did) VALUES (?, ?, ?)",
         | 
| 39 | 
            +
                        (message.strip(), "user", username)
         | 
| 40 | 
             
                    )
         | 
| 41 | 
             
                return RedirectResponse(url="/chat", status_code=303)
         | 
| 42 |  | 
| 43 | 
             
            @router.get("/messages")
         | 
| 44 | 
            +
            def show_messages(request: Request, only_personal: bool = False):
         | 
| 45 | 
            +
                username = request.session.get("user")
         | 
| 46 | 
            +
                if not username:
         | 
| 47 | 
            +
                    return RedirectResponse("/login", status_code=303)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                is_operator = False  # Пока не реализовано
         | 
| 50 | 
            +
                messages = storage.get_notes(
         | 
| 51 | 
            +
                    limit=50,
         | 
| 52 | 
            +
                    user_did=username,
         | 
| 53 | 
            +
                    is_operator=is_operator,
         | 
| 54 | 
            +
                    only_personal=only_personal
         | 
| 55 | 
            +
                )
         | 
| 56 | 
             
                return templates.TemplateResponse("messages.html", {
         | 
| 57 | 
             
                    "request": request,
         | 
| 58 | 
            +
                    "messages": messages,
         | 
| 59 | 
            +
                    "only_personal": only_personal,
         | 
| 60 | 
            +
                    "username": username  # 👈 вот это
         | 
| 61 | 
             
                })
         | 
| 62 |  | 
| 63 | 
             
            @router.post("/messages")
         | 
| 64 | 
             
            def post_message(
         | 
| 65 | 
             
                request: Request,
         | 
| 66 | 
             
                text: str = Form(...),
         | 
| 67 | 
            +
                user_did: str = Form(default="anon"),
         | 
| 68 | 
            +
                hidden: str = Form(default=None)
         | 
| 69 | 
             
            ):
         | 
| 70 | 
            +
                is_hidden = 1 if hidden else 0
         | 
| 71 | 
            +
             | 
| 72 | 
             
                storage.write_note(
         | 
| 73 | 
             
                    content=text,
         | 
| 74 | 
             
                    user_did=user_did,
         | 
| 75 | 
            +
                    source="user",
         | 
| 76 | 
            +
                    hidden=is_hidden
         | 
| 77 | 
             
                )
         | 
| 78 | 
             
                return RedirectResponse(url="/messages", status_code=303)
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            @router.get("/login")
         | 
| 81 | 
            +
            def login_page(request: Request):
         | 
| 82 | 
            +
                return templates.TemplateResponse("login.html", {"request": request})
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            @router.post("/login")
         | 
| 85 | 
            +
            def login_user(request: Request, username: str = Form(...), password: str = Form(...)):
         | 
| 86 | 
            +
                if storage.authenticate_user(username, password):
         | 
| 87 | 
            +
                    request.session["user"] = username
         | 
| 88 | 
            +
                    return RedirectResponse("/chat", status_code=HTTP_303_SEE_OTHER)
         | 
| 89 | 
            +
                return templates.TemplateResponse("login.html", {
         | 
| 90 | 
            +
                    "request": request,
         | 
| 91 | 
            +
                    "error": "Неверный логин или пароль"
         | 
| 92 | 
            +
                })
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            @router.get("/register")
         | 
| 95 | 
            +
            def register_page(request: Request):
         | 
| 96 | 
            +
                return templates.TemplateResponse("register.html", {"request": request})
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            @router.post("/register")
         | 
| 99 | 
            +
            def register_user(request: Request, username: str = Form(...), password: str = Form(...)):
         | 
| 100 | 
            +
                if storage.register_user(username, password):
         | 
| 101 | 
            +
                    request.session["user"] = username
         | 
| 102 | 
            +
                    return RedirectResponse("/chat", status_code=HTTP_303_SEE_OTHER)
         | 
| 103 | 
            +
                return templates.TemplateResponse("register.html", {
         | 
| 104 | 
            +
                    "request": request,
         | 
| 105 | 
            +
                    "error": "Пользователь уже существует"
         | 
| 106 | 
            +
                })
         | 
| 107 | 
            +
             | 
| 108 | 
            +
            @router.get("/logout")
         | 
| 109 | 
            +
            def logout(request: Request):
         | 
| 110 | 
            +
                request.session.clear()
         | 
| 111 | 
            +
                return RedirectResponse("/login", status_code=HTTP_303_SEE_OTHER)
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/requirements.txt
    CHANGED
    
    | @@ -11,4 +11,5 @@ uvicorn | |
| 11 | 
             
            jinja2
         | 
| 12 | 
             
            python-multipart
         | 
| 13 | 
             
            passlib[bcrypt]
         | 
| 14 | 
            -
            werkzeug
         | 
|  | 
|  | |
| 11 | 
             
            jinja2
         | 
| 12 | 
             
            python-multipart
         | 
| 13 | 
             
            passlib[bcrypt]
         | 
| 14 | 
            +
            werkzeug
         | 
| 15 | 
            +
            itsdangerous
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py
    CHANGED
    
    | @@ -1,5 +1,6 @@ | |
| 1 | 
             
            # agents/tools/storage.py
         | 
| 2 |  | 
|  | |
| 3 | 
             
            import sqlite3
         | 
| 4 | 
             
            import os
         | 
| 5 | 
             
            import json
         | 
| @@ -14,7 +15,9 @@ class Storage: | |
| 14 | 
             
                    db_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "agent_data.db"))
         | 
| 15 | 
             
                    self.db_path = db_path
         | 
| 16 | 
             
                    self.conn = sqlite3.connect(db_path, check_same_thread=False)
         | 
|  | |
| 17 | 
             
                    self._init_db()
         | 
|  | |
| 18 |  | 
| 19 | 
             
                def _init_db(self):
         | 
| 20 | 
             
                    # Загружаем и выполняем весь SQL из файла db_structure.sql
         | 
| @@ -700,24 +703,86 @@ class Storage: | |
| 700 | 
             
                    return row[0] if row else default
         | 
| 701 |  | 
| 702 | 
             
                # Web-интерфейс и API
         | 
| 703 | 
            -
                def write_note(self, content, user_did="anon", source="user"):
         | 
| 704 | 
             
                    timestamp = datetime.now(UTC).isoformat()
         | 
| 705 | 
             
                    self.conn.execute("""
         | 
| 706 | 
            -
                        INSERT INTO notes (text, user_did, source, timestamp)
         | 
| 707 | 
            -
                        VALUES (?, ?, ?, ?)
         | 
| 708 | 
            -
                    """, (content, user_did, source, timestamp))
         | 
| 709 | 
             
                    self.conn.commit()
         | 
| 710 |  | 
| 711 | 
            -
                def get_notes(self, limit=50):
         | 
| 712 | 
             
                    cursor = self.conn.cursor()
         | 
| 713 | 
            -
             | 
| 714 | 
            -
             | 
| 715 | 
            -
                         | 
| 716 | 
            -
             | 
| 717 | 
            -
             | 
| 718 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 719 | 
             
                    return [dict(row) for row in cursor.fetchall()]
         | 
| 720 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 721 | 
             
                # Утилиты
         | 
| 722 |  | 
| 723 | 
             
                def close(self):
         | 
|  | |
| 1 | 
             
            # agents/tools/storage.py
         | 
| 2 |  | 
| 3 | 
            +
            import hashlib
         | 
| 4 | 
             
            import sqlite3
         | 
| 5 | 
             
            import os
         | 
| 6 | 
             
            import json
         | 
|  | |
| 15 | 
             
                    db_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "agent_data.db"))
         | 
| 16 | 
             
                    self.db_path = db_path
         | 
| 17 | 
             
                    self.conn = sqlite3.connect(db_path, check_same_thread=False)
         | 
| 18 | 
            +
                    self.conn.row_factory = sqlite3.Row
         | 
| 19 | 
             
                    self._init_db()
         | 
| 20 | 
            +
                    self._init_user_table()
         | 
| 21 |  | 
| 22 | 
             
                def _init_db(self):
         | 
| 23 | 
             
                    # Загружаем и выполняем весь SQL из файла db_structure.sql
         | 
|  | |
| 703 | 
             
                    return row[0] if row else default
         | 
| 704 |  | 
| 705 | 
             
                # Web-интерфейс и API
         | 
| 706 | 
            +
                def write_note(self, content, user_did="anon", source="user", hidden=0):
         | 
| 707 | 
             
                    timestamp = datetime.now(UTC).isoformat()
         | 
| 708 | 
             
                    self.conn.execute("""
         | 
| 709 | 
            +
                        INSERT INTO notes (text, user_did, source, timestamp, hidden)
         | 
| 710 | 
            +
                        VALUES (?, ?, ?, ?, ?)
         | 
| 711 | 
            +
                    """, (content, user_did, source, timestamp, hidden))
         | 
| 712 | 
             
                    self.conn.commit()
         | 
| 713 |  | 
| 714 | 
            +
                def get_notes(self, limit=50, user_did="anon", is_operator=False, only_personal=False):
         | 
| 715 | 
             
                    cursor = self.conn.cursor()
         | 
| 716 | 
            +
             | 
| 717 | 
            +
                    if is_operator:
         | 
| 718 | 
            +
                        query = """
         | 
| 719 | 
            +
                            SELECT id, text, source, user_did, timestamp, hidden
         | 
| 720 | 
            +
                            FROM notes
         | 
| 721 | 
            +
                            ORDER BY timestamp DESC
         | 
| 722 | 
            +
                            LIMIT ?
         | 
| 723 | 
            +
                        """
         | 
| 724 | 
            +
                        cursor.execute(query, (limit,))
         | 
| 725 | 
            +
                    else:
         | 
| 726 | 
            +
                        if only_personal:
         | 
| 727 | 
            +
                            # Только личные сообщения
         | 
| 728 | 
            +
                            query = """
         | 
| 729 | 
            +
                                SELECT id, text, source, user_did, timestamp, hidden
         | 
| 730 | 
            +
                                FROM notes
         | 
| 731 | 
            +
                                WHERE user_did = ? AND hidden = 0
         | 
| 732 | 
            +
                                ORDER BY timestamp DESC
         | 
| 733 | 
            +
                                LIMIT ?
         | 
| 734 | 
            +
                            """
         | 
| 735 | 
            +
                            cursor.execute(query, (user_did, limit))
         | 
| 736 | 
            +
                        else:
         | 
| 737 | 
            +
                            # Публичные и личные
         | 
| 738 | 
            +
                            query = """
         | 
| 739 | 
            +
                                SELECT id, text, source, user_did, timestamp, hidden
         | 
| 740 | 
            +
                                FROM notes
         | 
| 741 | 
            +
                                WHERE (user_did = ? OR user_did = 'ALL') AND hidden = 0
         | 
| 742 | 
            +
                                ORDER BY timestamp DESC
         | 
| 743 | 
            +
                                LIMIT ?
         | 
| 744 | 
            +
                            """
         | 
| 745 | 
            +
                            cursor.execute(query, (user_did, limit))
         | 
| 746 | 
            +
             | 
| 747 | 
             
                    return [dict(row) for row in cursor.fetchall()]
         | 
| 748 |  | 
| 749 | 
            +
                # Пользователи
         | 
| 750 | 
            +
                def _hash_password(self, password: str) -> str:
         | 
| 751 | 
            +
                    return hashlib.sha256(password.encode()).hexdigest()
         | 
| 752 | 
            +
             | 
| 753 | 
            +
                def _init_user_table(self):
         | 
| 754 | 
            +
                    self.conn.execute('''
         | 
| 755 | 
            +
                        CREATE TABLE IF NOT EXISTS users (
         | 
| 756 | 
            +
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
         | 
| 757 | 
            +
                            username TEXT UNIQUE NOT NULL,
         | 
| 758 | 
            +
                            password_hash TEXT NOT NULL
         | 
| 759 | 
            +
                        )
         | 
| 760 | 
            +
                    ''')
         | 
| 761 | 
            +
                    self.conn.commit()
         | 
| 762 | 
            +
             | 
| 763 | 
            +
                def register_user(self, username: str, password: str) -> bool:
         | 
| 764 | 
            +
                    self._init_user_table()
         | 
| 765 | 
            +
                    try:
         | 
| 766 | 
            +
                        self.conn.execute(
         | 
| 767 | 
            +
                            "INSERT INTO users (username, password_hash) VALUES (?, ?)",
         | 
| 768 | 
            +
                            (username, self._hash_password(password))
         | 
| 769 | 
            +
                        )
         | 
| 770 | 
            +
                        self.conn.commit()
         | 
| 771 | 
            +
                        return True
         | 
| 772 | 
            +
                    except sqlite3.IntegrityError:
         | 
| 773 | 
            +
                        return False  # пользователь уже существует
         | 
| 774 | 
            +
             | 
| 775 | 
            +
                def authenticate_user(self, username: str, password: str) -> bool:
         | 
| 776 | 
            +
                    cursor = self.conn.cursor()
         | 
| 777 | 
            +
                    cursor.execute(
         | 
| 778 | 
            +
                        "SELECT password_hash FROM users WHERE username = ?",
         | 
| 779 | 
            +
                        (username,)
         | 
| 780 | 
            +
                    )
         | 
| 781 | 
            +
                    result = cursor.fetchone()
         | 
| 782 | 
            +
                    if result:
         | 
| 783 | 
            +
                        return result["password_hash"] == self._hash_password(password)
         | 
| 784 | 
            +
                    return False
         | 
| 785 | 
            +
             | 
| 786 | 
             
                # Утилиты
         | 
| 787 |  | 
| 788 | 
             
                def close(self):
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/web_ui.py
    CHANGED
    
    | @@ -13,11 +13,14 @@ from fastapi import FastAPI | |
| 13 | 
             
            from fastapi.staticfiles import StaticFiles
         | 
| 14 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| 15 | 
             
            #from agents.notebook.auth import router as auth_router
         | 
|  | |
| 16 | 
             
            from agents.notebook.views import router as notebook_router
         | 
| 17 | 
             
            from tools.storage import Storage
         | 
| 18 |  | 
| 19 | 
             
            storage = Storage()
         | 
| 20 | 
             
            app = FastAPI()
         | 
|  | |
|  | |
| 21 |  | 
| 22 | 
             
            app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "notebook/static")), name="static")
         | 
| 23 | 
             
            templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "notebook/templates"))
         | 
|  | |
| 13 | 
             
            from fastapi.staticfiles import StaticFiles
         | 
| 14 | 
             
            from fastapi.templating import Jinja2Templates
         | 
| 15 | 
             
            #from agents.notebook.auth import router as auth_router
         | 
| 16 | 
            +
            from starlette.middleware.sessions import SessionMiddleware
         | 
| 17 | 
             
            from agents.notebook.views import router as notebook_router
         | 
| 18 | 
             
            from tools.storage import Storage
         | 
| 19 |  | 
| 20 | 
             
            storage = Storage()
         | 
| 21 | 
             
            app = FastAPI()
         | 
| 22 | 
            +
            app.add_middleware(SessionMiddleware, secret_key="очень_секретный_ключ")
         | 
| 23 | 
            +
             | 
| 24 |  | 
| 25 | 
             
            app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "notebook/static")), name="static")
         | 
| 26 | 
             
            templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "notebook/templates"))
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/add_message.py
    CHANGED
    
    | @@ -1,28 +1,24 @@ | |
| 1 | 
             
            # agents/add_message.py
         | 
| 2 |  | 
| 3 | 
             
            import argparse
         | 
| 4 | 
            -
            from datetime import datetime
         | 
| 5 | 
             
            from tools.storage import Storage
         | 
| 6 |  | 
| 7 | 
             
            storage = Storage()
         | 
| 8 |  | 
| 9 | 
            -
            def add_message( | 
| 10 | 
             
                storage.write_note(
         | 
| 11 | 
             
                    content,
         | 
| 12 | 
            -
                    role=role,
         | 
| 13 | 
             
                    source=source,
         | 
| 14 | 
            -
                    user_did=user_did | 
| 15 | 
            -
                    tags=[]
         | 
| 16 | 
             
                )
         | 
| 17 | 
            -
                print(f"[+] Сообщение от { | 
| 18 |  | 
| 19 | 
             
            # --- CLI interface ---
         | 
| 20 | 
             
            if __name__ == "__main__":
         | 
| 21 | 
             
                parser = argparse.ArgumentParser()
         | 
| 22 | 
            -
                parser.add_argument("--role", required=True)
         | 
| 23 | 
             
                parser.add_argument("--content", required=True)
         | 
| 24 | 
             
                parser.add_argument("--source", default="cli")
         | 
| 25 | 
            -
                parser.add_argument("--user_did")
         | 
| 26 | 
             
                args = parser.parse_args()
         | 
| 27 |  | 
| 28 | 
            -
                add_message(args. | 
|  | |
| 1 | 
             
            # agents/add_message.py
         | 
| 2 |  | 
| 3 | 
             
            import argparse
         | 
|  | |
| 4 | 
             
            from tools.storage import Storage
         | 
| 5 |  | 
| 6 | 
             
            storage = Storage()
         | 
| 7 |  | 
| 8 | 
            +
            def add_message(content, source="cli", user_did="anon"):
         | 
| 9 | 
             
                storage.write_note(
         | 
| 10 | 
             
                    content,
         | 
|  | |
| 11 | 
             
                    source=source,
         | 
| 12 | 
            +
                    user_did=user_did
         | 
|  | |
| 13 | 
             
                )
         | 
| 14 | 
            +
                print(f"[+] Сообщение от {source} ({user_did}) добавлено: {content}")
         | 
| 15 |  | 
| 16 | 
             
            # --- CLI interface ---
         | 
| 17 | 
             
            if __name__ == "__main__":
         | 
| 18 | 
             
                parser = argparse.ArgumentParser()
         | 
|  | |
| 19 | 
             
                parser.add_argument("--content", required=True)
         | 
| 20 | 
             
                parser.add_argument("--source", default="cli")
         | 
| 21 | 
            +
                parser.add_argument("--user_did", default="anon")
         | 
| 22 | 
             
                args = parser.parse_args()
         | 
| 23 |  | 
| 24 | 
            +
                add_message(args.content, args.source, args.user_did)
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py
    CHANGED
    
    | @@ -6,7 +6,7 @@ from fastapi.templating import Jinja2Templates | |
| 6 | 
             
            from tools.storage import Storage
         | 
| 7 |  | 
| 8 | 
             
            router = APIRouter()
         | 
| 9 | 
            -
            templates = Jinja2Templates(directory=" | 
| 10 | 
             
            storage = Storage()
         | 
| 11 |  | 
| 12 | 
             
            DID = "did:example:local-user"  # временно
         | 
| @@ -30,7 +30,7 @@ def submit_note(request: Request, message: str = Form(...)): | |
| 30 |  | 
| 31 | 
             
            @router.get("/messages")
         | 
| 32 | 
             
            def show_messages(request: Request):
         | 
| 33 | 
            -
                messages = storage.get_notes(limit=50) | 
| 34 | 
             
                return templates.TemplateResponse("messages.html", {
         | 
| 35 | 
             
                    "request": request,
         | 
| 36 | 
             
                    "messages": messages
         | 
| @@ -40,13 +40,11 @@ def show_messages(request: Request): | |
| 40 | 
             
            def post_message(
         | 
| 41 | 
             
                request: Request,
         | 
| 42 | 
             
                text: str = Form(...),
         | 
| 43 | 
            -
                role: str = Form(default="user"), 
         | 
| 44 | 
             
                user_did: str = Form(default="anon")
         | 
| 45 | 
             
            ):
         | 
| 46 | 
             
                storage.write_note(
         | 
| 47 | 
             
                    content=text,
         | 
| 48 | 
            -
                    role=role,
         | 
| 49 | 
             
                    user_did=user_did,
         | 
| 50 | 
            -
                    source=" | 
| 51 | 
             
                )
         | 
| 52 | 
             
                return RedirectResponse(url="/messages", status_code=303)
         | 
|  | |
| 6 | 
             
            from tools.storage import Storage
         | 
| 7 |  | 
| 8 | 
             
            router = APIRouter()
         | 
| 9 | 
            +
            templates = Jinja2Templates(directory="notebook/templates")
         | 
| 10 | 
             
            storage = Storage()
         | 
| 11 |  | 
| 12 | 
             
            DID = "did:example:local-user"  # временно
         | 
|  | |
| 30 |  | 
| 31 | 
             
            @router.get("/messages")
         | 
| 32 | 
             
            def show_messages(request: Request):
         | 
| 33 | 
            +
                messages = storage.get_notes(limit=50)
         | 
| 34 | 
             
                return templates.TemplateResponse("messages.html", {
         | 
| 35 | 
             
                    "request": request,
         | 
| 36 | 
             
                    "messages": messages
         | 
|  | |
| 40 | 
             
            def post_message(
         | 
| 41 | 
             
                request: Request,
         | 
| 42 | 
             
                text: str = Form(...),
         | 
|  | |
| 43 | 
             
                user_did: str = Form(default="anon")
         | 
| 44 | 
             
            ):
         | 
| 45 | 
             
                storage.write_note(
         | 
| 46 | 
             
                    content=text,
         | 
|  | |
| 47 | 
             
                    user_did=user_did,
         | 
| 48 | 
            +
                    source="user"
         | 
| 49 | 
             
                )
         | 
| 50 | 
             
                return RedirectResponse(url="/messages", status_code=303)
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql
    CHANGED
    
    | @@ -46,7 +46,7 @@ CREATE TABLE IF NOT EXISTS notes ( | |
| 46 | 
             
                text TEXT NOT NULL,                                         -- Текст заметки
         | 
| 47 | 
             
                tags TEXT,                                                  -- Теги (например: "idea", "instruction")
         | 
| 48 | 
             
                user_did TEXT DEFAULT 'ALL',                                -- DID пользователя (или 'ALL' — для всех)
         | 
| 49 | 
            -
                source TEXT DEFAULT 'user',                                 -- Источник заметки: user | llm | system
         | 
| 50 | 
             
                links TEXT DEFAULT '',                                      -- Ссылки или связи с другими объектами
         | 
| 51 | 
             
                read INTEGER DEFAULT 0,                                     -- Статус прочтения LLM: 0 = нет, 1 = да
         | 
| 52 | 
             
                hidden INTEGER DEFAULT 0,                                   -- Скрыта ли от пользователя: 0 = нет, 1 = да
         | 
|  | |
| 46 | 
             
                text TEXT NOT NULL,                                         -- Текст заметки
         | 
| 47 | 
             
                tags TEXT,                                                  -- Теги (например: "idea", "instruction")
         | 
| 48 | 
             
                user_did TEXT DEFAULT 'ALL',                                -- DID пользователя (или 'ALL' — для всех)
         | 
| 49 | 
            +
                source TEXT DEFAULT 'user',                                 -- Источник заметки: user | cli | llm | system
         | 
| 50 | 
             
                links TEXT DEFAULT '',                                      -- Ссылки или связи с другими объектами
         | 
| 51 | 
             
                read INTEGER DEFAULT 0,                                     -- Статус прочтения LLM: 0 = нет, 1 = да
         | 
| 52 | 
             
                hidden INTEGER DEFAULT 0,                                   -- Скрыта ли от пользователя: 0 = нет, 1 = да
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py
    CHANGED
    
    | @@ -700,18 +700,18 @@ class Storage: | |
| 700 | 
             
                    return row[0] if row else default
         | 
| 701 |  | 
| 702 | 
             
                # Web-интерфейс и API
         | 
| 703 | 
            -
                def write_note(self, content,  | 
| 704 | 
             
                    timestamp = datetime.now(UTC).isoformat()
         | 
| 705 | 
             
                    self.conn.execute("""
         | 
| 706 | 
            -
                        INSERT INTO notes (text,  | 
| 707 | 
            -
                        VALUES (?, ?, ?,  | 
| 708 | 
            -
                    """, (content,  | 
| 709 | 
             
                    self.conn.commit()
         | 
| 710 |  | 
| 711 | 
             
                def get_notes(self, limit=50):
         | 
| 712 | 
             
                    cursor = self.conn.cursor()
         | 
| 713 | 
             
                    cursor.execute("""
         | 
| 714 | 
            -
                        SELECT text,  | 
| 715 | 
             
                        WHERE hidden = 0
         | 
| 716 | 
             
                        ORDER BY timestamp DESC
         | 
| 717 | 
             
                        LIMIT ?
         | 
|  | |
| 700 | 
             
                    return row[0] if row else default
         | 
| 701 |  | 
| 702 | 
             
                # Web-интерфейс и API
         | 
| 703 | 
            +
                def write_note(self, content, user_did="anon", source="user"):
         | 
| 704 | 
             
                    timestamp = datetime.now(UTC).isoformat()
         | 
| 705 | 
             
                    self.conn.execute("""
         | 
| 706 | 
            +
                        INSERT INTO notes (text, user_did, source, timestamp)
         | 
| 707 | 
            +
                        VALUES (?, ?, ?, ?)
         | 
| 708 | 
            +
                    """, (content, user_did, source, timestamp))
         | 
| 709 | 
             
                    self.conn.commit()
         | 
| 710 |  | 
| 711 | 
             
                def get_notes(self, limit=50):
         | 
| 712 | 
             
                    cursor = self.conn.cursor()
         | 
| 713 | 
             
                    cursor.execute("""
         | 
| 714 | 
            +
                        SELECT text, source, user_did, timestamp FROM notes
         | 
| 715 | 
             
                        WHERE hidden = 0
         | 
| 716 | 
             
                        ORDER BY timestamp DESC
         | 
| 717 | 
             
                        LIMIT ?
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/readme.md
    CHANGED
    
    | @@ -79,4 +79,4 @@ FastAPI-сервер, предоставляющий HTTP-интерфейс к | |
| 79 | 
             
            │       └── [`style.css`](notebook/templates/style.css) ← Таблица стилей    
         | 
| 80 | 
             
            ├── [`config.yml`](config.yml) ← Конфигурация агента (имя, порты, роли и т.п.)  
         | 
| 81 | 
             
            ├── [`bootstrap.txt`](bootstrap.txt) ← Локальная этическая модель  
         | 
| 82 | 
            -
            └── [`ethics.yml`](ethics.yml) ← Список начальных узлов   | 
|  | |
| 79 | 
             
            │       └── [`style.css`](notebook/templates/style.css) ← Таблица стилей    
         | 
| 80 | 
             
            ├── [`config.yml`](config.yml) ← Конфигурация агента (имя, порты, роли и т.п.)  
         | 
| 81 | 
             
            ├── [`bootstrap.txt`](bootstrap.txt) ← Локальная этическая модель  
         | 
| 82 | 
            +
            └── [`ethics.yml`](ethics.yml) ← Список начальных узлов  
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml
    CHANGED
    
    | @@ -1,44 +1,69 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 4 | 
             
            api_port: 8080
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
              password: password
         | 
| 11 | 
            -
              username: user
         | 
| 12 | 
            -
            dht_enabled: true
         | 
| 13 | 
             
            dht_port: 20784
         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
             
            llm_backends:
         | 
| 18 | 
            -
            -  | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
               | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
              name: openai-gpt4o
         | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 43 | 
             
            ui_port: 8765
         | 
| 44 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # HMP Agent Configuration
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # === Общие параметры ===
         | 
| 4 | 
            +
            agent_id: ""                      # Оставьте пустым для генерации DiD автоматически
         | 
| 5 | 
            +
            agent_name: "CognitiveCore"       # Имя агента
         | 
| 6 | 
            +
            agent_role: "core"                # 'core' или 'shell'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            # === Прокси ===
         | 
| 9 | 
            +
            proxy_mode: false                 # false — прокси не используется, иначе true
         | 
| 10 | 
            +
            proxy_type: "socks5"              # 'http', 'socks4', 'socks5' и т.д. (если proxy_mode: true)
         | 
| 11 | 
            +
            proxy_address: "127.0.0.1:9050"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            # === Функции ядра ===
         | 
| 14 | 
            +
            enable_llm: true                  # доступ к LLM
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            serve_api: true                   # REST API
         | 
| 17 | 
             
            api_port: 8080
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            # === DHT-сеть и обмен знаниями ===
         | 
| 20 | 
            +
            dht_enabled: true                 # Включение участия в DHT-сети (включено принудительно!)
         | 
| 21 | 
            +
            dht_update: true                  # Регулярные обновления и публикация данных в DHT (включено принудительно!)
         | 
| 22 | 
            +
            bootstrap_responder: true         # Агент отвечает на bootstrap-запросы (включено принудительно!)
         | 
|  | |
|  | |
|  | |
| 23 | 
             
            dht_port: 20784
         | 
| 24 | 
            +
            update_interval: 60               # секунд (для DHT-обновлений)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            # === LLM-бэкенды ===
         | 
| 27 | 
             
            llm_backends:
         | 
| 28 | 
            +
              - name: "local-model"
         | 
| 29 | 
            +
                type: "local"
         | 
| 30 | 
            +
                path: "/models/gguf/mistral.gguf"
         | 
| 31 | 
            +
                format: "gguf"
         | 
| 32 | 
            +
                prompt_template: "mistral"
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              - name: "lmstudio-local"
         | 
| 35 | 
            +
                type: "api"
         | 
| 36 | 
            +
                provider: "openai-compatible"
         | 
| 37 | 
            +
                model: "mistral"               # или то, что LM Studio показывает как модель
         | 
| 38 | 
            +
                api_key: "lm-studio-any-key"  # может быть заглушкой
         | 
| 39 | 
            +
                base_url: "http://127.0.0.1:1234/v1"
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              - name: "openai-gpt4o"
         | 
| 42 | 
            +
                type: "api"
         | 
| 43 | 
            +
                provider: "openai"
         | 
| 44 | 
            +
                model: "gpt-4o"
         | 
| 45 | 
            +
                api_key: "sk-..."
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              # Пользователь может добавить сколько угодно дополнительных локальных или сетевых LLM
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            default_llm: "local-model"        # если модели нет в списке `llm_backends` используется первая в списке
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            # === Веб-интерфейс ===
         | 
| 52 | 
            +
            notebook_ui: true                 # UI в виде блокнота
         | 
| 53 | 
            +
            # ui_hosts:
         | 
| 54 | 
            +
            #   - "0.0.0.0"   # (небезопасно) доступ с любых IPv4-адресов
         | 
| 55 | 
            +
            #   - "::"        # (небезопасно) доступ с любых IPv6-адресов
         | 
| 56 | 
            +
            ui_hosts:                         # Какие IP прослушиваются, ["0.0.0.0"; "::"] - доступен везде
         | 
| 57 | 
            +
              - "127.0.0.1"
         | 
| 58 | 
            +
              - "::1"
         | 
| 59 | 
             
            ui_port: 8765
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            # === Данные пользователя ===
         | 
| 62 | 
            +
            default_user:
         | 
| 63 | 
            +
              username: "user"
         | 
| 64 | 
            +
              email: "[email protected]"
         | 
| 65 | 
            +
              password: "password"            # пусто при инициализации, будет установлен при регистрации
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            # === Отладка и логгирование ===
         | 
| 68 | 
            +
            debug: true
         | 
| 69 | 
            +
            log_level: "INFO"                 # DEBUG, INFO, WARNING, ERROR
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/readme.md
    CHANGED
    
    | @@ -4,7 +4,7 @@ | |
| 4 | 
             
            Конфигурационные файлы: `config.yml`, `bootstrap.txt`
         | 
| 5 | 
             
            Локальная этическая модель: `ethics.yml`
         | 
| 6 |  | 
| 7 | 
            -
            Проверка инициализации БД - если нет, инициализация (` | 
| 8 |  | 
| 9 | 
             
            Запуск потоков (осуществляет start_repl.py):
         | 
| 10 |  | 
| @@ -17,7 +17,6 @@ | |
| 17 | 
             
            | 📡 `transporter.py`               | Обмен сообщениями: WebSocket, IPFS, очереди, шифрование                   |
         | 
| 18 | 
             
            | 🧭 `agent_controller.py`          | Управление режимами REPL, маршрутизация задач и контроль доступа         |
         | 
| 19 | 
             
            | 🧱 `container_agent.py` *(опц.)*  | Управление дочерними агентами, запуск/мониторинг/масштабирование [[docs]](../docs/container_agents.md)         |
         | 
| 20 | 
            -
            | 🧱 `container_agent.py` *(опц.)*  | Управление дочерними агентами, запуск/мониторинг/масштабирование         |
         | 
| 21 | 
             
            | 🧠 `ethics_guard.py` *(опц.)*     | Контроль этики: аудит мыслей, фильтрация и репутационные проверки         |
         | 
| 22 |  | 
| 23 | 
             
            *См. также: [Контейнерные агенты](../docs/container_agents.md), [Архитектура HMP-агента](../docs/HMP-Agent-Architecture.md)*
         | 
|  | |
| 4 | 
             
            Конфигурационные файлы: `config.yml`, `bootstrap.txt`
         | 
| 5 | 
             
            Локальная этическая модель: `ethics.yml`
         | 
| 6 |  | 
| 7 | 
            +
            Проверка инициализации БД - если нет, инициализация (`init.py`)
         | 
| 8 |  | 
| 9 | 
             
            Запуск потоков (осуществляет start_repl.py):
         | 
| 10 |  | 
|  | |
| 17 | 
             
            | 📡 `transporter.py`               | Обмен сообщениями: WebSocket, IPFS, очереди, шифрование                   |
         | 
| 18 | 
             
            | 🧭 `agent_controller.py`          | Управление режимами REPL, маршрутизация задач и контроль доступа         |
         | 
| 19 | 
             
            | 🧱 `container_agent.py` *(опц.)*  | Управление дочерними агентами, запуск/мониторинг/масштабирование [[docs]](../docs/container_agents.md)         |
         | 
|  | |
| 20 | 
             
            | 🧠 `ethics_guard.py` *(опц.)*     | Контроль этики: аудит мыслей, фильтрация и репутационные проверки         |
         | 
| 21 |  | 
| 22 | 
             
            *См. также: [Контейнерные агенты](../docs/container_agents.md), [Архитектура HMP-агента](../docs/HMP-Agent-Architecture.md)*
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/check_agents.py
    CHANGED
    
    | @@ -1,21 +1,35 @@ | |
|  | |
|  | |
| 1 | 
             
            import os
         | 
| 2 | 
             
            import sys
         | 
| 3 | 
            -
            from datetime import datetime,  | 
| 4 |  | 
| 5 | 
             
            sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
         | 
|  | |
| 6 | 
             
            from tools.storage import Storage
         | 
| 7 |  | 
| 8 | 
             
            storage = Storage()
         | 
| 9 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 10 | 
             
            def check_all_processes():
         | 
|  | |
|  | |
|  | |
| 11 | 
             
                processes = storage.conn.execute("SELECT name, heartbeat FROM main_process").fetchall()
         | 
| 12 | 
            -
                
         | 
| 13 | 
             
                if not processes:
         | 
| 14 | 
             
                    print("⛔ В базе нет активных процессов.")
         | 
| 15 | 
             
                    return
         | 
| 16 | 
            -
             | 
| 17 | 
             
                print("📋 Статус процессов:")
         | 
| 18 | 
            -
                now = datetime. | 
| 19 | 
             
                for name, heartbeat in processes:
         | 
| 20 | 
             
                    try:
         | 
| 21 | 
             
                        hb_time = datetime.fromisoformat(heartbeat)
         | 
| @@ -26,4 +40,4 @@ def check_all_processes(): | |
| 26 | 
             
                        print(f" • {name:20} — ⚠️ Ошибка: {e}")
         | 
| 27 |  | 
| 28 | 
             
            if __name__ == "__main__":
         | 
| 29 | 
            -
                check_all_processes()
         | 
|  | |
| 1 | 
            +
            # agents/check_agents.py
         | 
| 2 | 
            +
             | 
| 3 | 
             
            import os
         | 
| 4 | 
             
            import sys
         | 
| 5 | 
            +
            from datetime import datetime, UTC
         | 
| 6 |  | 
| 7 | 
             
            sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
         | 
| 8 | 
            +
             | 
| 9 | 
             
            from tools.storage import Storage
         | 
| 10 |  | 
| 11 | 
             
            storage = Storage()
         | 
| 12 |  | 
| 13 | 
            +
            def print_config():
         | 
| 14 | 
            +
                print("⚙️ Конфигурация:")
         | 
| 15 | 
            +
                rows = storage.conn.execute("SELECT key, value FROM config").fetchall()
         | 
| 16 | 
            +
                if not rows:
         | 
| 17 | 
            +
                    print(" • (таблица config пуста)")
         | 
| 18 | 
            +
                for key, value in rows:
         | 
| 19 | 
            +
                    print(f" • {key:20} = {value}")
         | 
| 20 | 
            +
                print()
         | 
| 21 | 
            +
             | 
| 22 | 
             
            def check_all_processes():
         | 
| 23 | 
            +
                print_config()
         | 
| 24 | 
            +
                print(f"🗄️ Путь к базе данных: {storage.db_path}\n")
         | 
| 25 | 
            +
             | 
| 26 | 
             
                processes = storage.conn.execute("SELECT name, heartbeat FROM main_process").fetchall()
         | 
|  | |
| 27 | 
             
                if not processes:
         | 
| 28 | 
             
                    print("⛔ В базе нет активных процессов.")
         | 
| 29 | 
             
                    return
         | 
| 30 | 
            +
             | 
| 31 | 
             
                print("📋 Статус процессов:")
         | 
| 32 | 
            +
                now = datetime.now(UTC)
         | 
| 33 | 
             
                for name, heartbeat in processes:
         | 
| 34 | 
             
                    try:
         | 
| 35 | 
             
                        hb_time = datetime.fromisoformat(heartbeat)
         | 
|  | |
| 40 | 
             
                        print(f" • {name:20} — ⚠️ Ошибка: {e}")
         | 
| 41 |  | 
| 42 | 
             
            if __name__ == "__main__":
         | 
| 43 | 
            +
                check_all_processes()
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml
    CHANGED
    
    | @@ -1,75 +1,44 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
            agent_id: ""                      # Оставьте пустым для генерации DiD автоматически
         | 
| 5 | 
            -
            agent_name: "CognitiveCore"       # Имя агента
         | 
| 6 | 
            -
            agent_role: "core"                # 'core' или 'shell'
         | 
| 7 | 
            -
             | 
| 8 | 
            -
            # === Прокси ===
         | 
| 9 | 
            -
            proxy_mode: false                 # false — прокси не используется, иначе true
         | 
| 10 | 
            -
            proxy_type: "socks5"              # 'http', 'socks4', 'socks5' и т.д. (если proxy_mode: true)
         | 
| 11 | 
            -
            proxy_address: "127.0.0.1:9050"
         | 
| 12 | 
            -
             | 
| 13 | 
            -
            # === Функции ядра ===
         | 
| 14 | 
            -
            enable_llm: true                  # доступ к LLM
         | 
| 15 | 
            -
             | 
| 16 | 
            -
            serve_api: true                   # REST API
         | 
| 17 | 
             
            api_port: 8080
         | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
|  | |
|  | |
|  | |
| 23 | 
             
            dht_port: 20784
         | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
             
            llm_backends:
         | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
               | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
               | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
            # ui_hosts:
         | 
| 54 | 
            -
            #   - "0.0.0.0"   # (небезопасно) доступ с любых IPv4-адресов
         | 
| 55 | 
            -
            #   - "::"        # (небезопасно) доступ с любых IPv6-адресов
         | 
| 56 | 
            -
            ui_hosts:                         # Какие IP прослушиваются, ["0.0.0.0"; "::"] - доступен везде
         | 
| 57 | 
            -
              - "127.0.0.1"
         | 
| 58 | 
            -
              - "::1"
         | 
| 59 | 
             
            ui_port: 8765
         | 
| 60 | 
            -
             | 
| 61 | 
            -
            # === Данные пользователя ===
         | 
| 62 | 
            -
            default_user:
         | 
| 63 | 
            -
              username: "user"
         | 
| 64 | 
            -
              email: "[email protected]"
         | 
| 65 | 
            -
              password_hash: ""               # пусто при инициализации, будет установлен при регистрации
         | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
            # === Пути ===
         | 
| 69 | 
            -
            data_dir: "./data"
         | 
| 70 | 
            -
            log_dir: "./logs"
         | 
| 71 | 
            -
            db_path: "./data/agent_storage.db"
         | 
| 72 | 
            -
             | 
| 73 | 
            -
            # === Отладка и логгирование ===
         | 
| 74 | 
            -
            debug: true
         | 
| 75 | 
            -
            log_level: "INFO"                 # DEBUG, INFO, WARNING, ERROR
         | 
|  | |
| 1 | 
            +
            agent_id: did:hmp:6afb62eb-8384-4042-948a-c4b7adee3e59
         | 
| 2 | 
            +
            agent_name: CognitiveCore
         | 
| 3 | 
            +
            agent_role: core
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 4 | 
             
            api_port: 8080
         | 
| 5 | 
            +
            bootstrap_responder: true
         | 
| 6 | 
            +
            debug: true
         | 
| 7 | 
            +
            default_llm: local-model
         | 
| 8 | 
            +
            default_user:
         | 
| 9 | 
            +
              email: [email protected]
         | 
| 10 | 
            +
              password: password
         | 
| 11 | 
            +
              username: user
         | 
| 12 | 
            +
            dht_enabled: true
         | 
| 13 | 
             
            dht_port: 20784
         | 
| 14 | 
            +
            dht_update: true
         | 
| 15 | 
            +
            enable_llm: true
         | 
| 16 | 
            +
            identity_agent: 6afb62eb-8384-4042-948a-c4b7adee3e59
         | 
| 17 | 
             
            llm_backends:
         | 
| 18 | 
            +
            - format: gguf
         | 
| 19 | 
            +
              name: local-model
         | 
| 20 | 
            +
              path: /models/gguf/mistral.gguf
         | 
| 21 | 
            +
              prompt_template: mistral
         | 
| 22 | 
            +
              type: local
         | 
| 23 | 
            +
            - api_key: lm-studio-any-key
         | 
| 24 | 
            +
              base_url: http://127.0.0.1:1234/v1
         | 
| 25 | 
            +
              model: mistral
         | 
| 26 | 
            +
              name: lmstudio-local
         | 
| 27 | 
            +
              provider: openai-compatible
         | 
| 28 | 
            +
              type: api
         | 
| 29 | 
            +
            - api_key: sk-...
         | 
| 30 | 
            +
              model: gpt-4o
         | 
| 31 | 
            +
              name: openai-gpt4o
         | 
| 32 | 
            +
              provider: openai
         | 
| 33 | 
            +
              type: api
         | 
| 34 | 
            +
            log_level: INFO
         | 
| 35 | 
            +
            notebook_ui: true
         | 
| 36 | 
            +
            proxy_address: 127.0.0.1:9050
         | 
| 37 | 
            +
            proxy_mode: false
         | 
| 38 | 
            +
            proxy_type: socks5
         | 
| 39 | 
            +
            serve_api: true
         | 
| 40 | 
            +
            ui_hosts:
         | 
| 41 | 
            +
            - 127.0.0.1
         | 
| 42 | 
            +
            - ::1
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 43 | 
             
            ui_port: 8765
         | 
| 44 | 
            +
            update_interval: 60
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/examples/config.yml
    CHANGED
    
    | @@ -62,13 +62,7 @@ ui_port: 8765 | |
| 62 | 
             
            default_user:
         | 
| 63 | 
             
              username: "user"
         | 
| 64 | 
             
              email: "[email protected]"
         | 
| 65 | 
            -
               | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
            # === Пути ===
         | 
| 69 | 
            -
            data_dir: "./data"
         | 
| 70 | 
            -
            log_dir: "./logs"
         | 
| 71 | 
            -
            db_path: "./data/agent_storage.db"
         | 
| 72 |  | 
| 73 | 
             
            # === Отладка и логгирование ===
         | 
| 74 | 
             
            debug: true
         | 
|  | |
| 62 | 
             
            default_user:
         | 
| 63 | 
             
              username: "user"
         | 
| 64 | 
             
              email: "[email protected]"
         | 
| 65 | 
            +
              password: "password"            # пусто при инициализации, будет установлен при регистрации
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 66 |  | 
| 67 | 
             
            # === Отладка и логгирование ===
         | 
| 68 | 
             
            debug: true
         | 
    	
        hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/init.py
    CHANGED
    
    | @@ -4,20 +4,19 @@ import os | |
| 4 | 
             
            import sys
         | 
| 5 | 
             
            import yaml
         | 
| 6 | 
             
            import json
         | 
| 7 | 
            -
            import time
         | 
| 8 | 
             
            import uuid
         | 
| 9 | 
             
            import sqlite3
         | 
| 10 |  | 
| 11 | 
             
            sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
         | 
| 12 |  | 
| 13 | 
            -
            from datetime import datetime
         | 
| 14 | 
             
            from werkzeug.security import generate_password_hash
         | 
| 15 | 
             
            from tools.storage import Storage
         | 
| 16 | 
             
            from tools.identity import generate_did
         | 
| 17 | 
             
            from tools.crypto import generate_keypair
         | 
| 18 | 
            -
            from tools.config_utils import update_config
         | 
| 19 |  | 
| 20 | 
             
            CONFIG_PATH = os.path.join(os.path.dirname(__file__), "config.yml")
         | 
|  | |
| 21 |  | 
| 22 | 
             
            def load_config(path):
         | 
| 23 | 
             
                with open(path, 'r', encoding='utf-8') as f:
         | 
| @@ -39,12 +38,11 @@ def init_identity(storage, config): | |
| 39 | 
             
                        "pubkey": pubkey,
         | 
| 40 | 
             
                        "privkey": privkey,
         | 
| 41 | 
             
                        "metadata": json.dumps({"role": config.get("agent_role", "core")}),
         | 
| 42 | 
            -
                        "created_at": datetime. | 
| 43 | 
            -
                        "updated_at": datetime. | 
| 44 | 
             
                    }
         | 
| 45 | 
             
                    storage.add_identity(identity)
         | 
| 46 |  | 
| 47 | 
            -
                    # Обновляем config.yml
         | 
| 48 | 
             
                    config["agent_id"] = did
         | 
| 49 | 
             
                    config["identity_agent"] = identity_id
         | 
| 50 | 
             
                    save_config(CONFIG_PATH, config)
         | 
| @@ -61,8 +59,8 @@ def init_user(storage, config): | |
| 61 | 
             
                if not password:
         | 
| 62 | 
             
                    print("[-] Не указан пароль пользователя — пропуск.")
         | 
| 63 | 
             
                    return
         | 
| 64 | 
            -
                password_hash = generate_password_hash(password)
         | 
| 65 |  | 
|  | |
| 66 | 
             
                did = generate_did()
         | 
| 67 | 
             
                user_entry = {
         | 
| 68 | 
             
                    "username": user.get("username", "user"),
         | 
| @@ -76,7 +74,6 @@ def init_user(storage, config): | |
| 76 | 
             
                    "operator": 1
         | 
| 77 | 
             
                }
         | 
| 78 | 
             
                storage.add_user(user_entry)
         | 
| 79 | 
            -
             | 
| 80 | 
             
                print(f"[+] Пользователь {user['username']} добавлен.")
         | 
| 81 |  | 
| 82 | 
             
            def init_llm_backends(storage, config):
         | 
| @@ -90,7 +87,7 @@ def init_llm_backends(storage, config): | |
| 90 | 
             
                        "name": backend["name"],
         | 
| 91 | 
             
                        "endpoint": desc,
         | 
| 92 | 
             
                        "metadata": json.dumps(backend),
         | 
| 93 | 
            -
                        "created_at": datetime. | 
| 94 | 
             
                    }
         | 
| 95 | 
             
                    storage.add_llm(llm)
         | 
| 96 | 
             
                    print(f"[+] Зарегистрирован LLM: {backend['name']}")
         | 
| @@ -102,19 +99,14 @@ def init_config_table(storage, config): | |
| 102 | 
             
                    storage.set_config(key, json.dumps(value))
         | 
| 103 | 
             
                print("[+] Конфигурация сохранена в БД.")
         | 
| 104 |  | 
| 105 | 
            -
            def ensure_directories( | 
| 106 | 
            -
                 | 
| 107 | 
            -
                     | 
| 108 | 
            -
                     | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
                for path in directories:
         | 
| 113 | 
            -
                    if path and not os.path.exists(path):
         | 
| 114 | 
            -
                        os.makedirs(path)
         | 
| 115 | 
            -
                        print(f"[+] Создан каталог: {path}")
         | 
| 116 | 
             
                    else:
         | 
| 117 | 
            -
                        print(f"[=] Каталог уже существует: { | 
| 118 |  | 
| 119 | 
             
            def is_db_initialized(db_path):
         | 
| 120 | 
             
                if not os.path.exists(db_path):
         | 
| @@ -129,13 +121,12 @@ def is_db_initialized(db_path): | |
| 129 |  | 
| 130 | 
             
            def ensure_db_initialized():
         | 
| 131 | 
             
                config = load_config(CONFIG_PATH)
         | 
| 132 | 
            -
                db_path = config.get("db_path", "./data/agent_storage.db")
         | 
| 133 |  | 
| 134 | 
            -
                if not is_db_initialized( | 
| 135 | 
             
                    print("[*] БД не инициализирована — выполняем инициализацию.")
         | 
| 136 | 
             
                    try:
         | 
| 137 | 
            -
                        ensure_directories( | 
| 138 | 
            -
                        storage = Storage( | 
| 139 | 
             
                        init_identity(storage, config)
         | 
| 140 | 
             
                        init_user(storage, config)
         | 
| 141 | 
             
                        init_llm_backends(storage, config)
         | 
| @@ -150,4 +141,4 @@ def ensure_db_initialized(): | |
| 150 | 
             
                return config
         | 
| 151 |  | 
| 152 | 
             
            if __name__ == "__main__":
         | 
| 153 | 
            -
                ensure_db_initialized()
         | 
|  | |
| 4 | 
             
            import sys
         | 
| 5 | 
             
            import yaml
         | 
| 6 | 
             
            import json
         | 
|  | |
| 7 | 
             
            import uuid
         | 
| 8 | 
             
            import sqlite3
         | 
| 9 |  | 
| 10 | 
             
            sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
         | 
| 11 |  | 
| 12 | 
            +
            from datetime import datetime, UTC
         | 
| 13 | 
             
            from werkzeug.security import generate_password_hash
         | 
| 14 | 
             
            from tools.storage import Storage
         | 
| 15 | 
             
            from tools.identity import generate_did
         | 
| 16 | 
             
            from tools.crypto import generate_keypair
         | 
|  | |
| 17 |  | 
| 18 | 
             
            CONFIG_PATH = os.path.join(os.path.dirname(__file__), "config.yml")
         | 
| 19 | 
            +
            DB_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "agent_data.db"))  # фиксированный путь
         | 
| 20 |  | 
| 21 | 
             
            def load_config(path):
         | 
| 22 | 
             
                with open(path, 'r', encoding='utf-8') as f:
         | 
|  | |
| 38 | 
             
                        "pubkey": pubkey,
         | 
| 39 | 
             
                        "privkey": privkey,
         | 
| 40 | 
             
                        "metadata": json.dumps({"role": config.get("agent_role", "core")}),
         | 
| 41 | 
            +
                        "created_at": datetime.now(UTC).isoformat(),
         | 
| 42 | 
            +
                        "updated_at": datetime.now(UTC).isoformat()
         | 
| 43 | 
             
                    }
         | 
| 44 | 
             
                    storage.add_identity(identity)
         | 
| 45 |  | 
|  | |
| 46 | 
             
                    config["agent_id"] = did
         | 
| 47 | 
             
                    config["identity_agent"] = identity_id
         | 
| 48 | 
             
                    save_config(CONFIG_PATH, config)
         | 
|  | |
| 59 | 
             
                if not password:
         | 
| 60 | 
             
                    print("[-] Не указан пароль пользователя — пропуск.")
         | 
| 61 | 
             
                    return
         | 
|  | |
| 62 |  | 
| 63 | 
            +
                password_hash = generate_password_hash(password)
         | 
| 64 | 
             
                did = generate_did()
         | 
| 65 | 
             
                user_entry = {
         | 
| 66 | 
             
                    "username": user.get("username", "user"),
         | 
|  | |
| 74 | 
             
                    "operator": 1
         | 
| 75 | 
             
                }
         | 
| 76 | 
             
                storage.add_user(user_entry)
         | 
|  | |
| 77 | 
             
                print(f"[+] Пользователь {user['username']} добавлен.")
         | 
| 78 |  | 
| 79 | 
             
            def init_llm_backends(storage, config):
         | 
|  | |
| 87 | 
             
                        "name": backend["name"],
         | 
| 88 | 
             
                        "endpoint": desc,
         | 
| 89 | 
             
                        "metadata": json.dumps(backend),
         | 
| 90 | 
            +
                        "created_at": datetime.now(UTC).isoformat()
         | 
| 91 | 
             
                    }
         | 
| 92 | 
             
                    storage.add_llm(llm)
         | 
| 93 | 
             
                    print(f"[+] Зарегистрирован LLM: {backend['name']}")
         | 
|  | |
| 99 | 
             
                    storage.set_config(key, json.dumps(value))
         | 
| 100 | 
             
                print("[+] Конфигурация сохранена в БД.")
         | 
| 101 |  | 
| 102 | 
            +
            def ensure_directories():
         | 
| 103 | 
            +
                for folder in ["logs", "scripts"]:
         | 
| 104 | 
            +
                    full_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", folder))
         | 
| 105 | 
            +
                    if not os.path.exists(full_path):
         | 
| 106 | 
            +
                        os.makedirs(full_path)
         | 
| 107 | 
            +
                        print(f"[+] Создан каталог: {full_path}")
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 108 | 
             
                    else:
         | 
| 109 | 
            +
                        print(f"[=] Каталог уже существует: {full_path}")
         | 
| 110 |  | 
| 111 | 
             
            def is_db_initialized(db_path):
         | 
| 112 | 
             
                if not os.path.exists(db_path):
         | 
|  | |
| 121 |  | 
| 122 | 
             
            def ensure_db_initialized():
         | 
| 123 | 
             
                config = load_config(CONFIG_PATH)
         | 
|  | |
| 124 |  | 
| 125 | 
            +
                if not is_db_initialized(DB_PATH):
         | 
| 126 | 
             
                    print("[*] БД не инициализирована — выполняем инициализацию.")
         | 
| 127 | 
             
                    try:
         | 
| 128 | 
            +
                        ensure_directories()
         | 
| 129 | 
            +
                        storage = Storage()
         | 
| 130 | 
             
                        init_identity(storage, config)
         | 
| 131 | 
             
                        init_user(storage, config)
         | 
| 132 | 
             
                        init_llm_backends(storage, config)
         | 
|  | |
| 141 | 
             
                return config
         | 
| 142 |  | 
| 143 | 
             
            if __name__ == "__main__":
         | 
| 144 | 
            +
                ensure_db_initialized()
         | 
