Skip to content
Snippets Groups Projects
Commit f1d4ca08 authored by Swetha Lakshmana Murthy's avatar Swetha Lakshmana Murthy
Browse files

Added the user ratings node

parent dee1bfb2
No related branches found
No related tags found
No related merge requests found
FROM python:3.8
RUN apt-get update -y
RUN apt-get install -y python3-pip python3-dev
RUN pip3 install --upgrade pip
COPY requirements.txt .
RUN pip3 install -r requirements.txt
ARG TIMEZONE=Europe/Berlin
RUN ln -sf /usr/share/zoneinfo/$TIMEZONE /etc/localtime && \
echo "$TIMEZONE" > /etc/timezone
RUN mkdir /user_ratings
COPY . /user_ratings
WORKDIR /user_ratings
RUN python3 -m grpc_tools.protoc --python_out=. --proto_path=. --grpc_python_out=. user_ratings.proto
ENTRYPOINT python3 -u server.py
import grpc
from flask import Flask, render_template
from flask_bootstrap import Bootstrap
from flask import send_file
import user_ratings_pb2
import user_ratings_pb2_grpc
import matplotlib.pyplot as plt
import plotly.graph_objects as go
app = Flask(__name__)
def get_ratings():
with grpc.insecure_channel('localhost:8061') as channel:
stub = user_ratings_pb2_grpc.RatingsServiceStub(channel)
for rating in stub.GetRatings(user_ratings_pb2.Empty()):
yield rating.stars, rating.filename, rating.time
@app.route('/')
def index():
ratings = list(get_ratings())
plot_url = plot_ratings(ratings)
return render_template('index.html', plot_url="/plot.png")
@app.route('/plot.png')
def plot_image():
return send_file("plot.png", mimetype='image/png')
def plot_ratings(ratings):
stars, filenames, timestamps = zip(*ratings)
stars = list(stars)
filenames = list(filenames)
timestamps = list(timestamps)
ratings_by_timestamp = {}
for timestamp, filename, star in zip(timestamps, filenames, stars):
if timestamp not in ratings_by_timestamp:
ratings_by_timestamp[timestamp] = {}
if filename not in ratings_by_timestamp[timestamp]:
ratings_by_timestamp[timestamp][filename] = []
ratings_by_timestamp[timestamp][filename].append(star)
data = []
for timestamp, ratings_dict in ratings_by_timestamp.items():
x_labels = list(ratings_dict.keys())
y_values = [sum(ratings_dict[filename])/len(ratings_dict[filename]) for filename in x_labels]
data.append(go.Bar(x=x_labels, y=y_values, name=timestamp))
layout = go.Layout(
title='Stars ratings for various Graphene tutorials',
xaxis=dict(title='Graphene Tutorial Name'),
yaxis=dict(title='Stars Rating'),
showlegend=False
)
fig = go.Figure(data=data, layout=layout)
fig.show()
fig.write_image("plot.png") # Save plot as a PNG image
plt.close()
return "plot.png"
def app_run():
app.secret_key = "user_ratings"
bootstrap = Bootstrap(app)
app.run(host="0.0.0.0", port=8062, debug=False)
\ No newline at end of file
grpcio==1.38.0
grpcio-tools==1.38.0
grpc-interceptor
multithreading
protobuf==3.16.0
Flask
Bootstrap-Flask
matplotlib
plotly
kaleido
\ No newline at end of file
import grpc
from concurrent import futures
import threading
import os
import user_ratings_pb2
import user_ratings_pb2_grpc
from app import app_run
local_directory = os.getenv("SHARED_FOLDER_PATH")
print('The SHARED_FOLDER_PATH is {}'.format(local_directory))
class RatingsServicer(user_ratings_pb2_grpc.RatingsServiceServicer):
def __init__(self, ratings_file_path):
self.ratings_file_path = os.path.join(ratings_file_path, 'ratings.txt')
def GetRatings(self, request, context):
with open(self.ratings_file_path, 'r') as file:
for line in file:
parts = line.strip().split(', ')
stars = int(parts[1].split(': ')[1])
time_str = parts[2].split(': ')[1]
filename = parts[0].split(': ')[1]
rating = user_ratings_pb2.Rating(stars=stars, time=time_str, filename=filename)
yield rating
def serve(port):
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
user_ratings_pb2_grpc.add_RatingsServiceServicer_to_server(RatingsServicer(local_directory), server)
server.add_insecure_port("[::]:{}".format(port))
print("Starting server. Listening on port : " + str(port))
server.start()
threading.Thread(target=app_run()).start()
server.wait_for_termination()
if __name__ == "__main__":
port = 8061
serve(port)
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User Ratings</title>
</head>
<body>
<h1>User Ratings Over Time</h1>
<img src="{{ plot_url }}" alt="User Ratings Graph">
</body>
</html>
\ No newline at end of file
syntax = "proto3";
message Empty {
// Empty message
}
message Rating {
int32 stars = 1;
string time = 2;
string filename = 3;
}
// Stream is used here to continuously retrieve the sequence of ratings.
service RatingsService {
rpc GetRatings (Empty) returns (stream Rating);
}
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: user_ratings.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12user_ratings.proto\"\x07\n\x05\x45mpty\"7\n\x06Rating\x12\r\n\x05stars\x18\x01 \x01(\x05\x12\x0c\n\x04time\x18\x02 \x01(\t\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t21\n\x0eRatingsService\x12\x1f\n\nGetRatings\x12\x06.Empty\x1a\x07.Rating0\x01\x62\x06proto3')
_EMPTY = DESCRIPTOR.message_types_by_name['Empty']
_RATING = DESCRIPTOR.message_types_by_name['Rating']
Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), {
'DESCRIPTOR' : _EMPTY,
'__module__' : 'user_ratings_pb2'
# @@protoc_insertion_point(class_scope:Empty)
})
_sym_db.RegisterMessage(Empty)
Rating = _reflection.GeneratedProtocolMessageType('Rating', (_message.Message,), {
'DESCRIPTOR' : _RATING,
'__module__' : 'user_ratings_pb2'
# @@protoc_insertion_point(class_scope:Rating)
})
_sym_db.RegisterMessage(Rating)
_RATINGSSERVICE = DESCRIPTOR.services_by_name['RatingsService']
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_EMPTY._serialized_start=22
_EMPTY._serialized_end=29
_RATING._serialized_start=31
_RATING._serialized_end=86
_RATINGSSERVICE._serialized_start=88
_RATINGSSERVICE._serialized_end=137
# @@protoc_insertion_point(module_scope)
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import user_ratings_pb2 as user__ratings__pb2
class RatingsServiceStub(object):
"""Missing associated documentation comment in .proto file."""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.GetRatings = channel.unary_stream(
'/RatingsService/GetRatings',
request_serializer=user__ratings__pb2.Empty.SerializeToString,
response_deserializer=user__ratings__pb2.Rating.FromString,
)
class RatingsServiceServicer(object):
"""Missing associated documentation comment in .proto file."""
def GetRatings(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_RatingsServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'GetRatings': grpc.unary_stream_rpc_method_handler(
servicer.GetRatings,
request_deserializer=user__ratings__pb2.Empty.FromString,
response_serializer=user__ratings__pb2.Rating.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'RatingsService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
# This class is part of an EXPERIMENTAL API.
class RatingsService(object):
"""Missing associated documentation comment in .proto file."""
@staticmethod
def GetRatings(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_stream(request, target, '/RatingsService/GetRatings',
user__ratings__pb2.Empty.SerializeToString,
user__ratings__pb2.Rating.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment