add files
This commit is contained in:
parent
b7ced7d964
commit
d35e9d7a21
11
backend/Dockerfile
Normal file
11
backend/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM python:3.12
|
||||||
|
|
||||||
|
#RUN curl https://ollama.ai/install.sh | sh
|
||||||
|
#RUN ollama run llama2
|
||||||
|
|
||||||
|
COPY requirements.txt requirements.txt
|
||||||
|
RUN pip3 install -r requirements.txt
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENTRYPOINT ["python3", "app.py"]
|
||||||
|
|
BIN
backend/__pycache__/elastictools.cpython-310.pyc
Normal file
BIN
backend/__pycache__/elastictools.cpython-310.pyc
Normal file
Binary file not shown.
BIN
backend/__pycache__/funcs.cpython-310.pyc
Normal file
BIN
backend/__pycache__/funcs.cpython-310.pyc
Normal file
Binary file not shown.
160
backend/app.py
Normal file
160
backend/app.py
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
|
||||||
|
"""
|
||||||
|
OpenAPI access via http://localhost:5000/openapi/ on local docker-compose deployment
|
||||||
|
|
||||||
|
"""
|
||||||
|
#import warnings
|
||||||
|
#warnings.filterwarnings("ignore")
|
||||||
|
|
||||||
|
#std lib modules:
|
||||||
|
import os, sys, json
|
||||||
|
from typing import Any, Tuple, List, Dict, Any, Callable, Optional
|
||||||
|
from datetime import datetime, date
|
||||||
|
from collections import namedtuple
|
||||||
|
import hashlib, traceback, logging
|
||||||
|
|
||||||
|
#llm
|
||||||
|
from langchain.callbacks.manager import CallbackManager
|
||||||
|
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
|
||||||
|
from langchain_community.llms import Ollama
|
||||||
|
|
||||||
|
#import openai #even used?
|
||||||
|
import tiktoken
|
||||||
|
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||||
|
from langchain.chains import RetrievalQA
|
||||||
|
#from langchain.callbacks import get_openai_callback
|
||||||
|
#from langchain_community.callbacks import get_openai_callback
|
||||||
|
|
||||||
|
#from langchain_openai import ChatOpenAI, AzureChatOpenAI
|
||||||
|
#from langchain_openai import OpenAIEmbeddings, AzureOpenAIEmbeddings
|
||||||
|
from langchain_community.vectorstores.elasticsearch import ElasticsearchStore
|
||||||
|
#from langchain.document_loaders import PyPDFLoader, Docx2txtLoader
|
||||||
|
from langchain_community.document_loaders import PyPDFLoader, Docx2txtLoader
|
||||||
|
|
||||||
|
from langchain.callbacks.base import BaseCallbackHandler, BaseCallbackManager
|
||||||
|
from langchain.prompts import PromptTemplate
|
||||||
|
|
||||||
|
#ext libs
|
||||||
|
from elasticsearch import NotFoundError, Elasticsearch # for normal read/write without vectors
|
||||||
|
from elasticsearch_dsl import Search, A
|
||||||
|
from elasticsearch_dsl import Document, Date, Integer, Keyword, Float, Long, Text, connections
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
#flask, openapi
|
||||||
|
from flask import Flask, send_from_directory, Response, request, jsonify
|
||||||
|
import sys, os
|
||||||
|
from flask_cors import CORS, cross_origin
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
|
from flask_openapi3 import Info, Tag, OpenAPI, Server, FileStorage
|
||||||
|
from flask_socketio import SocketIO, join_room, leave_room, rooms, send
|
||||||
|
|
||||||
|
|
||||||
|
#home grown
|
||||||
|
#from scraper import WebScraper
|
||||||
|
from funcs import group_by
|
||||||
|
#from elastictools import update_by_id, delete_by_id
|
||||||
|
|
||||||
|
#TODO: implement some kind of logging mechanism
|
||||||
|
#logging.basicConfig(filename='record.log', level=logging.DEBUG)
|
||||||
|
#logging.basicConfig(level=logging.DEBUG)
|
||||||
|
logging.basicConfig(level=logging.WARN)
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
from flask_cors import CORS #falls cross-orgin verwendet werden soll
|
||||||
|
CORS(app)
|
||||||
|
|
||||||
|
socket = SocketIO(app, cors_allowed_origins="*")
|
||||||
|
|
||||||
|
@socket.on('connect')
|
||||||
|
def sockcon(data):
|
||||||
|
"""
|
||||||
|
put every connection into it's own room
|
||||||
|
to avoid broadcasting messages
|
||||||
|
answer in callback only to room with sid
|
||||||
|
"""
|
||||||
|
room = request.sid
|
||||||
|
join_room(room)
|
||||||
|
socket.emit('backend response', {'msg': f'Connected to room {room} !', "room": room}) # looks like iOS needs an answer
|
||||||
|
|
||||||
|
|
||||||
|
class StreamingCallback(BaseCallbackHandler):
|
||||||
|
|
||||||
|
def __init__(self, key: str, sid: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_llm_new_token(self, token: str, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_llm_end(self, response, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@socket.on('client message')
|
||||||
|
def handle_message(message):
|
||||||
|
|
||||||
|
room = message["room"]
|
||||||
|
stream_key = "chatbot_stream"
|
||||||
|
|
||||||
|
llm = Ollama(
|
||||||
|
model="llama3",
|
||||||
|
#callback_manager=CallbackManager([StreamingCallback(stream_key, room)]),
|
||||||
|
base_url="http://ollama:11434"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
system_prompt = "Answer in the language of the question. Give a short answer. Answer all questions without reservations or advice."
|
||||||
|
|
||||||
|
|
||||||
|
query = system_prompt + " " + message["data"]
|
||||||
|
print(message["data"])
|
||||||
|
|
||||||
|
for chunks in llm.stream(query):
|
||||||
|
socket.emit('backend token', {'data': chunks, "done": False}, to=room)
|
||||||
|
|
||||||
|
socket.emit('backend token', {'done': True}, to=room)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#==============Routes===============
|
||||||
|
|
||||||
|
@app.route("/") #Index Verzeichnis
|
||||||
|
def index():
|
||||||
|
return send_from_directory('.', "index.html")
|
||||||
|
|
||||||
|
@app.route("/info") #spezielle Nutzer definierte Route
|
||||||
|
def info():
|
||||||
|
return sys.version+" "+os.getcwd()
|
||||||
|
|
||||||
|
@app.route('/<path:path>') #generische Route (auch Unterordner)
|
||||||
|
def catchAll(path):
|
||||||
|
return send_from_directory('.', path)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
#Wenn HTTPS benötigt wird (Pfade für RHEL7/können je OS variieren)
|
||||||
|
#cert = "/etc/pki/tls/certs/cert-payment.pem" #cert
|
||||||
|
#key = "/etc/pki/tls/private/cert-payment-private.pem" #key
|
||||||
|
#context = (cert, key)
|
||||||
|
#app.run(debug=True, host='0.0.0.0', ssl_context=context)
|
||||||
|
app.run(debug=True, host='0.0.0.0')
|
||||||
|
#app.run(debug=True)
|
||||||
|
|
||||||
|
"""
|
||||||
|
llm = Ollama(
|
||||||
|
model="llama2",
|
||||||
|
callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]),
|
||||||
|
base_url="http://ollama:11434"
|
||||||
|
)
|
||||||
|
|
||||||
|
assume = "Answer the next question with either true or false and name an example."
|
||||||
|
question = "Can cats use guns?"
|
||||||
|
print(question)
|
||||||
|
s = llm.invoke(assume + " " + question)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
0
backend/backend.env
Normal file
0
backend/backend.env
Normal file
45
backend/elastictools.py
Normal file
45
backend/elastictools.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
Some helper functions to make querying easier
|
||||||
|
"""
|
||||||
|
from typing import Any, Tuple, List, Dict, Any, Callable, Optional
|
||||||
|
import json
|
||||||
|
from elasticsearch import NotFoundError, Elasticsearch # for normal read/write without vectors
|
||||||
|
from elasticsearch_dsl import Search, A
|
||||||
|
from elasticsearch_dsl import Document, Date, Integer, Keyword, Float, Long, Text, connections
|
||||||
|
|
||||||
|
|
||||||
|
def update_by_id(client: Elasticsearch, index: str, id_field_name: str, id_value: str, values_to_set: Dict[str, Any]) -> None:
|
||||||
|
#create painless insert script
|
||||||
|
source = ""
|
||||||
|
for k, v in values_to_set.items():
|
||||||
|
source += f"ctx._source.{k} = {json.dumps(v)};"
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"query": {
|
||||||
|
"term": {
|
||||||
|
id_field_name: id_value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"script": {
|
||||||
|
"source": source,
|
||||||
|
"lang": "painless"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.update_by_query(index=index, body=body)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def delete_by_id(client: Elasticsearch, index: str, id_field_name: str, id_value: str):
|
||||||
|
s = Search(using=client, index=index).filter("term", **{id_field_name: id_value})
|
||||||
|
response = s.delete()
|
||||||
|
#if not response.success():
|
||||||
|
# raise Exception("Unable to delete id '%s' in index '%' !" % (index, id_value))
|
||||||
|
|
||||||
|
print(response, flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_datetime_interval(search: Search, start, end) -> Search:
|
||||||
|
return search.filter("range", timest={"gte": start}).filter("range", timest={"lte": end})
|
||||||
|
|
||||||
|
|
36
backend/funcs.py
Normal file
36
backend/funcs.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
"""
|
||||||
|
Function lib
|
||||||
|
"""
|
||||||
|
from typing import Any, Tuple, List, Dict, Any, Callable, Optional
|
||||||
|
import json
|
||||||
|
|
||||||
|
def group_by(fs: List[Callable[[Any], Any]], ls: List[Any]) -> Dict[Any, Any]:
|
||||||
|
"""
|
||||||
|
Recursivly divides a list into sublists according to a list of membership-defining functions
|
||||||
|
"""
|
||||||
|
match fs:
|
||||||
|
case [f]:
|
||||||
|
match ls:
|
||||||
|
case []: return {}
|
||||||
|
case _:
|
||||||
|
d = {}
|
||||||
|
for x in ls:
|
||||||
|
k = f(x)
|
||||||
|
if k in d:
|
||||||
|
d[k].append(x)
|
||||||
|
else:
|
||||||
|
d[k] = [x]
|
||||||
|
return d
|
||||||
|
case [f, *fs]:
|
||||||
|
d = group_by([f], ls)
|
||||||
|
return {k: group_by(fs, v) for k, v in d.items()}
|
||||||
|
|
||||||
|
|
||||||
|
def pretty(x):
|
||||||
|
"""
|
||||||
|
A convenience pretty printing function
|
||||||
|
"""
|
||||||
|
print( json.dumps(x, indent=4) )
|
||||||
|
|
||||||
|
|
||||||
|
|
77
backend/index.html
Normal file
77
backend/index.html
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Ollama Chatbot</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="w3.css">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table id="log" class="w3-table-all" style="width: 100%;">
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<textarea style="width: 100%; height: 50px;" id="user_input"></textarea>
|
||||||
|
<button id="submit_btn">Submit</button>
|
||||||
|
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
window.onload = ()=>{
|
||||||
|
let tA = document.getElementById("user_input");
|
||||||
|
let log = document.getElementById("log");
|
||||||
|
let btn = document.getElementById("submit_btn");
|
||||||
|
|
||||||
|
function log_msg(nick, msg){
|
||||||
|
console.log(nick + ": " + msg);
|
||||||
|
log.innerHTML += "<tr><td><b>" + nick + "</b>:</td><td>" + msg + "</td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
log_msg("Bot", "Ask a question!");
|
||||||
|
|
||||||
|
const socket = io();
|
||||||
|
|
||||||
|
let room = null;
|
||||||
|
socket.on('backend response', function(data) {
|
||||||
|
console.log(data);
|
||||||
|
if(data.room) room = data.room;
|
||||||
|
});
|
||||||
|
|
||||||
|
let answer_count = 0;
|
||||||
|
let acc_text = "";
|
||||||
|
let first_token = true;
|
||||||
|
|
||||||
|
socket.on('backend token', function(obj) {
|
||||||
|
console.log(obj);
|
||||||
|
if(first_token){
|
||||||
|
let id = answer_count;
|
||||||
|
log.innerHTML += "<tr><td><b>Bot</b>:</td><td id='" + id + "'></td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!obj.done){
|
||||||
|
acc_text += "" + obj.data;
|
||||||
|
first_token = false;
|
||||||
|
document.getElementById(answer_count).innerHTML += obj.data;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//log_msg("Bot", acc_text);
|
||||||
|
acc_text = "";
|
||||||
|
first_token = true;
|
||||||
|
answer_count += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btn.onclick = evt=>{
|
||||||
|
let s = tA.value;
|
||||||
|
if(s.trim() != '' && room){
|
||||||
|
tA.value = "";
|
||||||
|
log_msg('User', s);
|
||||||
|
socket.emit('client message', {data: s, room: room});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
93
backend/models.py
Normal file
93
backend/models.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import os
|
||||||
|
from elasticsearch_dsl import Document, InnerDoc, Date, Integer, Keyword, Float, Long, Text, connections, Object
|
||||||
|
|
||||||
|
# Define a default Elasticsearch client
|
||||||
|
connections.create_connection(hosts="http://localhost:9200")
|
||||||
|
|
||||||
|
class Article(Document):
|
||||||
|
title = Text(analyzer='snowball', fields={'raw': Keyword()})
|
||||||
|
body = Text(analyzer='snowball')
|
||||||
|
tags = Keyword()
|
||||||
|
published_from = Date()
|
||||||
|
lines = Integer()
|
||||||
|
|
||||||
|
class Index:
|
||||||
|
name = 'blog'
|
||||||
|
settings = {
|
||||||
|
"number_of_shards": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
def save(self, ** kwargs):
|
||||||
|
self.lines = len(self.body.split())
|
||||||
|
return super(Article, self).save(** kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
#======= nextsearch_log ===========
|
||||||
|
|
||||||
|
class Sources(InnerDoc):
|
||||||
|
score = Float()
|
||||||
|
sourceFileId = Text()
|
||||||
|
sourceType = Text()
|
||||||
|
tags = Text()
|
||||||
|
|
||||||
|
class NextsearchLog(Document):
|
||||||
|
a = Text()
|
||||||
|
chatbotid = Keyword()
|
||||||
|
durasecs = Float()
|
||||||
|
inCt = Float()
|
||||||
|
inToks = Long()
|
||||||
|
llm = Text()
|
||||||
|
outCt = Float()
|
||||||
|
outToks = Long()
|
||||||
|
q = Text()
|
||||||
|
queryid = Keyword()
|
||||||
|
rating = Long()
|
||||||
|
reason = Text()
|
||||||
|
reasontags = Text()
|
||||||
|
session = Keyword()
|
||||||
|
|
||||||
|
sources = Object(Sources) #Text(analyzer='snowball')
|
||||||
|
temperature = Float()
|
||||||
|
totalCt = Float()
|
||||||
|
|
||||||
|
timest = Date() #timestamp
|
||||||
|
date = Date() #iso date
|
||||||
|
|
||||||
|
class Index:
|
||||||
|
#name = 'test_nextsearch_log'
|
||||||
|
name = 'nextsearch_log'
|
||||||
|
settings = {
|
||||||
|
"number_of_shards": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
def save(self, ** kwargs):
|
||||||
|
self.lines = len(self.body.split())
|
||||||
|
return super(NextsearchLog, self).save(** kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
elastic_uri = os.getenv("ELASTIC_URI")
|
||||||
|
#elastic_uri = "http://localhost:9200"
|
||||||
|
assert elastic_uri
|
||||||
|
|
||||||
|
# Define a default Elasticsearch client
|
||||||
|
connections.create_connection(hosts=elastic_uri)
|
||||||
|
#connections.create_connection(hosts)
|
||||||
|
|
||||||
|
# create the mappings in elasticsearch
|
||||||
|
NextsearchLog.init()
|
||||||
|
|
||||||
|
# create the mappings in elasticsearch
|
||||||
|
#Article.init()
|
||||||
|
|
||||||
|
# create and save and article
|
||||||
|
#article = Article(meta={'id': 42}, title='Hello world!', tags=['test'])
|
||||||
|
#article.body = ''' looong text '''
|
||||||
|
##article.published_from = datetime.now()
|
||||||
|
#article.save()
|
||||||
|
|
||||||
|
#article = Article.get(id=42)
|
||||||
|
#print(article.is_published())
|
||||||
|
|
||||||
|
# Display cluster health
|
||||||
|
#print(connections.get_connection().cluster.health())
|
1322
backend/old_app.py
Normal file
1322
backend/old_app.py
Normal file
File diff suppressed because it is too large
Load Diff
14
backend/requirements.txt
Normal file
14
backend/requirements.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
elasticsearch
|
||||||
|
elasticsearch-dsl
|
||||||
|
langchain
|
||||||
|
tiktoken
|
||||||
|
|
||||||
|
pydantic
|
||||||
|
Werkzeug
|
||||||
|
flask
|
||||||
|
Flask-Cors
|
||||||
|
Flask-SocketIO
|
||||||
|
flask-openapi3
|
||||||
|
|
||||||
|
minio
|
361
backend/w3.css
Executable file
361
backend/w3.css
Executable file
@ -0,0 +1,361 @@
|
|||||||
|
/* W3.CSS 2.99 Mar 2017 by Jan Egil and Borge Refsnes */
|
||||||
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
|
article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}
|
||||||
|
audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
|
||||||
|
audio:not([controls]){display:none;height:0}[hidden],template{display:none}
|
||||||
|
a{background-color:transparent;-webkit-text-decoration-skip:objects}
|
||||||
|
a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
|
||||||
|
dfn{font-style:italic}mark{background:#ff0;color:#000}
|
||||||
|
small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||||||
|
sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}
|
||||||
|
img{border-style:none}svg:not(:root){overflow:hidden}
|
||||||
|
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}
|
||||||
|
hr{box-sizing:content-box;height:0;overflow:visible}
|
||||||
|
button,input,select,textarea{font:inherit;margin:0}optgroup{font-weight:bold}
|
||||||
|
button,input{overflow:visible}button,select{text-transform:none}
|
||||||
|
button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}
|
||||||
|
button::-moz-focus-inner, [type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner{border-style:none;padding:0}
|
||||||
|
button:-moz-focusring, [type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring{outline:1px dotted ButtonText}
|
||||||
|
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
|
||||||
|
legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
|
||||||
|
[type=checkbox],[type=radio]{padding:0}
|
||||||
|
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
|
||||||
|
[type=search]{-webkit-appearance:textfield;outline-offset:-2px}
|
||||||
|
[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}
|
||||||
|
::-webkit-input-placeholder{color:inherit;opacity:0.54}
|
||||||
|
::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
|
||||||
|
/* End extract */
|
||||||
|
html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden}
|
||||||
|
h1,h2,h3,h4,h5,h6,.w3-slim,.w3-wide{font-family:"Segoe UI",Arial,sans-serif}
|
||||||
|
h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}
|
||||||
|
.w3-serif{font-family:"Times New Roman",Times,serif}
|
||||||
|
h1,h2,h3,h4,h5,h6{font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
|
||||||
|
h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{font-weight:inherit}
|
||||||
|
hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
||||||
|
img{margin-bottom:-5px}a{color:inherit}
|
||||||
|
.w3-image{max-width:100%;height:auto}
|
||||||
|
.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}
|
||||||
|
.w3-table-all{border:1px solid #ccc}
|
||||||
|
.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}
|
||||||
|
.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
|
||||||
|
.w3-table-all tr:nth-child(odd){background-color:#fff}
|
||||||
|
.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
|
||||||
|
.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}
|
||||||
|
.w3-centered tr th,.w3-centered tr td{text-align:center}
|
||||||
|
.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
|
||||||
|
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
||||||
|
.w3-btn,.w3-btn-block,.w3-button{border:none;display:inline-block;outline:0;padding:6px 16px;vertical-align:middle;overflow:hidden;text-decoration:none!important;color:#fff;background-color:#000;text-align:center;cursor:pointer;white-space:nowrap}
|
||||||
|
.w3-btn:hover,.w3-btn-block:hover,.w3-btn-floating:hover,.w3-btn-floating-large:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
||||||
|
.w3-button{color:#000;background-color:#f1f1f1;padding:8px 16px}.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||||
|
.w3-btn,.w3-btn-floating,.w3-btn-floating-large,.w3-closenav,.w3-opennav,.w3-btn-block,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||||
|
.w3-btn-floating,.w3-btn-floating-large{display:inline-block;text-align:center;color:#fff;background-color:#000;position:relative;overflow:hidden;z-index:1;padding:0;border-radius:50%;cursor:pointer;font-size:24px}
|
||||||
|
.w3-btn-floating{width:40px;height:40px;line-height:40px}.w3-btn-floating-large{width:56px;height:56px;line-height:56px}
|
||||||
|
.w3-disabled,.w3-btn:disabled,.w3-button:disabled,.w3-btn-floating:disabled,.w3-btn-floating-large:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
||||||
|
.w3-btn.w3-disabled:hover,.w3-btn-block.w3-disabled:hover,.w3-btn:disabled:hover,.w3-btn-floating.w3-disabled:hover,.w3-btn-floating:disabled:hover,
|
||||||
|
.w3-btn-floating-large.w3-disabled:hover,.w3-btn-floating-large:disabled:hover{box-shadow:none}
|
||||||
|
.w3-btn-group .w3-btn{float:left}.w3-btn-block{width:100%}
|
||||||
|
.w3-btn-bar .w3-btn{box-shadow:none;background-color:inherit;color:inherit;float:left}.w3-btn-bar .w3-btn:hover{background-color:#ccc}
|
||||||
|
.w3-badge,.w3-tag,.w3-sign{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}
|
||||||
|
.w3-badge{border-radius:50%}
|
||||||
|
ul.w3-ul{list-style-type:none;padding:0;margin:0}ul.w3-ul li{padding:6px 2px 6px 16px;border-bottom:1px solid #ddd}ul.w3-ul li:last-child{border-bottom:none}
|
||||||
|
.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
|
||||||
|
.w3-navbar{list-style-type:none;margin:0;padding:0;overflow:hidden}
|
||||||
|
.w3-navbar li{float:left}.w3-navbar li a,.w3-navitem,.w3-navbar li .w3-btn,.w3-navbar li .w3-input{display:block;padding:8px 16px}.w3-navbar li .w3-btn,.w3-navbar li .w3-input{border:none;outline:none;width:100%}
|
||||||
|
.w3-navbar li a:hover{color:#000;background-color:#ccc}
|
||||||
|
.w3-navbar .w3-dropdown-hover,.w3-navbar .w3-dropdown-click{position:static}
|
||||||
|
.w3-navbar .w3-dropdown-hover:hover,.w3-navbar .w3-dropdown-hover:first-child,.w3-navbar .w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
||||||
|
.w3-navbar a,.w3-topnav a,.w3-sidenav a,.w3-dropdown-content a,.w3-accordion-content a,.w3-dropnav a,.w3-navblock a{text-decoration:none!important}
|
||||||
|
.w3-navbar .w3-opennav.w3-right{float:right!important}.w3-topnav{padding:8px 8px}
|
||||||
|
.w3-navblock .w3-dropdown-hover:hover,.w3-navblock .w3-dropdown-hover:first-child,.w3-navblock .w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
||||||
|
.w3-navblock .w3-dropdown-hover,.w3-navblock .w3-dropdown-click{width:100%}.w3-navblock .w3-dropdown-hover .w3-dropdown-content,.w3-navblock .w3-dropdown-click .w3-dropdown-content{min-width:100%}
|
||||||
|
.w3-topnav a{padding:0 8px;border-bottom:3px solid transparent;-webkit-transition:border-bottom .25s;transition:border-bottom .25s}
|
||||||
|
.w3-topnav a:hover{border-bottom:3px solid #fff}.w3-topnav .w3-dropdown-hover a{border-bottom:0}
|
||||||
|
.w3-opennav,.w3-closenav{color:inherit}.w3-opennav:hover,.w3-closenav:hover{cursor:pointer;opacity:0.8}
|
||||||
|
.w3-btn,.w3-btn-floating,.w3-dropnav a,.w3-btn-floating-large,.w3-btn-block, .w3-navbar a,.w3-navblock a,.w3-sidenav a,.w3-pagination li a,.w3-hoverable tbody tr,.w3-hoverable li,
|
||||||
|
.w3-accordion-content a,.w3-dropdown-content a,.w3-dropdown-click:hover,.w3-dropdown-hover:hover,.w3-opennav,.w3-closenav,.w3-closebtn,*[class*="w3-hover-"]
|
||||||
|
{-webkit-transition:background-color .25s,color .15s,box-shadow .25s,opacity 0.25s,filter 0.25s,border 0.15s;transition:background-color .25s,color .15s,box-shadow .15s,opacity .25s,filter .25s,border .15s}
|
||||||
|
.w3-ripple:active{opacity:0.5}.w3-ripple{-webkit-transition:opacity 0s;transition:opacity 0s}
|
||||||
|
.w3-sidenav,.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
|
||||||
|
.w3-sidenav a,.w3-navblock a{padding:4px 2px 4px 16px}.w3-sidenav a:hover,.w3-navblock a:hover{background-color:#ccc;color:#000}.w3-sidenav a,.w3-dropnav a,.w3-navblock a{display:block}
|
||||||
|
.w3-sidenav .w3-dropdown-hover:hover,.w3-sidenav .w3-dropdown-hover:first-child,.w3-sidenav .w3-dropdown-click:hover,.w3-dropnav a:hover{background-color:#ccc;color:#000}
|
||||||
|
.w3-sidenav .w3-dropdown-hover,.w3-sidenav .w3-dropdown-click,.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
|
||||||
|
.w3-sidenav .w3-dropdown-hover .w3-dropdown-content,.w3-sidenav .w3-dropdown-click .w3-dropdown-content,.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
|
||||||
|
.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;background-color:inherit;color:inherit;padding:6px 2px 6px 16px}
|
||||||
|
.w3-main,#main{transition:margin-left .4s}
|
||||||
|
.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
|
||||||
|
.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}.w3-closebtn{text-decoration:none;float:right;font-size:24px;font-weight:bold;color:inherit}
|
||||||
|
.w3-closebtn:hover,.w3-closebtn:focus{color:#000;text-decoration:none;cursor:pointer}
|
||||||
|
.w3-pagination{display:inline-block;padding:0;margin:0}.w3-pagination li{display:inline}
|
||||||
|
.w3-pagination li a{text-decoration:none;color:#000;float:left;padding:8px 16px}
|
||||||
|
.w3-pagination li a:hover{background-color:#ccc}
|
||||||
|
.w3-input-group,.w3-group{margin-top:24px;margin-bottom:24px}
|
||||||
|
.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #808080;width:100%}
|
||||||
|
.w3-label{color:#009688}.w3-input:not(:valid)~.w3-validate{color:#f44336}
|
||||||
|
.w3-select{padding:9px 0;width:100%;color:#000;border:1px solid transparent;border-bottom:1px solid #009688}
|
||||||
|
.w3-select select:focus{color:#000;border:1px solid #009688}.w3-select option[disabled]{color:#009688}
|
||||||
|
.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
|
||||||
|
.w3-dropdown-hover:hover .w3-dropdown-content{display:block;z-index:1}
|
||||||
|
.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
||||||
|
.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
|
||||||
|
.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0}
|
||||||
|
.w3-dropdown-content a{padding:6px 16px;display:block}
|
||||||
|
.w3-dropdown-content a:hover{background-color:#ccc}
|
||||||
|
.w3-accordion{width:100%;cursor:pointer}
|
||||||
|
.w3-accordion-content{cursor:auto;display:none;position:relative;width:100%;margin:0;padding:0}
|
||||||
|
.w3-accordion-content a{padding:6px 16px;display:block}.w3-accordion-content a:hover{background-color:#ccc}
|
||||||
|
.w3-progress-container{width:100%;height:1.5em;position:relative;background-color:#f1f1f1}
|
||||||
|
.w3-progressbar{background-color:#757575;height:100%;position:absolute;line-height:inherit}
|
||||||
|
input[type=checkbox].w3-check,input[type=radio].w3-radio{width:24px;height:24px;position:relative;top:6px}
|
||||||
|
input[type=checkbox].w3-check:checked+.w3-validate,input[type=radio].w3-radio:checked+.w3-validate{color:#009688}
|
||||||
|
input[type=checkbox].w3-check:disabled+.w3-validate,input[type=radio].w3-radio:disabled+.w3-validate{color:#aaa}
|
||||||
|
.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
|
||||||
|
.w3-bar .w3-bar-item{padding:8px 16px;float:left;background-color:inherit;color:inherit;width:auto;border:none;outline:none;display:block}
|
||||||
|
.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
|
||||||
|
.w3-bar .w3-button{background-color:inherit;color:inherit;white-space:normal}
|
||||||
|
.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;background-color:inherit;color:inherit;border:none;outline:none;white-space:normal}
|
||||||
|
.w3-bar-block.w3-center .w3-bar-item{text-align:center}
|
||||||
|
.w3-block{display:block;width:100%}
|
||||||
|
.w3-responsive{overflow-x:auto}
|
||||||
|
.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,.w3-cell-row:before,.w3-cell-row:after,
|
||||||
|
.w3-topnav:after,.w3-topnav:before,.w3-clear:after,.w3-clear:before,.w3-btn-group:before,.w3-btn-group:after,.w3-btn-bar:before,.w3-btn-bar:after,.w3-bar:before,.w3-bar:after
|
||||||
|
{content:"";display:table;clear:both}
|
||||||
|
.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
|
||||||
|
.w3-col.s1{width:8.33333%}
|
||||||
|
.w3-col.s2{width:16.66666%}
|
||||||
|
.w3-col.s3{width:24.99999%}
|
||||||
|
.w3-col.s4{width:33.33333%}
|
||||||
|
.w3-col.s5{width:41.66666%}
|
||||||
|
.w3-col.s6{width:49.99999%}
|
||||||
|
.w3-col.s7{width:58.33333%}
|
||||||
|
.w3-col.s8{width:66.66666%}
|
||||||
|
.w3-col.s9{width:74.99999%}
|
||||||
|
.w3-col.s10{width:83.33333%}
|
||||||
|
.w3-col.s11{width:91.66666%}
|
||||||
|
.w3-col.s12,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{width:99.99999%}
|
||||||
|
@media (min-width:601px){
|
||||||
|
.w3-col.m1{width:8.33333%}
|
||||||
|
.w3-col.m2{width:16.66666%}
|
||||||
|
.w3-col.m3,.w3-quarter{width:24.99999%}
|
||||||
|
.w3-col.m4,.w3-third{width:33.33333%}
|
||||||
|
.w3-col.m5{width:41.66666%}
|
||||||
|
.w3-col.m6,.w3-half{width:49.99999%}
|
||||||
|
.w3-col.m7{width:58.33333%}
|
||||||
|
.w3-col.m8,.w3-twothird{width:66.66666%}
|
||||||
|
.w3-col.m9,.w3-threequarter{width:74.99999%}
|
||||||
|
.w3-col.m10{width:83.33333%}
|
||||||
|
.w3-col.m11{width:91.66666%}
|
||||||
|
.w3-col.m12{width:99.99999%}}
|
||||||
|
@media (min-width:993px){
|
||||||
|
.w3-col.l1{width:8.33333%}
|
||||||
|
.w3-col.l2{width:16.66666%}
|
||||||
|
.w3-col.l3,.w3-quarter{width:24.99999%}
|
||||||
|
.w3-col.l4,.w3-third{width:33.33333%}
|
||||||
|
.w3-col.l5{width:41.66666%}
|
||||||
|
.w3-col.l6,.w3-half{width:49.99999%}
|
||||||
|
.w3-col.l7{width:58.33333%}
|
||||||
|
.w3-col.l8,.w3-twothird{width:66.66666%}
|
||||||
|
.w3-col.l9,.w3-threequarter{width:74.99999%}
|
||||||
|
.w3-col.l10{width:83.33333%}
|
||||||
|
.w3-col.l11{width:91.66666%}
|
||||||
|
.w3-col.l12{width:99.99999%}}
|
||||||
|
.w3-content{max-width:980px;margin:auto}
|
||||||
|
.w3-rest{overflow:hidden}
|
||||||
|
.w3-layout-container,.w3-cell-row{display:table;width:100%}.w3-layout-row{display:table-row}.w3-layout-cell,.w3-layout-col,.w3-cell{display:table-cell}
|
||||||
|
.w3-layout-top,.w3-cell-top{vertical-align:top}.w3-layout-middle,.w3-cell-middle{vertical-align:middle}.w3-layout-bottom,.w3-cell-bottom{vertical-align:bottom}
|
||||||
|
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
||||||
|
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
||||||
|
.w3-topnav a{display:block}.w3-navbar li:not(.w3-opennav){float:none;width:100%!important}.w3-navbar li.w3-right{float:none!important}
|
||||||
|
.w3-topnav .w3-dropdown-hover .w3-dropdown-content,.w3-navbar .w3-dropdown-click .w3-dropdown-content,.w3-navbar .w3-dropdown-hover .w3-dropdown-content,.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
||||||
|
.w3-topnav,.w3-navbar{text-align:center}.w3-hide-small{display:none!important}.w3-layout-col,.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
||||||
|
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
||||||
|
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
||||||
|
@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidenav.w3-collapse,.w3-sidebar.w3-collapse{display:block!important}}
|
||||||
|
@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
|
||||||
|
@media (max-width:992px){.w3-sidenav.w3-collapse,.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}}
|
||||||
|
.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
|
||||||
|
.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
|
||||||
|
.w3-left{float:left!important}.w3-right{float:right!important}
|
||||||
|
.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}
|
||||||
|
.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
|
||||||
|
.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}
|
||||||
|
.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
|
||||||
|
.w3-vertical{word-break:break-all;line-height:1;text-align:center;width:0.6em}
|
||||||
|
.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}
|
||||||
|
.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
|
||||||
|
.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
|
||||||
|
.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
|
||||||
|
.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
|
||||||
|
.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
|
||||||
|
.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
|
||||||
|
.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||||
|
.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||||
|
.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
|
||||||
|
.w3-display-position{position:absolute}
|
||||||
|
.w3-circle{border-radius:50%!important}
|
||||||
|
.w3-round-small{border-radius:2px!important}.w3-round,.w3-round-medium{border-radius:4px!important}
|
||||||
|
.w3-round-large{border-radius:8px!important}.w3-round-xlarge{border-radius:16px!important}
|
||||||
|
.w3-round-xxlarge{border-radius:32px!important}.w3-round-jumbo{border-radius:64px!important}
|
||||||
|
.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
|
||||||
|
.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
|
||||||
|
.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
|
||||||
|
.w3-margin{margin:16px!important}.w3-margin-0{margin:0!important}
|
||||||
|
.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
|
||||||
|
.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
|
||||||
|
.w3-section{margin-top:16px!important;margin-bottom:16px!important}
|
||||||
|
.w3-padding-tiny{padding:2px 4px!important}.w3-padding-small{padding:4px 8px!important}
|
||||||
|
.w3-padding-medium,.w3-padding,.w3-form{padding:8px 16px!important}
|
||||||
|
.w3-padding-large{padding:12px 24px!important}.w3-padding-xlarge{padding:16px 32px!important}
|
||||||
|
.w3-padding-xxlarge{padding:24px 48px!important}.w3-padding-jumbo{padding:32px 64px!important}
|
||||||
|
.w3-padding-4{padding-top:4px!important;padding-bottom:4px!important}
|
||||||
|
.w3-padding-8{padding-top:8px!important;padding-bottom:8px!important}
|
||||||
|
.w3-padding-12{padding-top:12px!important;padding-bottom:12px!important}
|
||||||
|
.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}
|
||||||
|
.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
|
||||||
|
.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}
|
||||||
|
.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
|
||||||
|
.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
|
||||||
|
.w3-padding-128{padding-top:128px!important;padding-bottom:128px!important}
|
||||||
|
.w3-padding-0{padding:0!important}
|
||||||
|
.w3-padding-top{padding-top:8px!important}.w3-padding-bottom{padding-bottom:8px!important}
|
||||||
|
.w3-padding-left{padding-left:16px!important}.w3-padding-right{padding-right:16px!important}
|
||||||
|
.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
|
||||||
|
.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
|
||||||
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
|
.w3-spin{animation:w3-spin 2s infinite linear;-webkit-animation:w3-spin 2s infinite linear}
|
||||||
|
@-webkit-keyframes w3-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
|
||||||
|
@keyframes w3-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
|
||||||
|
.w3-container{padding:0.01em 16px}
|
||||||
|
.w3-panel{padding:0.01em 16px;margin-top:16px!important;margin-bottom:16px!important}
|
||||||
|
.w3-example{background-color:#f1f1f1;padding:0.01em 16px}
|
||||||
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
|
.w3-code{line-height:1.4;width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
|
.w3-example,.w3-code{margin:20px 0}.w3-card{border:1px solid #ccc}
|
||||||
|
.w3-card-2,.w3-example{box-shadow:0 2px 4px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)!important}
|
||||||
|
.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)!important}
|
||||||
|
.w3-card-8{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)!important}
|
||||||
|
.w3-card-12{box-shadow:0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19)!important}
|
||||||
|
.w3-card-16{box-shadow:0 16px 24px 0 rgba(0,0,0,0.22),0 25px 55px 0 rgba(0,0,0,0.21)!important}
|
||||||
|
.w3-card-24{box-shadow:0 24px 24px 0 rgba(0,0,0,0.2),0 40px 77px 0 rgba(0,0,0,0.22)!important}
|
||||||
|
.w3-animate-fading{-webkit-animation:fading 10s infinite;animation:fading 10s infinite}
|
||||||
|
@-webkit-keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
|
||||||
|
@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
|
||||||
|
.w3-animate-opacity{-webkit-animation:opac 0.8s;animation:opac 0.8s}
|
||||||
|
@-webkit-keyframes opac{from{opacity:0} to{opacity:1}}
|
||||||
|
@keyframes opac{from{opacity:0} to{opacity:1}}
|
||||||
|
.w3-animate-top{position:relative;-webkit-animation:animatetop 0.4s;animation:animatetop 0.4s}
|
||||||
|
@-webkit-keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
|
||||||
|
@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
|
||||||
|
.w3-animate-left{position:relative;-webkit-animation:animateleft 0.4s;animation:animateleft 0.4s}
|
||||||
|
@-webkit-keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
|
||||||
|
@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
|
||||||
|
.w3-animate-right{position:relative;-webkit-animation:animateright 0.4s;animation:animateright 0.4s}
|
||||||
|
@-webkit-keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
|
||||||
|
@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
|
||||||
|
.w3-animate-bottom{position:relative;-webkit-animation:animatebottom 0.4s;animation:animatebottom 0.4s}
|
||||||
|
@-webkit-keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0px;opacity:1}}
|
||||||
|
@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
|
||||||
|
.w3-animate-zoom {-webkit-animation:animatezoom 0.6s;animation:animatezoom 0.6s}
|
||||||
|
@-webkit-keyframes animatezoom{from{-webkit-transform:scale(0)} to{-webkit-transform:scale(1)}}
|
||||||
|
@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
|
||||||
|
.w3-animate-input{-webkit-transition:width 0.4s ease-in-out;transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
|
||||||
|
.w3-opacity,.w3-hover-opacity:hover{opacity:0.60;-webkit-backface-visibility:hidden}
|
||||||
|
.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1;-webkit-backface-visibility:hidden}
|
||||||
|
.w3-opacity-max{opacity:0.25;-webkit-backface-visibility:hidden}
|
||||||
|
.w3-opacity-min{opacity:0.75;-webkit-backface-visibility:hidden}
|
||||||
|
.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{-webkit-filter:grayscale(100%);filter:grayscale(100%)}
|
||||||
|
.w3-greyscale,.w3-grayscale{-webkit-filter:grayscale(75%);filter:grayscale(75%)}
|
||||||
|
.w3-greyscale-min,.w3-grayscale-min{-webkit-filter:grayscale(50%);filter:grayscale(50%)}
|
||||||
|
.w3-sepia{-webkit-filter:sepia(75%);filter:sepia(75%)}
|
||||||
|
.w3-sepia-max,.w3-hover-sepia:hover{-webkit-filter:sepia(100%);filter:sepia(100%)}
|
||||||
|
.w3-sepia-min{-webkit-filter:sepia(50%);filter:sepia(50%)}
|
||||||
|
.w3-text-shadow{text-shadow:1px 1px 0 #444}.w3-text-shadow-white{text-shadow:1px 1px 0 #ddd}
|
||||||
|
.w3-transparent{background-color:transparent!important}
|
||||||
|
.w3-hover-none:hover{box-shadow:none!important;background-color:transparent!important}
|
||||||
|
/* Colors */
|
||||||
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
|
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
||||||
|
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
||||||
|
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
||||||
|
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
||||||
|
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
|
||||||
|
.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
|
||||||
|
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
|
||||||
|
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
|
||||||
|
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
|
||||||
|
.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
|
||||||
|
.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
|
||||||
|
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
|
||||||
|
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
||||||
|
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
||||||
|
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
||||||
|
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
||||||
|
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
||||||
|
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
||||||
|
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
||||||
|
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
||||||
|
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
||||||
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
|
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
|
||||||
|
.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
|
||||||
|
.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
|
||||||
|
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
|
||||||
|
.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
|
||||||
|
.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
|
||||||
|
.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
|
||||||
|
.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,.w3-hover-text-blue-gray:hover{color:#607d8b!important}
|
||||||
|
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
|
||||||
|
.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
|
||||||
|
.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
|
||||||
|
.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
|
||||||
|
.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
|
||||||
|
.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
|
||||||
|
.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
|
||||||
|
.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
|
||||||
|
.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
|
||||||
|
.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
|
||||||
|
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
|
||||||
|
.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
|
||||||
|
.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
|
||||||
|
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
|
||||||
|
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
|
||||||
|
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
|
||||||
|
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
|
||||||
|
.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
|
||||||
|
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
|
||||||
|
.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important}
|
||||||
|
.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important}
|
||||||
|
.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
|
||||||
|
.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important}
|
||||||
|
.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important}
|
||||||
|
.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important}
|
||||||
|
.w3-border-blue-grey,.w3-hover-border-blue-grey:hover,.w3-border-blue-gray,.w3-hover-border-blue-gray:hover{border-color:#607d8b!important}
|
||||||
|
.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
|
||||||
|
.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important}
|
||||||
|
.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important}
|
||||||
|
.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important}
|
||||||
|
.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important}
|
||||||
|
.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important}
|
||||||
|
.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important}
|
||||||
|
.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important}
|
||||||
|
.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important}
|
||||||
|
.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important}
|
||||||
|
.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
|
||||||
|
.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important}
|
||||||
|
.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important}
|
||||||
|
.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
|
||||||
|
.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
|
||||||
|
.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
|
||||||
|
.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#9e9e9e!important}
|
||||||
|
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||||
|
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||||
|
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||||
|
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
116
docker-compose.yml
Normal file
116
docker-compose.yml
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
version: "3.9"
|
||||||
|
networks:
|
||||||
|
llm_network:
|
||||||
|
driver: bridge
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
container_name: ${APP_PREFIX}_reverseproxy
|
||||||
|
image: nginxinc/nginx-unprivileged #:1.25-alpine
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "81:8080"
|
||||||
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: ./nginx.conf
|
||||||
|
target: /etc/nginx/nginx.conf
|
||||||
|
networks:
|
||||||
|
- llm_network
|
||||||
|
#minio:
|
||||||
|
# container_name: ${APP_PREFIX}_minio
|
||||||
|
# #image: docker.io/bitnami/minio #:2022
|
||||||
|
# image: minio/minio
|
||||||
|
# ports:
|
||||||
|
# - '9000:9000'
|
||||||
|
# - '9001:9001'
|
||||||
|
# networks:
|
||||||
|
# - llm_network
|
||||||
|
# volumes:
|
||||||
|
# - 'minio_data:/data'
|
||||||
|
# environment:
|
||||||
|
# - MINIO_ROOT_USER=root
|
||||||
|
# - MINIO_ROOT_PASSWORD=rootrootroot
|
||||||
|
# - MINIO_DEFAULT_BUCKETS=defaultbucket
|
||||||
|
# command: server --console-address ":9001" /data
|
||||||
|
|
||||||
|
elasticsearch:
|
||||||
|
container_name: ${APP_PREFIX}_elasticsearch
|
||||||
|
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "9200:9200"
|
||||||
|
environment:
|
||||||
|
- discovery.type=single-node
|
||||||
|
- xpack.security.enabled=false
|
||||||
|
- logger.level=ERROR
|
||||||
|
volumes:
|
||||||
|
- esdata:/usr/share/elasticsearch/data
|
||||||
|
ulimits:
|
||||||
|
memlock:
|
||||||
|
soft: -1
|
||||||
|
hard: -1
|
||||||
|
networks:
|
||||||
|
- llm_network
|
||||||
|
|
||||||
|
|
||||||
|
ollama:
|
||||||
|
container_name: ${APP_PREFIX}_ollama
|
||||||
|
image: ollama/ollama:latest
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "11434:11434"
|
||||||
|
volumes:
|
||||||
|
- .:/code
|
||||||
|
- ./ollama/ollama:/root/.ollama
|
||||||
|
networks:
|
||||||
|
- llm_network
|
||||||
|
#command: "ollama pull llama2"
|
||||||
|
|
||||||
|
|
||||||
|
ollama-webui:
|
||||||
|
image: ghcr.io/ollama-webui/ollama-webui:main
|
||||||
|
container_name: ollama-webui
|
||||||
|
volumes:
|
||||||
|
- ./ollama/ollama-webui:/app/backend/data
|
||||||
|
depends_on:
|
||||||
|
- ollama
|
||||||
|
ports:
|
||||||
|
- 8888:8080
|
||||||
|
environment:
|
||||||
|
- '/ollama/api=http://ollama:11434/api'
|
||||||
|
extra_hosts:
|
||||||
|
- host.docker.internal:host-gateway
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- llm_network
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#frontend:
|
||||||
|
# container_name: ${APP_PREFIX}_frontend
|
||||||
|
# image: ${APP_PREFIX}-vue-frontend
|
||||||
|
# restart: always
|
||||||
|
# ports:
|
||||||
|
# - "3000:3000"
|
||||||
|
# build: ./frontend
|
||||||
|
backend:
|
||||||
|
container_name: ${APP_PREFIX}_backend
|
||||||
|
image: ${APP_PREFIX}-python-backend
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "5000:5000"
|
||||||
|
env_file:
|
||||||
|
- backend/backend.env
|
||||||
|
build: ./backend
|
||||||
|
networks:
|
||||||
|
- llm_network
|
||||||
|
depends_on:
|
||||||
|
- elasticsearch
|
||||||
|
- ollama
|
||||||
|
#- minio
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
esdata:
|
||||||
|
driver: local
|
||||||
|
filedata:
|
||||||
|
minio_data:
|
||||||
|
driver: local
|
59
nginx.conf
Normal file
59
nginx.conf
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
worker_processes 1;
|
||||||
|
pid /tmp/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
log_format main '$time_iso8601 :: $status :: $request';
|
||||||
|
access_log /dev/stdout main;
|
||||||
|
error_log /dev/stderr error;
|
||||||
|
|
||||||
|
client_body_temp_path /tmp/client_temp;
|
||||||
|
proxy_temp_path /tmp/proxy_temp_path;
|
||||||
|
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||||
|
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||||
|
scgi_temp_path /tmp/scgi_temp;
|
||||||
|
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
send_timeout 600;
|
||||||
|
tcp_nopush on;
|
||||||
|
proxy_read_timeout 300;
|
||||||
|
client_max_body_size 100m;
|
||||||
|
|
||||||
|
server {
|
||||||
|
server_name localhost;
|
||||||
|
listen 8080;
|
||||||
|
resolver 127.0.0.11;
|
||||||
|
|
||||||
|
# Frontend
|
||||||
|
# location / {
|
||||||
|
# proxy_pass http://frontend:3000;
|
||||||
|
# }
|
||||||
|
|
||||||
|
#location /epdm/chat/frontend {
|
||||||
|
# rewrite ^/epdm/chat/frontend/assets/(.*) $1 break;
|
||||||
|
# proxy_pass http://frontend:3000;
|
||||||
|
#}
|
||||||
|
|
||||||
|
#location /epdm/chat/frontend/assets {
|
||||||
|
# rewrite ^/epdm/chat/frontend/assets/(.*) $1 break;
|
||||||
|
# proxy_pass http://frontend:3000/assets/$uri$is_args$args;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Node Backend API Server
|
||||||
|
#location /epdm/chat/backend {
|
||||||
|
# rewrite ^/epdm/chat/backend(.*) $1 break;
|
||||||
|
# proxy_pass http://backend:8000$uri$is_args$args;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Python Backend
|
||||||
|
location /backend {
|
||||||
|
rewrite ^/backend(.*) $1 break;
|
||||||
|
proxy_pass http://backend:5000$uri$is_args$args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user