using System.Text.Json;
namespace EARSystem.Core;
public enum PlaceCategory { Dining, Cafe, Park, Bookstore, Gallery, Entertainment }
public enum RecommendationGoal { Relax, Explore, Social, Focus }
public enum DataMode { Demo, Online }
public enum PlaceSource { Demo, Collected }
public static class Labels
{
public static readonly string[] EmotionTags = ["开心", "平静", "焦虑", "烦躁", "低落", "疲惫"];
public static readonly string[] SceneTags = ["学习", "工作", "独处", "聚会", "准备学习", "准备工作"];
public static string Category(PlaceCategory c) => c switch {
PlaceCategory.Dining => "餐饮", PlaceCategory.Cafe => "咖啡馆", PlaceCategory.Park => "公园",
PlaceCategory.Bookstore => "书店", PlaceCategory.Gallery => "展馆", _ => "休闲娱乐" };
public static string Goal(RecommendationGoal g) => g switch {
RecommendationGoal.Relax => "放松恢复", RecommendationGoal.Social => "社交玩乐",
RecommendationGoal.Focus => "专注学习", _ => "轻松探索" };
public static string Json<T>(T value) => JsonSerializer.Serialize(value);
public static T[] Read<T>(string? value) => string.IsNullOrWhiteSpace(value) ? [] : JsonSerializer.Deserialize<T[]>(value) ?? [];
}
public class MoodEntry
{
public Guid Id { get; set; } = Guid.NewGuid();
public string UserId { get; set; } = "";
public int Mood { get; set; }
public int Energy { get; set; }
public int Stress { get; set; }
public string TagsJson { get; set; } = "[]";
public string Thoughts { get; set; } = "";
public DateTimeOffset RecordedAt { get; set; }
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
public Guid Version { get; set; } = Guid.NewGuid();
public Guid? ExperienceId { get; set; }
}
public class UserPreference
{
public string UserId { get; set; } = "";
public string FavoriteCategoriesJson { get; set; } = "[]";
public string BlockedCategoriesJson { get; set; } = "[]";
public string BlockedPlacesJson { get; set; } = "[]";
public decimal? Budget { get; set; }
public int RadiusMeters { get; set; } = 3000;
}
public class Place
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = "";
public string Address { get; set; } = "";
public string Description { get; set; } = "";
public PlaceCategory Category { get; set; }
public PlaceSource Source { get; set; } = PlaceSource.Demo;
public double Longitude { get; set; }
public double Latitude { get; set; }
public decimal? Price { get; set; }
public double? Rating { get; set; }
public int? OpenHour { get; set; }
public int? CloseHour { get; set; }
public string? AuthorizedExternalId { get; set; }
public PlaceAtmosphere? Atmosphere { get; set; }
}
// Baselines are kept separately from user contributions, so editing/deleting a vote is reversible.
public class PlaceAtmosphere
{
public Guid PlaceId { get; set; }
public double Quiet { get; set; } = 3;
public double Comfort { get; set; } = 3;
public double Nature { get; set; } = 3;
public double Liveliness { get; set; } = 3;
public double Social { get; set; } = 3;
public double Focus { get; set; } = 3;
public int BaselineCount { get; set; }
public string Evidence { get; set; } = "";
public double[] Values() => [Quiet, Comfort, Nature, Liveliness, Social, Focus];
}
public class Experience
{
public Guid Id { get; set; } = Guid.NewGuid();
public string UserId { get; set; } = "";
public Guid PlaceId { get; set; }
public Place Place { get; set; } = null!;
public DateTimeOffset VisitedAt { get; set; }
public int VisitDay { get; set; }
public int Satisfaction { get; set; }
public int? MoodBefore { get; set; }
public int? MoodAfter { get; set; }
public int Quiet { get; set; } = 3;
public int Comfort { get; set; } = 3;
public int Nature { get; set; } = 3;
public int Liveliness { get; set; } = 3;
public int Social { get; set; } = 3;
public int Focus { get; set; } = 3;
public string Thoughts { get; set; } = "";
public bool Contribute { get; set; }
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
public Guid Version { get; set; } = Guid.NewGuid();
public double[] Values() => [Quiet, Comfort, Nature, Liveliness, Social, Focus];
}
public class Favorite
{
public string UserId { get; set; } = "";
public Guid PlaceId { get; set; }
public Place Place { get; set; } = null!;
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
}
public class RecommendationRecord
{
public Guid Id { get; set; } = Guid.NewGuid();
public string UserId { get; set; } = "";
public RecommendationGoal Goal { get; set; }
public DataMode Mode { get; set; }
public string AlgorithmVersion { get; set; } = "1";
public string ResultsJson { get; set; } = "[]";
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
public double DurationMs { get; set; }
}
public class RuleConfiguration
{
public int Id { get; set; }
public string Version { get; set; } = "1";
public string WeightsJson { get; set; } = Labels.Json(new AlgorithmWeights());
public Guid ConcurrencyStamp { get; set; } = Guid.NewGuid();
public DateTimeOffset? DemoSeededAt { get; set; }
}
public static class ChinaTime
{
public static DateTimeOffset Local(DateTimeOffset time) => time.ToOffset(TimeSpan.FromHours(8));
public static DateOnly Day(DateTimeOffset time) => DateOnly.FromDateTime(Local(time).DateTime);
public static int DayKey(DateTimeOffset time) => Day(time).DayNumber;
public static DateTimeOffset Start(DateOnly day) => new(day.ToDateTime(TimeOnly.MinValue), TimeSpan.FromHours(8));
public static DateOnly Monday(DateOnly day) => day.AddDays(-(((int)day.DayOfWeek + 6) % 7));
}
using System.Text.Json;
namespace EARSystem.Core;
public enum PlaceCategory { Dining, Cafe, Park, Bookstore, Gallery, Entertainment }
public enum RecommendationGoal { Relax, Explore, Social, Focus }
public enum DataMode { Demo, Online }
public enum PlaceSource { Demo, Collected }
public static class Labels
{
public static readonly string[] EmotionTags = ["开心", "平静", "焦虑", "烦躁", "低落", "疲惫"];
public static readonly string[] SceneTags = ["学习", "工作", "独处", "聚会", "准备学习", "准备工作"];
public static string Category(PlaceCategory c) => c switch {
PlaceCategory.Dining => "餐饮", PlaceCategory.Cafe => "咖啡馆", PlaceCategory.Park => "公园",
PlaceCategory.Bookstore => "书店", PlaceCategory.Gallery => "展馆", _ => "休闲娱乐" };
public static string Goal(RecommendationGoal g) => g switch {
RecommendationGoal.Relax => "放松恢复", RecommendationGoal.Social => "社交玩乐",
RecommendationGoal.Focus => "专注学习", _ => "轻松探索" };
public static string Json<T>(T value) => JsonSerializer.Serialize(value);
public static T[] Read<T>(string? value) => string.IsNullOrWhiteSpace(value) ? [] : JsonSerializer.Deserialize<T[]>(value) ?? [];
}
public class MoodEntry
{
public Guid Id { get; set; } = Guid.NewGuid();
public string UserId { get; set; } = "";
public int Mood { get; set; }
public int Energy { get; set; }
public int Stress { get; set; }
public string TagsJson { get; set; } = "[]";
public string Thoughts { get; set; } = "";
public DateTimeOffset RecordedAt { get; set; }
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
public Guid Version { get; set; } = Guid.NewGuid();
public Guid? ExperienceId { get; set; }
}
public class UserPreference
{
public string UserId { get; set; } = "";
public string FavoriteCategoriesJson { get; set; } = "[]";
public string BlockedCategoriesJson { get; set; } = "[]";
public string BlockedPlacesJson { get; set; } = "[]";
public decimal? Budget { get; set; }
public int RadiusMeters { get; set; } = 3000;
}
public class Place
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = "";
public string Address { get; set; } = "";
public string Description { get; set; } = "";
public PlaceCategory Category { get; set; }
public PlaceSource Source { get; set; } = PlaceSource.Demo;
public double Longitude { get; set; }
public double Latitude { get; set; }
public decimal? Price { get; set; }
public double? Rating { get; set; }
public int? OpenHour { get; set; }
public int? CloseHour { get; set; }
public string? AuthorizedExternalId { get; set; }
public PlaceAtmosphere? Atmosphere { get; set; }
}
// Baselines are kept separately from user contributions, so editing/deleting a vote is reversible.
public class PlaceAtmosphere
{
public Guid PlaceId { get; set; }
public double Quiet { get; set; } = 3;
public double Comfort { get; set; } = 3;
public double Nature { get; set; } = 3;
public double Liveliness { get; set; } = 3;
public double Social { get; set; } = 3;
public double Focus { get; set; } = 3;
public int BaselineCount { get; set; }
public string Evidence { get; set; } = "";
public double[] Values() => [Quiet, Comfort, Nature, Liveliness, Social, Focus];
}
public class Experience
{
public Guid Id { get; set; } = Guid.NewGuid();
public string UserId { get; set; } = "";
public Guid PlaceId { get; set; }
public Place Place { get; set; } = null!;
public DateTimeOffset VisitedAt { get; set; }
public int VisitDay { get; set; }
public int Satisfaction { get; set; }
public int? MoodBefore { get; set; }
public int? MoodAfter { get; set; }
public int Quiet { get; set; } = 3;
public int Comfort { get; set; } = 3;
public int Nature { get; set; } = 3;
public int Liveliness { get; set; } = 3;
public int Social { get; set; } = 3;
public int Focus { get; set; } = 3;
public string Thoughts { get; set; } = "";
public bool Contribute { get; set; }
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
public Guid Version { get; set; } = Guid.NewGuid();
public double[] Values() => [Quiet, Comfort, Nature, Liveliness, Social, Focus];
}
public class Favorite
{
public string UserId { get; set; } = "";
public Guid PlaceId { get; set; }
public Place Place { get; set; } = null!;
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
}
public class RecommendationRecord
{
public Guid Id { get; set; } = Guid.NewGuid();
public string UserId { get; set; } = "";
public RecommendationGoal Goal { get; set; }
public DataMode Mode { get; set; }
public string AlgorithmVersion { get; set; } = "1";
public string ResultsJson { get; set; } = "[]";
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
public double DurationMs { get; set; }
}
public class RuleConfiguration
{
public int Id { get; set; }
public string Version { get; set; } = "1";
public string WeightsJson { get; set; } = Labels.Json(new AlgorithmWeights());
public Guid ConcurrencyStamp { get; set; } = Guid.NewGuid();
public DateTimeOffset? DemoSeededAt { get; set; }
}
public static class ChinaTime
{
public static DateTimeOffset Local(DateTimeOffset time) => time.ToOffset(TimeSpan.FromHours(8));
public static DateOnly Day(DateTimeOffset time) => DateOnly.FromDateTime(Local(time).DateTime);
public static int DayKey(DateTimeOffset time) => Day(time).DayNumber;
public static DateTimeOffset Start(DateOnly day) => new(day.ToDateTime(TimeOnly.MinValue), TimeSpan.FromHours(8));
public static DateOnly Monday(DateOnly day) => day.AddDays(-(((int)day.DayOfWeek + 6) % 7));
}